From fbe873afbb149c2d419a726afd27fa7be91cec58 Mon Sep 17 00:00:00 2001 From: Planet-Lab Support Date: Fri, 21 Jan 2005 03:34:04 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create tag 'before-fedora-2_6_7-1_441-merge'. --- Documentation/COPYING.modules | 708 ++++ Documentation/arm/SA1100/PCMCIA | 374 -- Documentation/arm/Sharp-LH/SDRAM | 51 + Documentation/arm/VFP/release-notes.txt | 55 + Documentation/arm/XScale/ADIFCC/80200EVB | 110 - Documentation/arm/XScale/IOP3XX/IQ80310 | 247 -- Documentation/arm/XScale/IOP3XX/IQ80321 | 215 -- Documentation/arm/XScale/IOP3XX/aau.txt | 178 - Documentation/arm/XScale/IOP3XX/dma.txt | 214 -- Documentation/arm/XScale/IOP3XX/message.txt | 110 - Documentation/arm/XScale/IOP3XX/pmon.txt | 71 - Documentation/arm/XScale/cache-lock.txt | 123 - Documentation/arm/XScale/pmu.txt | 168 - Documentation/arm/XScale/tlb-lock.txt | 64 - Documentation/device-mapper/dm-io.txt | 75 + Documentation/device-mapper/kcopyd.txt | 47 + Documentation/device-mapper/linear.txt | 61 + Documentation/device-mapper/striped.txt | 58 + Documentation/device-mapper/zero.txt | 37 + Documentation/fb/sisfb.txt | 158 + Documentation/filesystems/ntfs.txt | 15 - Documentation/filesystems/proc.txt | 15 +- Documentation/filesystems/relayfs.txt | 812 ++++ Documentation/hpet.txt | 298 ++ MAINTAINERS | 8 +- Makefile | 5 +- arch/alpha/Kconfig | 2 + arch/alpha/kernel/ptrace.c | 2 + arch/alpha/kernel/systbls.S | 10 +- arch/arm/Kconfig | 4 +- arch/arm/boot/compressed/head.S | 14 - arch/arm/kernel/entry-armv.S | 10 +- arch/arm/kernel/ptrace.c | 2 + arch/arm/kernel/signal.c | 14 +- arch/arm/mach-integrator/clock.c | 138 + arch/arm/mach-integrator/clock.h | 25 + arch/arm/mach-omap/board-generic.c | 3 +- arch/arm/mach-omap/board-innovator.c | 15 +- arch/arm/mach-omap/board-osk.c | 1 - arch/arm/mach-omap/board-perseus2.c | 6 +- arch/arm/mach-omap/bus.c | 3 +- arch/arm/mach-omap/dma.c | 230 +- arch/arm/mach-omap/gpio.c | 87 +- arch/arm/mach-omap/innovator1510.c | 99 - arch/arm/mach-omap/innovator1610.c | 91 - arch/arm/mach-omap/irq.c | 22 +- arch/arm/mach-omap/irq.h | 172 - arch/arm/mach-omap/omap-generic.c | 77 - arch/arm/mach-omap/omap-perseus2.c | 116 - arch/arm/mach-pxa/Kconfig | 3 +- arch/arm/mach-pxa/leds-lubbock.c | 1 - arch/arm/mach-pxa/lubbock.c | 1 - arch/arm/mach-pxa/pm.c | 1 - arch/arm/mach-s3c2410/Kconfig | 8 +- arch/arm/mach-sa1100/cpu-sa1100.c | 5 +- arch/arm/mach-sa1100/cpu-sa1110.c | 5 +- arch/arm/mach-versatile/clock.c | 146 + arch/arm/mach-versatile/clock.h | 25 + arch/arm/mm/fault-armv.c | 14 +- arch/arm/vfp/Makefile | 12 + arch/arm/vfp/entry.S | 45 + arch/arm/vfp/vfp.h | 333 ++ arch/arm/vfp/vfpdouble.c | 1186 ++++++ arch/arm/vfp/vfphw.S | 210 ++ arch/arm/vfp/vfpinstr.h | 88 + arch/arm/vfp/vfpmodule.c | 288 ++ arch/arm/vfp/vfpsingle.c | 1224 ++++++ arch/arm26/Kconfig | 2 + arch/arm26/kernel/ptrace.c | 2 + arch/cris/Kconfig | 2 + arch/cris/arch-v10/drivers/ethernet.c | 4 +- arch/cris/kernel/hexify.c | 31 - arch/cris/kernel/ksyms.c | 96 - arch/h8300/Kconfig | 2 + arch/h8300/kernel/ptrace.c | 2 + arch/i386/Kconfig | 64 +- arch/i386/Makefile | 4 +- arch/i386/boot/setup.S | 2 +- arch/i386/boot/video.S | 4 + arch/i386/kernel/Makefile | 8 +- arch/i386/kernel/acpi/boot.c | 2 +- arch/i386/kernel/acpi/sleep.c | 30 +- arch/i386/kernel/acpi/wakeup.S | 15 + arch/i386/kernel/asm-offsets.c | 17 + arch/i386/kernel/cpu/common.c | 9 +- arch/i386/kernel/cpu/cpufreq/elanfreq.c | 3 +- arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 4 +- arch/i386/kernel/cpu/cpufreq/longhaul.c | 124 +- arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 29 +- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 8 +- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 27 +- arch/i386/kernel/cpu/cpufreq/speedstep-ich.c | 70 +- arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 34 +- arch/i386/kernel/cpu/intel.c | 5 +- arch/i386/kernel/cpu/proc.c | 2 +- arch/i386/kernel/doublefault.c | 7 +- arch/i386/kernel/entry.S | 240 +- arch/i386/kernel/entry_trampoline.c | 75 + arch/i386/kernel/head.S | 26 + arch/i386/kernel/i386_ksyms.c | 7 +- arch/i386/kernel/i387.c | 24 +- arch/i386/kernel/init_task.c | 4 +- arch/i386/kernel/irq.c | 31 +- arch/i386/kernel/ldt.c | 132 +- arch/i386/kernel/microcode.c | 2 +- arch/i386/kernel/module.c | 2 +- arch/i386/kernel/mpparse.c | 2 +- arch/i386/kernel/nmi.c | 2 +- arch/i386/kernel/process.c | 360 +- arch/i386/kernel/ptrace.c | 2 + arch/i386/kernel/reboot.c | 11 +- arch/i386/kernel/signal.c | 103 +- arch/i386/kernel/smp.c | 22 +- arch/i386/kernel/sys_i386.c | 16 +- arch/i386/kernel/sysenter.c | 55 +- arch/i386/kernel/timers/timer.c | 2 +- arch/i386/kernel/traps.c | 140 +- arch/i386/kernel/vm86.c | 4 +- arch/i386/kernel/vmlinux.lds.S | 48 +- arch/i386/kernel/vsyscall-sysenter.S | 11 +- arch/i386/kernel/vsyscall.lds | 11 +- arch/i386/lib/bitops.c | 70 + arch/i386/lib/checksum.S | 6 +- arch/i386/lib/getuser.S | 1 + arch/i386/lib/usercopy.c | 64 +- arch/i386/mach-es7000/es7000.c | 279 -- arch/i386/mach-es7000/setup.c | 106 - arch/i386/mach-es7000/topology.c | 64 - arch/i386/math-emu/fpu_system.h | 3 +- arch/i386/mm/fault.c | 42 +- arch/i386/mm/highmem.c | 37 +- arch/i386/mm/hugetlbpage.c | 9 +- arch/i386/mm/init.c | 479 +-- arch/i386/mm/pageattr.c | 27 +- arch/i386/mm/pgtable.c | 100 +- arch/i386/pci/fixup.c | 7 +- arch/i386/power/cpu.c | 2 - arch/ia64/Kconfig | 23 +- arch/ia64/Makefile | 14 +- arch/ia64/ia32/binfmt_elf32.c | 26 +- arch/ia64/kernel/entry.S | 10 +- arch/ia64/kernel/fsys.S | 3 +- arch/ia64/kernel/head.S | 36 - arch/ia64/kernel/ia64_ksyms.c | 6 + arch/ia64/kernel/iosapic.c | 2 +- arch/ia64/kernel/irq.c | 6 +- arch/ia64/kernel/perfmon.c | 5 +- arch/ia64/kernel/perfmon_hpsim.h | 75 - arch/ia64/kernel/ptrace.c | 3 + arch/ia64/kernel/setup.c | 17 +- arch/ia64/kernel/smpboot.c | 3 +- arch/ia64/kernel/time.c | 8 + arch/ia64/mm/fault.c | 8 +- arch/ia64/mm/hugetlbpage.c | 9 +- arch/ia64/mm/init.c | 7 + arch/m68k/Kconfig | 2 + arch/m68k/atari/stram.c | 3 +- arch/m68k/kernel/ptrace.c | 2 + arch/m68knommu/Kconfig | 2 + arch/m68knommu/kernel/ptrace.c | 2 + arch/mips/Kconfig | 2 + arch/mips/kernel/irixelf.c | 3 +- arch/mips/kernel/linux32.c | 2 +- arch/mips/kernel/ptrace.c | 2 + arch/mips/kernel/syscall.c | 20 +- arch/mips/kernel/sysirix.c | 3 +- arch/parisc/Kconfig | 2 + arch/parisc/kernel/ptrace.c | 3 + arch/parisc/kernel/sys_parisc32.c | 1 + arch/ppc/8260_io/uart.c | 4 +- arch/ppc/Kconfig | 13 +- arch/ppc/Makefile | 5 +- arch/ppc/boot/simple/embed_config.c | 86 +- arch/ppc/kernel/cputable.c | 8 - arch/ppc/kernel/head_e500.S | 1329 +++++++ arch/ppc/kernel/misc.S | 2 +- arch/ppc/kernel/ppc_ksyms.c | 9 + arch/ppc/kernel/process.c | 4 +- arch/ppc/kernel/ptrace.c | 2 + arch/ppc/kernel/syscalls.c | 14 +- arch/ppc/mm/cachemap.c | 174 - arch/ppc/mm/fsl_booke_mmu.c | 236 ++ arch/ppc/mm/init.c | 5 + arch/ppc/ocp/Makefile | 6 - arch/ppc/ocp/ocp-driver.c | 195 - arch/ppc/ocp/ocp-probe.c | 113 - arch/ppc/ocp/ocp.c | 109 - arch/ppc/platforms/85xx/Kconfig | 44 + arch/ppc/platforms/85xx/Makefile | 7 + arch/ppc/platforms/85xx/mpc8540.c | 97 + arch/ppc/platforms/85xx/mpc8540_ads.c | 238 ++ arch/ppc/platforms/85xx/mpc8540_ads.h | 30 + arch/ppc/platforms/85xx/mpc85xx_ads_common.c | 237 ++ arch/ppc/platforms/85xx/mpc85xx_ads_common.h | 50 + arch/ppc/syslib/Makefile | 7 +- arch/ppc/syslib/ppc85xx_common.c | 46 + arch/ppc/syslib/ppc85xx_common.h | 29 + arch/ppc/syslib/ppc85xx_setup.c | 341 ++ arch/ppc/syslib/ppc85xx_setup.h | 67 + arch/ppc64/Kconfig | 2 + arch/ppc64/Makefile | 4 +- arch/ppc64/kernel/head.S | 8 +- arch/ppc64/kernel/misc.S | 22 +- arch/ppc64/kernel/ptrace.c | 2 + arch/ppc64/kernel/rtas.c | 2 + arch/ppc64/kernel/smp.c | 25 +- arch/ppc64/kernel/sys_ppc32.c | 12 +- arch/ppc64/kernel/sysfs.c | 3 + arch/ppc64/kernel/traps.c | 16 +- arch/ppc64/kernel/vio.c | 28 +- arch/ppc64/kernel/viopath.c | 10 +- arch/ppc64/mm/hugetlbpage.c | 9 +- arch/s390/Kconfig | 2 + arch/s390/Makefile | 5 + arch/s390/defconfig | 9 +- arch/s390/kernel/compat_exec.c | 11 +- arch/s390/kernel/compat_wrapper.S | 2 - arch/s390/kernel/entry.S | 93 +- arch/s390/kernel/entry64.S | 97 +- arch/s390/kernel/process.c | 13 +- arch/s390/kernel/ptrace.c | 32 +- arch/s390/kernel/sys_s390.c | 46 +- arch/s390/kernel/syscalls.S | 2 +- arch/s390/mm/init.c | 5 + arch/sh/Kconfig | 2 + arch/sh/kernel/ptrace.c | 2 + arch/sh/mm/hugetlbpage.c | 9 +- arch/sparc/Kconfig | 2 + arch/sparc/Makefile | 3 + arch/sparc/kernel/ptrace.c | 4 + arch/sparc/kernel/sys_sparc.c | 6 +- arch/sparc/kernel/systbls.S | 2 +- arch/sparc/kernel/unaligned.c | 8 +- arch/sparc/mm/fault.c | 27 +- arch/sparc64/Kconfig | 2 + arch/sparc64/Makefile | 3 + arch/sparc64/defconfig | 10 +- arch/sparc64/kernel/binfmt_aout32.c | 3 +- arch/sparc64/kernel/irq.c | 4 - arch/sparc64/kernel/ptrace.c | 4 + arch/sparc64/kernel/smp.c | 27 +- arch/sparc64/kernel/sparc64_ksyms.c | 5 - arch/sparc64/kernel/sys32.S | 2 +- arch/sparc64/kernel/sys_sparc.c | 12 +- arch/sparc64/kernel/sys_sparc32.c | 2 +- arch/sparc64/kernel/sys_sunos32.c | 4 +- arch/sparc64/kernel/systbls.S | 4 +- arch/sparc64/kernel/unaligned.c | 4 +- arch/sparc64/lib/Makefile | 3 +- arch/sparc64/lib/debuglocks.c | 31 +- arch/sparc64/mm/hugetlbpage.c | 9 +- arch/sparc64/mm/init.c | 19 +- arch/um/Kconfig | 57 + arch/um/Kconfig_block | 14 + arch/um/Kconfig_net | 70 +- arch/um/Makefile | 110 +- arch/um/Makefile-i386 | 23 +- arch/um/Makefile-skas | 6 +- arch/um/config.release | 1 - arch/um/defconfig | 250 +- arch/um/drivers/Makefile | 17 +- arch/um/drivers/chan_kern.c | 16 +- arch/um/drivers/chan_user.c | 102 +- arch/um/drivers/cow_kern.c | 630 ++++ arch/um/drivers/cow_sys.h | 48 + arch/um/drivers/daemon_user.c | 26 +- arch/um/drivers/fd.c | 3 +- arch/um/drivers/harddog_user.c | 62 +- arch/um/drivers/hostaudio_kern.c | 109 +- arch/um/drivers/hostaudio_user.c | 63 +- arch/um/drivers/line.c | 152 +- arch/um/drivers/mcast_user.c | 16 +- arch/um/drivers/mconsole_kern.c | 140 +- arch/um/drivers/mconsole_user.c | 25 +- arch/um/drivers/mmapper_kern.c | 5 +- arch/um/drivers/net_kern.c | 89 +- arch/um/drivers/net_kern.c.orig | 870 +++++ arch/um/drivers/net_user.c | 46 +- arch/um/drivers/null.c | 1 - arch/um/drivers/port_kern.c | 17 +- arch/um/drivers/port_user.c | 31 +- arch/um/drivers/pty.c | 22 +- arch/um/drivers/slip_user.c | 69 +- arch/um/drivers/slirp_user.c | 15 +- arch/um/drivers/ssl.c | 49 +- arch/um/drivers/stdio_console.c | 54 +- arch/um/drivers/tty.c | 4 +- arch/um/drivers/ubd_kern.c | 602 ++- arch/um/drivers/ubd_user.c | 497 +-- arch/um/drivers/xterm.c | 21 +- arch/um/drivers/xterm_kern.c | 12 +- arch/um/dyn.lds.S | 15 +- arch/um/include/2_5compat.h | 14 - arch/um/include/kern_util.h | 11 +- arch/um/include/line.h | 4 +- arch/um/include/mconsole.h | 6 +- arch/um/include/mem.h | 15 +- arch/um/include/mem_user.h | 31 +- arch/um/include/os.h | 53 +- arch/um/include/signal_user.h | 2 + arch/um/include/skas_ptrace.h | 2 +- arch/um/include/sysdep-i386/frame_user.h | 28 +- arch/um/include/sysdep-i386/sigcontext.h | 4 +- arch/um/include/sysdep-i386/syscalls.h | 59 +- arch/um/include/ubd_user.h | 9 +- arch/um/include/um_uaccess.h | 51 + arch/um/include/user.h | 1 + arch/um/include/user_util.h | 7 +- arch/um/kernel/Makefile | 44 +- arch/um/kernel/config.c.in | 4 +- arch/um/kernel/exec_kern.c | 5 + arch/um/kernel/frame.c | 3 +- arch/um/kernel/frame_kern.c | 6 +- arch/um/kernel/helper.c | 55 +- arch/um/kernel/init_task.c | 17 +- arch/um/kernel/initrd_user.c | 13 +- arch/um/kernel/irq.c | 105 +- arch/um/kernel/irq_user.c | 37 +- arch/um/kernel/ksyms.c | 53 +- arch/um/kernel/mem.c | 657 +--- arch/um/kernel/mem_user.c | 222 +- arch/um/kernel/process.c | 20 +- arch/um/kernel/process_kern.c | 45 +- arch/um/kernel/ptrace.c | 20 +- arch/um/kernel/reboot.c | 2 + arch/um/kernel/sigio_kern.c | 7 +- arch/um/kernel/sigio_user.c | 96 +- arch/um/kernel/signal_kern.c | 60 +- arch/um/kernel/skas/Makefile | 24 +- arch/um/kernel/skas/include/mode.h | 6 +- arch/um/kernel/skas/include/skas.h | 4 +- arch/um/kernel/skas/include/uaccess.h | 207 +- arch/um/kernel/skas/mem_user.c | 32 +- arch/um/kernel/skas/mmu.c | 8 +- arch/um/kernel/skas/process.c | 107 +- arch/um/kernel/skas/process_kern.c | 26 +- arch/um/kernel/skas/sys-i386/Makefile | 2 - arch/um/kernel/skas/sys-i386/sigcontext.c | 15 +- arch/um/kernel/skas/syscall_kern.c | 2 +- arch/um/kernel/skas/syscall_user.c | 4 +- arch/um/kernel/skas/trap_user.c | 6 +- arch/um/kernel/skas/util/Makefile | 7 +- arch/um/kernel/skas/util/mk_ptregs.c | 1 + arch/um/kernel/smp.c | 63 +- arch/um/kernel/smp.c.orig | 302 ++ arch/um/kernel/sys_call_table.c | 687 ++-- arch/um/kernel/syscall_kern.c | 96 +- arch/um/kernel/sysrq.c | 5 + arch/um/kernel/tempfile.c | 7 +- arch/um/kernel/time.c | 69 +- arch/um/kernel/time_kern.c | 77 +- arch/um/kernel/trap_kern.c | 58 +- arch/um/kernel/trap_user.c | 9 +- arch/um/kernel/tt/Makefile | 6 +- arch/um/kernel/tt/exec_kern.c | 7 +- arch/um/kernel/tt/include/mode.h | 2 + arch/um/kernel/tt/include/uaccess.h | 60 +- arch/um/kernel/tt/mem_user.c | 7 +- arch/um/kernel/tt/process_kern.c | 82 +- arch/um/kernel/tt/ptproxy/Makefile | 2 - arch/um/kernel/tt/ptproxy/proxy.c | 25 +- arch/um/kernel/tt/ptproxy/sysdep.c | 1 + arch/um/kernel/tt/ptproxy/wait.c | 12 +- arch/um/kernel/tt/sys-i386/Makefile | 2 - arch/um/kernel/tt/syscall_kern.c | 2 +- arch/um/kernel/tt/syscall_user.c | 4 +- arch/um/kernel/tt/tlb.c | 1 + arch/um/kernel/tt/tracer.c | 27 +- arch/um/kernel/tt/uaccess_user.c | 22 +- arch/um/kernel/tt/unmap.c | 3 - arch/um/kernel/tty_log.c | 136 +- arch/um/kernel/uaccess_user.c | 2 +- arch/um/kernel/um_arch.c | 76 +- arch/um/kernel/umid.c | 80 +- arch/um/kernel/user_syms.c | 113 - arch/um/kernel/user_util.c | 15 +- arch/um/main.c | 7 +- arch/um/os-Linux/Makefile | 6 +- arch/um/os-Linux/drivers/ethertap_kern.c | 1 - arch/um/os-Linux/drivers/ethertap_user.c | 56 +- arch/um/os-Linux/drivers/tuntap_user.c | 57 +- arch/um/os-Linux/file.c | 450 ++- arch/um/os-Linux/process.c | 58 +- arch/um/os-Linux/tty.c | 10 +- arch/um/sys-i386/Makefile | 24 +- arch/um/sys-i386/bugs.c | 140 +- arch/um/sys-i386/extable.c | 30 - arch/um/sys-i386/fault.c | 16 +- arch/um/sys-i386/ptrace_user.c | 8 +- arch/um/sys-i386/time.c | 24 + arch/um/sys-i386/util/Makefile | 15 +- arch/um/sys-i386/util/mk_sc.c | 1 + arch/um/sys-ia64/Makefile | 15 +- arch/um/sys-ppc/Makefile | 11 +- arch/um/uml.lds.S | 10 +- arch/um/util/Makefile | 27 +- arch/um/util/mk_constants_kern.c | 4 + arch/v850/Kconfig | 2 + arch/v850/kernel/ptrace.c | 2 + arch/x86_64/Kconfig | 2 + arch/x86_64/defconfig | 4 +- arch/x86_64/ia32/fpu32.c | 16 +- arch/x86_64/ia32/ia32_aout.c | 3 +- arch/x86_64/ia32/ia32_binfmt.c | 13 +- arch/x86_64/ia32/ia32_ioctl.c | 10 +- arch/x86_64/ia32/ia32_signal.c | 36 +- arch/x86_64/ia32/ia32entry.S | 61 +- arch/x86_64/ia32/ptrace32.c | 30 +- arch/x86_64/ia32/sys_ia32.c | 124 +- arch/x86_64/ia32/syscall32.c | 6 +- arch/x86_64/ia32/tls32.c | 13 +- arch/x86_64/kernel/Makefile-HEAD | 38 - arch/x86_64/kernel/acpi/sleep.c | 1 + arch/x86_64/kernel/e820.c | 38 + arch/x86_64/kernel/head64.c | 9 - arch/x86_64/kernel/i387.c | 10 +- arch/x86_64/kernel/io_apic.c | 3 +- arch/x86_64/kernel/irq.c | 6 +- arch/x86_64/kernel/ldt.c | 8 +- arch/x86_64/kernel/mce.c | 62 +- arch/x86_64/kernel/module.c | 2 +- arch/x86_64/kernel/mpparse.c | 6 +- arch/x86_64/kernel/msr.c | 18 +- arch/x86_64/kernel/process.c | 9 +- arch/x86_64/kernel/ptrace.c | 43 +- arch/x86_64/kernel/setup.c | 9 +- arch/x86_64/kernel/setup64.c | 5 +- arch/x86_64/kernel/signal.c | 37 +- arch/x86_64/kernel/smpboot.c | 10 +- arch/x86_64/kernel/sys_x86_64.c | 10 +- arch/x86_64/kernel/traps.c | 4 +- arch/x86_64/kernel/vmlinux.lds.S | 5 +- arch/x86_64/kernel/x8664_ksyms.c | 3 + arch/x86_64/lib/Makefile | 4 +- arch/x86_64/lib/csum-wrappers.c | 12 +- arch/x86_64/lib/io.c | 10 +- arch/x86_64/lib/usercopy.c | 16 +- arch/x86_64/mm/init.c | 6 +- arch/x86_64/mm/ioremap.c | 1 - arch/x86_64/mm/pageattr.c | 39 +- configs/kernel-2.6.6-1.422-vs1.9.1-ckrm-E13 | 2415 ++++++++++++ configs/kernel-2.6.6-i586-smp.config | 2361 ++++++++++++ configs/kernel-2.6.6-i586.config | 2378 ++++++++++++ configs/kernel-2.6.6-i686-planetlab.config | 1126 ++++++ configs/kernel-2.6.6-i686-smp.config | 2364 ++++++++++++ configs/kernel-2.6.6-i686.config | 2379 ++++++++++++ configs/kernel-2.6.7-i586-smp.config | 2399 ++++++++++++ configs/kernel-2.6.7-i586.config | 2416 ++++++++++++ configs/kernel-2.6.7-i686-smp.config | 2402 ++++++++++++ configs/kernel-2.6.7-i686.config | 2417 ++++++++++++ drivers/acpi/dispatcher/dsopcode.c | 3 - drivers/acpi/ec.c | 2 +- drivers/atm/fore200e.c | 39 +- drivers/atm/fore200e.h | 26 +- drivers/base/node.c | 7 +- drivers/block/DAC960.c | 34 +- drivers/block/carmel.c | 2 +- drivers/block/cpqarray.c | 16 +- drivers/block/floppy.c | 2 +- drivers/block/ll_rw_blk.c | 6 +- drivers/block/loop.c | 4 +- drivers/block/paride/pg.c | 12 +- drivers/block/paride/pt.c | 12 +- drivers/block/ps2esdi.c | 16 +- drivers/block/rd.c | 15 +- drivers/block/scsi_ioctl.c | 4 +- drivers/block/umem.c | 2 +- drivers/bluetooth/hci_ldisc.c | 4 +- drivers/cdrom/aztcd.c | 45 +- drivers/cdrom/cdrom.c | 30 +- drivers/char/Kconfig | 4 +- drivers/char/Makefile | 2 + drivers/char/crash.c | 129 + drivers/char/drm/drm_agpsupport.h | 2 + drivers/char/drm/drm_ioctl.h | 7 - drivers/char/drm/ffb_drv.c | 8 +- drivers/char/drm/gamma_dma.c | 45 +- drivers/char/drm/i810_dma.c | 9 +- drivers/char/drm/i830_dma.c | 10 +- drivers/char/drm/r128_state.c | 8 +- drivers/char/drm/radeon.h | 4 +- drivers/char/drm/radeon_drm.h | 3 +- drivers/char/drm/radeon_drv.h | 1 - drivers/char/drm/radeon_state.c | 2 - drivers/char/dz.c | 1540 -------- drivers/char/dz.h | 230 -- drivers/char/hpet.c | 1076 ++++++ drivers/char/lp.c | 20 +- drivers/char/mem.c | 44 + drivers/char/ppdev.c | 51 +- drivers/char/sh-sci.c | 1646 --------- drivers/char/sh-sci.h | 478 --- drivers/cpufreq/cpufreq.c | 7 +- drivers/cpufreq/cpufreq_userspace.c | 4 +- drivers/firmware/edd.c | 52 +- drivers/i2c/busses/i2c-ixp42x.c | 176 - drivers/ide/Kconfig | 56 + drivers/ide/ide-cd.c | 78 +- drivers/ide/ide-disk.c | 206 +- drivers/ide/ide-io.c | 23 +- drivers/ide/ide-probe.c | 28 +- drivers/ide/ide-proc.c | 86 +- drivers/ide/ide-taskfile.c | 216 +- drivers/ide/ide.c | 52 +- drivers/ide/legacy/pdc4030.c | 6 + drivers/ide/pci/aec62xx.c | 10 +- drivers/ide/pci/alim15x3.h | 10 - drivers/ide/pci/amd74xx.h | 168 - drivers/ide/pci/cmd640.h | 32 - drivers/ide/pci/cmd64x.c | 6 +- drivers/ide/pci/cs5520.c | 26 +- drivers/ide/pci/cs5520.h | 12 +- drivers/ide/pci/cs5530.c | 14 +- drivers/ide/pci/cs5530.h | 11 +- drivers/ide/pci/hpt366.c | 16 +- drivers/ide/pci/ns87415.c | 12 +- drivers/ide/pci/ns87415.h | 11 - drivers/ide/pci/pdc202xx_new.c | 10 +- drivers/ide/pci/pdc202xx_old.c | 12 +- drivers/ide/pci/piix.c | 47 +- drivers/ide/pci/rz1000.c | 14 +- drivers/ide/pci/rz1000.h | 21 +- drivers/ide/pci/sc1200.c | 13 +- drivers/ide/pci/sc1200.h | 10 - drivers/ide/pci/siimage.c | 38 +- drivers/ide/pci/siimage.h | 20 - drivers/ide/pci/sis5513.c | 15 +- drivers/ide/pci/sis5513.h | 9 - drivers/ide/pci/sl82c105.c | 15 +- drivers/ide/pci/sl82c105.h | 9 - drivers/ide/pci/slc90e66.c | 14 +- drivers/ide/pci/slc90e66.h | 9 - drivers/ide/pci/triflex.c | 21 +- drivers/ide/pci/triflex.h | 5 - drivers/ide/pci/trm290.c | 14 +- drivers/ide/pci/trm290.h | 12 - drivers/ide/pci/via82cxxx.c | 15 +- drivers/ide/pci/via82cxxx.h | 19 - drivers/ide/ppc/swarm.c | 101 - drivers/ieee1394/csr1212.c | 6 +- drivers/ieee1394/hosts.c | 22 +- drivers/ieee1394/ieee1394_core.c | 6 - drivers/ieee1394/nodemgr.c | 14 +- drivers/ieee1394/sbp2.c | 2 +- drivers/input/Kconfig | 7 - drivers/input/evdev.c | 8 +- drivers/input/gameport/ns558.c | 14 +- drivers/input/gameport/vortex.c | 6 +- drivers/input/joystick/adi.c | 30 +- drivers/input/joystick/analog.c | 42 +- drivers/input/joystick/gf2k.c | 12 +- drivers/input/misc/98spkr.c | 4 +- drivers/input/misc/pcspkr.c | 4 +- drivers/input/mousedev.c | 290 +- drivers/input/serio/serport.c | 10 +- drivers/md/dm-exception-store.c | 648 ++++ drivers/md/dm-io.c | 647 ++++ drivers/md/dm-io.h | 77 + drivers/md/dm-ioctl.c | 10 +- drivers/md/dm-log.c | 629 ++++ drivers/md/dm-log.h | 124 + drivers/md/dm-raid1.c | 1278 +++++++ drivers/md/dm-snap.c | 1213 ++++++ drivers/md/dm-snap.h | 161 + drivers/md/dm-zero.c | 98 + drivers/md/kcopyd.c | 699 ++++ drivers/md/kcopyd.h | 42 + drivers/md/md.c | 177 +- drivers/md/multipath.c | 47 +- drivers/md/raid1.c | 205 +- drivers/md/raid5.c | 31 +- drivers/md/raid6main.c | 31 +- drivers/mtd/chips/jedec_probe.c | 42 - drivers/mtd/maps/Kconfig | 8 - drivers/mtd/maps/Makefile | 1 - drivers/net/3c59x.c | 45 +- drivers/net/8139too.c | 3 +- drivers/net/Kconfig | 1 - drivers/net/acenic.c | 2 +- drivers/net/arm/smc91x.c | 2171 +++++++++++ drivers/net/arm/smc91x.h | 829 +++++ drivers/net/auto_irq.c | 68 - drivers/net/b44.c | 2 +- drivers/net/e100.c | 14 +- drivers/net/e1000/e1000_main.c | 5 +- drivers/net/eepro100.c | 6 +- drivers/net/fealnx.c | 3 +- drivers/net/ibmveth.c | 4 +- drivers/net/ixgb/ixgb_ethtool.c | 6 +- drivers/net/ne-h8300.c | 6 +- drivers/net/pcmcia/axnet_cs.c | 2 +- drivers/net/pcnet32.c | 3 +- drivers/net/plip.c | 2 +- drivers/net/rcif.h | 292 -- drivers/net/rclanmtl.c | 2029 ---------- drivers/net/rclanmtl.h | 701 ---- drivers/net/rcpci45.c | 1049 ------ drivers/net/s2io.c | 78 +- drivers/net/sb1000.c | 4 +- drivers/net/sis900.c | 2 +- drivers/net/sk98lin/h/skdrv2nd.h | 3 +- drivers/net/sk98lin/skge.c | 3 +- drivers/net/tg3.c | 27 +- drivers/net/tlan.c | 2 +- drivers/net/tokenring/ibmtr.c | 9 +- drivers/net/tulip/tulip_core.c | 6 +- drivers/net/tulip/winbond-840.c | 4 +- drivers/net/via-rhine.c | 3 +- drivers/net/via-velocity.c | 3277 +++++++++++++++++ drivers/net/via-velocity.h | 1885 ++++++++++ drivers/net/wan/comx-hw-comx.c | 1450 -------- drivers/net/wan/comx-hw-locomx.c | 496 --- drivers/net/wan/comx-hw-mixcom.c | 960 ----- drivers/net/wan/comx-hw-munich.c | 2854 -------------- drivers/net/wan/comx-proto-fr.c | 1014 ----- drivers/net/wan/comx-proto-lapb.c | 551 --- drivers/net/wan/comx-proto-ppp.c | 269 -- drivers/net/wan/comx.c | 1128 ------ drivers/net/wan/comx.h | 232 -- drivers/net/wan/comxhw.h | 113 - drivers/net/wan/falc-lh.h | 102 - drivers/net/wan/hscx.h | 103 - drivers/net/wan/mixcom.h | 35 - drivers/net/wan/munich32x.h | 191 - drivers/net/wan/wanxlfw.inc | 158 - drivers/net/wireless/airo.c | 59 +- drivers/net/wireless/prism54/prismcompat.h | 46 + drivers/pci/pci.ids | 3 - drivers/pci/search.c | 2 +- drivers/pcmcia/sa1100.h | 164 - drivers/pcmcia/sa11xx_core.c | 971 ----- drivers/pcmcia/sa11xx_core.h | 121 - drivers/s390/Kconfig | 14 - drivers/s390/block/dasd.c | 6 +- drivers/s390/block/dasd_eckd.c | 10 +- drivers/s390/cio/css.c | 75 +- drivers/s390/cio/device.c | 18 +- drivers/s390/cio/device_fsm.c | 174 +- drivers/s390/cio/qdio.c | 12 +- drivers/s390/cio/qdio.h | 2 + drivers/s390/net/iucv.c | 9 +- drivers/s390/net/netiucv.c | 25 +- drivers/s390/net/qeth.h | 21 +- drivers/s390/net/qeth_main.c | 239 +- drivers/s390/net/qeth_sys.c | 16 +- drivers/scsi/3w-9xxx.c | 2153 +++++++++++ drivers/scsi/3w-9xxx.h | 704 ++++ drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/53c700.c | 2 +- drivers/scsi/53c7xx.c | 2 +- drivers/scsi/BusLogic.c | 2 +- drivers/scsi/Kconfig | 10 +- drivers/scsi/NCR53C9x.c | 2 +- drivers/scsi/NCR53c406a.c | 2 +- drivers/scsi/NCR_D700.c | 2 +- drivers/scsi/NCR_Q720.c | 2 +- drivers/scsi/a2091.c | 2 +- drivers/scsi/a3000.c | 2 +- drivers/scsi/advansys.c | 2 +- drivers/scsi/aha152x.c | 4 +- drivers/scsi/aha1542.c | 2 +- drivers/scsi/aha1740.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.h | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 +- drivers/scsi/aic7xxx/aiclib.c | 2 +- drivers/scsi/aic7xxx_old.c | 2 +- drivers/scsi/amiga7xx.c | 2 +- drivers/scsi/ata_piix.c | 27 +- drivers/scsi/atari_scsi.c | 2 +- drivers/scsi/atp870u.c | 2 +- drivers/scsi/blz1230.c | 2 +- drivers/scsi/blz2060.c | 2 +- drivers/scsi/bvme6000.c | 2 +- drivers/scsi/constants.c | 2 +- drivers/scsi/cpqfcTScontrol.c | 4 +- drivers/scsi/cpqfcTSinit.c | 4 +- drivers/scsi/cpqfcTSworker.c | 2 +- drivers/scsi/cyberstorm.c | 2 +- drivers/scsi/cyberstormII.c | 2 +- drivers/scsi/dc395x.c | 2 +- drivers/scsi/dec_esp.c | 2 +- drivers/scsi/dmx3191d.c | 2 +- drivers/scsi/dpt_i2o.c | 2 +- drivers/scsi/dtc.c | 2 +- drivers/scsi/eata.c | 2 +- drivers/scsi/eata_pio.c | 2 +- drivers/scsi/esp.c | 9 +- drivers/scsi/esp.h | 15 +- drivers/scsi/fastlane.c | 2 +- drivers/scsi/fcal.c | 2 +- drivers/scsi/fd_mcs.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/g_NCR5380.c | 2 +- drivers/scsi/gdth.c | 69 +- drivers/scsi/gvp11.c | 2 +- drivers/scsi/hosts.h | 2 +- drivers/scsi/i60uscsi.c | 2 +- drivers/scsi/ibmmca.c | 2 +- drivers/scsi/ide-scsi.c | 16 +- drivers/scsi/imm.h | 2 +- drivers/scsi/in2000.c | 2 +- drivers/scsi/ini9100u.c | 2 +- drivers/scsi/ipr.c | 13 +- drivers/scsi/ipr.h | 4 +- drivers/scsi/ips.c | 2 +- drivers/scsi/jazz_esp.c | 2 +- drivers/scsi/lasi700.c | 2 +- drivers/scsi/mac_esp.c | 2 +- drivers/scsi/mac_scsi.c | 2 +- drivers/scsi/mca_53c9x.c | 2 +- drivers/scsi/megaraid.c | 6 +- drivers/scsi/mvme147.c | 2 +- drivers/scsi/mvme16x.c | 2 +- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/nsp32.c | 2 +- drivers/scsi/oktagon_esp.c | 2 +- drivers/scsi/osst.c | 16 +- drivers/scsi/pas16.c | 2 +- drivers/scsi/pc980155.c | 2 +- drivers/scsi/pci2000.c | 2 +- drivers/scsi/pci2220i.c | 2 +- drivers/scsi/pcmcia/aha152x_stub.c | 2 +- drivers/scsi/pcmcia/fdomain_stub.c | 2 +- drivers/scsi/pcmcia/qlogic_core.c | 2 - drivers/scsi/pcmcia/qlogic_stub.c | 2 +- drivers/scsi/pluto.c | 2 +- drivers/scsi/ppa.h | 2 +- drivers/scsi/psi240i.c | 2 +- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qla2xxx/qla_os.h | 2 +- drivers/scsi/qlogicfas.c | 2 +- drivers/scsi/qlogicfas.h | 124 - drivers/scsi/qlogicfas408.c | 2 +- drivers/scsi/qlogicfc.c | 2 +- drivers/scsi/qlogicisp.c | 2 +- drivers/scsi/qlogicpti.c | 11 +- drivers/scsi/qlogicpti.h | 15 +- drivers/scsi/scsi_debug.c | 10 +- drivers/scsi/scsi_devinfo.c | 9 +- drivers/scsi/scsi_error.c | 2 +- drivers/scsi/scsi_ioctl.c | 2 +- drivers/scsi/scsi_module.c | 2 +- drivers/scsi/scsi_pc98.c | 2 +- drivers/scsi/scsicam.c | 2 +- drivers/scsi/sd.c | 2 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/sg.c | 8 +- drivers/scsi/sgiwd93.c | 2 +- drivers/scsi/sim710.c | 2 +- drivers/scsi/sr.c | 2 +- drivers/scsi/sr_ioctl.c | 2 +- drivers/scsi/sr_vendor.c | 2 +- drivers/scsi/st.c | 18 +- drivers/scsi/sun3_scsi.c | 2 +- drivers/scsi/sun3_scsi_vme.c | 2 +- drivers/scsi/sun3x_esp.c | 2 +- drivers/scsi/sym53c416.c | 2 +- drivers/scsi/t128.c | 2 +- drivers/scsi/tmscsim.c | 2 +- drivers/scsi/u14-34f.c | 2 +- drivers/scsi/ultrastor.c | 2 +- drivers/scsi/wd33c93.c | 2 +- drivers/scsi/wd7000.c | 2 +- drivers/scsi/zalon.c | 2 +- drivers/usb/class/cdc-acm.h | 115 + drivers/usb/core/devio.c | 41 +- drivers/usb/core/driverfs.c | 229 -- drivers/usb/core/sysfs.c | 89 +- drivers/usb/gadget/ether.c | 6 +- drivers/usb/host/ohci-lh7a404.c | 385 ++ drivers/usb/media/pwc-if.c | 9 +- drivers/usb/media/w9968cf.c | 9 +- drivers/usb/misc/phidgetservo.c | 115 +- drivers/usb/net/kaweth.c | 2 +- drivers/usb/net/pegasus.c | 6 +- drivers/usb/net/rtl8150.c | 6 +- drivers/usb/net/usbnet.c | 4 +- drivers/usb/serial/cyberjack.c | 21 +- drivers/usb/storage/scsiglue.c | 2 +- drivers/video/aty/radeon_base.c | 123 +- drivers/video/pxafb.c | 94 +- drivers/video/riva/fbdev.c | 21 +- drivers/video/riva/rivafb-i2c.c | 209 ++ drivers/video/vga16fb.c | 2 + fs/Kconfig | 56 +- fs/Makefile | 4 + fs/Makefile.orig | 94 + fs/affs/symlink.c | 5 +- fs/aio.c | 37 +- fs/attr.c | 20 + fs/autofs/symlink.c | 11 +- fs/autofs4/symlink.c | 13 +- fs/bad_inode.c | 3 +- fs/befs/debug.c | 2 +- fs/befs/linuxvfs.c | 64 +- fs/binfmt_aout.c | 6 +- fs/binfmt_elf.c | 157 +- fs/binfmt_flat.c | 3 +- fs/binfmt_misc.c | 14 +- fs/binfmt_som.c | 3 +- fs/cifs/AUTHORS | 5 +- fs/cifs/CHANGES | 17 - fs/cifs/README | 11 +- fs/cifs/TODO | 16 +- fs/cifs/cifs_debug.c | 116 +- fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsfs.h | 4 +- fs/cifs/cifspdu.h | 66 +- fs/cifs/cifsproto.h | 7 - fs/cifs/cifssmb.c | 157 +- fs/cifs/connect.c | 71 +- fs/cifs/dir.c | 21 +- fs/cifs/fcntl.c | 18 +- fs/cifs/file.c | 267 +- fs/cifs/inode.c | 76 +- fs/cifs/link.c | 2 +- fs/cifs/transport.c | 22 +- fs/coda/cnode.c | 5 +- fs/compat_ioctl.c | 21 +- fs/dcache.c | 55 +- fs/devfs/base.c | 37 +- fs/devpts/inode.c | 12 + fs/direct-io.c | 29 +- fs/dquot.c | 30 +- fs/eventpoll.c | 5 - fs/exec.c | 37 +- fs/ext2/ialloc.c | 3 +- fs/ext2/inode.c | 66 +- fs/ext2/ioctl.c | 4 +- fs/ext2/super.c | 10 +- fs/ext2/symlink.c | 17 +- fs/ext3/Makefile | 2 +- fs/ext3/acl.c | 10 +- fs/ext3/balloc.c | 678 +++- fs/ext3/file.c | 6 +- fs/ext3/ialloc.c | 12 +- fs/ext3/inode.c | 222 +- fs/ext3/ioctl.c | 114 +- fs/ext3/namei.c | 27 +- fs/ext3/super.c | 74 +- fs/ext3/symlink.c | 19 +- fs/ext3/xattr.c | 8 +- fs/fcntl.c | 8 +- fs/file_table.c | 2 + fs/freevxfs/vxfs_immed.c | 29 +- fs/fs-writeback.c | 23 +- fs/hugetlbfs/inode.c | 10 +- fs/inode.c | 34 +- fs/intermezzo/Makefile | 11 - fs/intermezzo/cache.c | 207 -- fs/intermezzo/dcache.c | 342 -- fs/intermezzo/dir.c | 1333 ------- fs/intermezzo/ext_attr.c | 197 - fs/intermezzo/file.c | 534 --- fs/intermezzo/fileset.c | 674 ---- fs/intermezzo/inode.c | 179 - fs/intermezzo/intermezzo_fs.h | 923 ----- fs/intermezzo/intermezzo_idl.h | 304 -- fs/intermezzo/intermezzo_journal.h | 24 - fs/intermezzo/intermezzo_kml.h | 260 -- fs/intermezzo/intermezzo_lib.h | 162 - fs/intermezzo/intermezzo_psdev.h | 55 - fs/intermezzo/intermezzo_upcall.h | 146 - fs/intermezzo/journal.c | 2452 ------------ fs/intermezzo/journal_ext2.c | 90 - fs/intermezzo/journal_ext3.c | 283 -- fs/intermezzo/journal_obdfs.c | 193 - fs/intermezzo/journal_reiserfs.c | 140 - fs/intermezzo/journal_tmpfs.c | 107 - fs/intermezzo/journal_xfs.c | 161 - fs/intermezzo/kml.c | 194 - fs/intermezzo/kml_decode.c | 1016 ----- fs/intermezzo/kml_reint.c | 647 ---- fs/intermezzo/kml_setup.c | 58 - fs/intermezzo/kml_unpack.c | 712 ---- fs/intermezzo/kml_utils.c | 43 - fs/intermezzo/methods.c | 493 --- fs/intermezzo/presto.c | 736 ---- fs/intermezzo/psdev.c | 647 ---- fs/intermezzo/replicator.c | 290 -- fs/intermezzo/super.c | 407 -- fs/intermezzo/sysctl.c | 368 -- fs/intermezzo/upcall.c | 559 --- fs/intermezzo/vfs.c | 2416 ------------ fs/ioctl.c | 50 + fs/isofs/export.c | 228 ++ fs/jbd/journal.c | 46 +- fs/jffs2/symlink.c | 39 +- fs/jfs/jfs_dtree.c | 19 +- fs/jfs/jfs_imap.c | 21 +- fs/jfs/jfs_metapage.c | 1 - fs/jfs/jfs_txnmgr.c | 42 +- fs/jfs/jfs_types.h | 3 +- fs/jfs/namei.c | 107 +- fs/jfs/symlink.c | 11 +- fs/jfs/xattr.c | 25 +- fs/lockd/clntlock.c | 1 + fs/minix/inode.c | 5 +- fs/namei.c | 119 +- fs/namespace.c | 52 +- fs/nfs/direct.c | 6 +- fs/nfs/nfsroot.c | 2 +- fs/nfs/write.c | 5 +- fs/nfsd/nfs3xdr.c | 39 +- fs/nfsd/nfs4xdr.c | 83 +- fs/nfsd/nfsfh.c | 2 +- fs/ntfs/ChangeLog | 73 +- fs/ntfs/Makefile | 2 +- fs/ntfs/aops.c | 52 +- fs/ntfs/attrib.c | 4 +- fs/ntfs/compress.c | 4 +- fs/ntfs/dir.c | 47 +- fs/ntfs/inode.c | 117 +- fs/ntfs/mft.c | 662 ---- fs/ntfs/mft.h | 54 - fs/ntfs/super.c | 333 +- fs/open.c | 17 +- fs/partitions/msdos.c | 17 +- fs/pipe.c | 2 + fs/proc/array.c | 84 +- fs/proc/base.c | 82 +- fs/proc/generic.c | 33 +- fs/proc/inode.c | 2 + fs/proc/kcore.c | 2 +- fs/proc/proc_misc.c | 4 + fs/proc/root.c | 4 + fs/proc/task_mmu.c | 15 +- fs/rcfs/Makefile | 10 + fs/rcfs/dir.c | 336 ++ fs/rcfs/inode.c | 204 + fs/rcfs/magic.c | 546 +++ fs/rcfs/rootdir.c | 244 ++ fs/rcfs/socket_fs.c | 338 ++ fs/rcfs/super.c | 288 ++ fs/rcfs/tc_magic.c | 94 + fs/read_write.c | 2 - fs/reiserfs/inode.c | 68 +- fs/reiserfs/ioctl.c | 12 +- fs/reiserfs/namei.c | 5 +- fs/relayfs/Makefile | 8 + fs/relayfs/inode.c | 629 ++++ fs/relayfs/klog.c | 206 ++ fs/relayfs/relay.c | 1911 ++++++++++ fs/relayfs/relay_locking.c | 322 ++ fs/relayfs/relay_locking.h | 34 + fs/relayfs/relay_lockless.c | 541 +++ fs/relayfs/relay_lockless.h | 34 + fs/relayfs/resize.c | 1091 ++++++ fs/relayfs/resize.h | 51 + fs/smbfs/proto.h | 2 - fs/smbfs/symlink.c | 48 +- fs/stat.c | 4 - fs/sysfs/file.c | 1 - fs/sysv/inode.c | 5 +- fs/sysv/symlink.c | 12 +- fs/ufs/symlink.c | 11 +- fs/xfs/linux-2.6/xfs_iops.c | 30 +- fs/xfs/linux/kmem.h | 197 - fs/xfs/linux/mrlock.h | 106 - fs/xfs/linux/mutex.h | 53 - fs/xfs/linux/sema.h | 67 - fs/xfs/linux/spin.h | 74 - fs/xfs/linux/sv.h | 89 - fs/xfs/linux/time.h | 51 - fs/xfs/linux/xfs_aops.c | 1276 ------- fs/xfs/linux/xfs_buf.c | 1811 --------- fs/xfs/linux/xfs_buf.h | 594 --- fs/xfs/linux/xfs_cred.h | 50 - fs/xfs/linux/xfs_file.c | 546 --- fs/xfs/linux/xfs_fs_subr.c | 124 - fs/xfs/linux/xfs_fs_subr.h | 49 - fs/xfs/linux/xfs_globals.c | 72 - fs/xfs/linux/xfs_globals.h | 44 - fs/xfs/linux/xfs_ioctl.c | 1236 ------- fs/xfs/linux/xfs_iops.c | 708 ---- fs/xfs/linux/xfs_iops.h | 51 - fs/xfs/linux/xfs_linux.h | 367 -- fs/xfs/linux/xfs_lrw.c | 1028 ------ fs/xfs/linux/xfs_lrw.h | 116 - fs/xfs/linux/xfs_stats.c | 132 - fs/xfs/linux/xfs_stats.h | 164 - fs/xfs/linux/xfs_super.c | 850 ----- fs/xfs/linux/xfs_super.h | 129 - fs/xfs/linux/xfs_sysctl.c | 163 - fs/xfs/linux/xfs_sysctl.h | 107 - fs/xfs/linux/xfs_version.h | 44 - fs/xfs/linux/xfs_vfs.c | 327 -- fs/xfs/linux/xfs_vfs.h | 206 -- fs/xfs/linux/xfs_vnode.c | 442 --- fs/xfs/linux/xfs_vnode.h | 651 ---- fs/xfs/xfs_dinode.h | 6 + fs/xfs/xfs_fs.h | 2 + fs/xfs/xfs_inode.c | 4 + fs/xfs/xfs_vnodeops.c | 4 + include/acpi/platform/aclinux.h | 3 +- include/asm-alpha/fcntl.h | 1 + include/asm-alpha/relay.h | 5 + include/asm-alpha/resource.h | 2 +- include/asm-alpha/rmap.h | 7 - include/asm-alpha/unistd.h | 1 + include/asm-arm/arch-cl7500/ide.h | 50 - include/asm-arm/arch-cl7500/keyboard.h | 16 - include/asm-arm/arch-clps711x/keyboard.h | 26 - include/asm-arm/arch-ebsa110/ide.h | 1 - include/asm-arm/arch-ebsa285/ide.h | 49 - include/asm-arm/arch-iop3xx/ide.h | 49 - include/asm-arm/arch-l7200/ide.h | 27 - include/asm-arm/arch-l7200/keyboard.h | 51 - include/asm-arm/arch-lh7a40x/hardware.h | 4 +- include/asm-arm/arch-nexuspci/ide.h | 37 - include/asm-arm/arch-omap/dma.h | 149 +- include/asm-arm/arch-omap/hardware.h | 222 +- include/asm-arm/arch-omap/mux.h | 12 +- include/asm-arm/arch-omap/uncompress.h | 2 +- include/asm-arm/arch-pxa/hardware.h | 9 + include/asm-arm/arch-pxa/ide.h | 54 - include/asm-arm/arch-pxa/keyboard.h | 28 - include/asm-arm/arch-rpc/ide.h | 48 - include/asm-arm/arch-s3c2410/ide.h | 49 - include/asm-arm/arch-sa1100/keyboard.h | 23 - include/asm-arm/arch-shark/ide.h | 47 - include/asm-arm/arch-shark/keyboard.h | 68 - include/asm-arm/arch-tbox/ide.h | 3 - include/asm-arm/cacheflush.h | 12 +- include/asm-arm/hardware/clock.h | 121 + include/asm-arm/pgtable.h | 7 - include/asm-arm/relay.h | 5 + include/asm-arm/resource.h | 2 +- include/asm-arm/rmap.h | 6 - include/asm-arm/tlb.h | 3 +- include/asm-arm/unistd.h | 1 - include/asm-arm/vfp.h | 78 + include/asm-arm/vfpmacros.h | 25 + include/asm-arm26/relay.h | 5 + include/asm-arm26/resource.h | 2 +- include/asm-arm26/rmap.h | 66 - include/asm-arm26/tlb.h | 3 +- include/asm-arm26/unistd.h | 1 - include/asm-cris/relay.h | 5 + include/asm-cris/resource.h | 2 +- include/asm-cris/rmap.h | 7 - include/asm-cris/unistd.h | 1 - include/asm-generic/relay.h | 76 + include/asm-generic/rmap.h | 91 - include/asm-generic/tlb.h | 4 +- include/asm-h8300/aki3068net/machine-depend.h | 29 - include/asm-h8300/edosk2674/machine-depend.h | 70 - include/asm-h8300/generic/machine-depend.h | 17 - include/asm-h8300/generic/timer_rate.h | 15 - include/asm-h8300/h8300_smsc.h | 20 - include/asm-h8300/h8max/machine-depend.h | 100 - include/asm-h8300/relay.h | 5 + include/asm-h8300/resource.h | 2 +- include/asm-h8300/unistd.h | 1 - include/asm-i386/acpi.h | 2 - include/asm-i386/atomic_kmap.h | 96 + include/asm-i386/checksum.h | 30 +- include/asm-i386/cpufeature.h | 2 + include/asm-i386/crash.h | 75 + include/asm-i386/desc.h | 49 +- include/asm-i386/elf.h | 47 +- include/asm-i386/fcntl.h | 1 + include/asm-i386/fixmap.h | 37 +- include/asm-i386/highmem.h | 12 +- include/asm-i386/irq.h | 4 - include/asm-i386/kmap_types.h | 48 +- include/asm-i386/mmu.h | 11 +- include/asm-i386/mmu_context.h | 12 +- include/asm-i386/module.h | 4 - include/asm-i386/msr.h | 9 + include/asm-i386/page.h | 38 +- include/asm-i386/pgalloc.h | 3 + include/asm-i386/pgtable-3level.h | 12 +- include/asm-i386/pgtable.h | 111 +- include/asm-i386/processor.h | 45 +- include/asm-i386/relay.h | 101 + include/asm-i386/resource.h | 2 +- include/asm-i386/rmap.h | 21 - include/asm-i386/string.h | 23 + include/asm-i386/thread_info.h | 11 +- include/asm-i386/tlbflush.h | 9 +- include/asm-i386/uaccess.h | 180 +- include/asm-i386/unistd.h | 8 +- include/asm-ia64/crash.h | 90 + include/asm-ia64/fcntl.h | 1 + include/asm-ia64/pgalloc.h | 4 + include/asm-ia64/relay.h | 5 + include/asm-ia64/resource.h | 2 +- include/asm-ia64/rmap.h | 7 - include/asm-ia64/sn/pda.h | 2 +- include/asm-ia64/system.h | 2 +- include/asm-ia64/tlb.h | 3 +- include/asm-ia64/unistd.h | 4 +- include/asm-m68k/relay.h | 5 + include/asm-m68k/resource.h | 2 +- include/asm-m68k/rmap.h | 7 - include/asm-m68k/unistd.h | 5 +- include/asm-m68knommu/relay.h | 5 + include/asm-m68knommu/rmap.h | 2 - include/asm-m68knommu/unistd.h | 5 +- include/asm-mips/relay.h | 5 + include/asm-mips/rmap.h | 7 - include/asm-mips/unistd.h | 22 +- include/asm-mips64/relay.h | 5 + include/asm-parisc/relay.h | 5 + include/asm-parisc/resource.h | 2 +- include/asm-parisc/rmap.h | 7 - include/asm-parisc/unistd.h | 5 +- include/asm-ppc/fcntl.h | 1 + include/asm-ppc/fsl_ocp.h | 54 + include/asm-ppc/immap_85xx.h | 126 + include/asm-ppc/mpc85xx.h | 128 + include/asm-ppc/pgalloc.h | 5 + include/asm-ppc/pgtable.h | 6 +- include/asm-ppc/reg_booke.h | 27 +- include/asm-ppc/relay.h | 5 + include/asm-ppc/resource.h | 2 +- include/asm-ppc/rmap.h | 9 - include/asm-ppc/spinlock.h | 22 +- include/asm-ppc/unistd.h | 3 +- include/asm-ppc64/fcntl.h | 1 + include/asm-ppc64/io.h | 6 +- include/asm-ppc64/paca.h | 4 +- include/asm-ppc64/pgalloc.h | 5 + include/asm-ppc64/pgtable.h | 5 +- include/asm-ppc64/relay.h | 5 + include/asm-ppc64/resource.h | 2 +- include/asm-ppc64/rmap.h | 9 - include/asm-ppc64/unistd.h | 3 +- include/asm-s390/atomic.h | 2 +- include/asm-s390/fcntl.h | 1 + include/asm-s390/pgalloc.h | 4 + include/asm-s390/pgtable.h | 4 - include/asm-s390/relay.h | 5 + include/asm-s390/resource.h | 2 +- include/asm-s390/rmap.h | 7 - include/asm-s390/spinlock.h | 8 +- include/asm-s390/types.h | 5 +- include/asm-s390/uaccess.h | 52 +- include/asm-s390/unistd.h | 3 +- include/asm-sh/relay.h | 5 + include/asm-sh/resource.h | 2 +- include/asm-sh/rmap.h | 7 - include/asm-sh/unistd.h | 1 - include/asm-sparc/fcntl.h | 1 + include/asm-sparc/pgalloc.h | 4 + include/asm-sparc/pgtable.h | 31 +- include/asm-sparc/relay.h | 5 + include/asm-sparc/resource.h | 2 +- include/asm-sparc/rmap.h | 7 - include/asm-sparc/unistd.h | 2 +- include/asm-sparc64/fcntl.h | 1 + include/asm-sparc64/pgalloc.h | 4 + include/asm-sparc64/relay.h | 5 + include/asm-sparc64/resource.h | 2 +- include/asm-sparc64/rmap.h | 7 - include/asm-sparc64/unistd.h | 2 +- include/asm-um/archparam-i386.h | 89 +- include/asm-um/common.lds.S | 48 +- include/asm-um/current.h | 6 +- include/asm-um/dma-mapping.h | 120 +- include/asm-um/elf.h | 13 + include/asm-um/fixmap.h | 8 + include/asm-um/irq.h | 18 - include/asm-um/module-i386.h | 13 + include/asm-um/page.h | 43 +- include/asm-um/pgalloc.h | 4 + include/asm-um/pgtable.h | 109 +- include/asm-um/processor-generic.h | 44 +- include/asm-um/processor-i386.h | 4 +- include/asm-um/rmap.h | 6 - include/asm-um/smp.h | 2 +- include/asm-um/smplock.h | 6 - include/asm-um/spinlock.h | 10 - include/asm-um/system-generic.h | 9 +- include/asm-um/system-i386.h | 31 - include/asm-um/thread_info.h | 16 +- include/asm-um/timex.h | 2 - include/asm-um/uaccess.h | 2 + include/asm-um/unistd.h | 6 +- include/asm-v850/relay.h | 5 + include/asm-v850/resource.h | 2 +- include/asm-v850/rmap.h | 1 - include/asm-v850/unistd.h | 1 - include/asm-x86_64/bitops.h | 7 +- include/asm-x86_64/checksum.h | 4 +- include/asm-x86_64/compat.h | 8 +- include/asm-x86_64/fcntl.h | 1 + include/asm-x86_64/floppy.h | 2 +- include/asm-x86_64/fpu32.h | 4 +- include/asm-x86_64/i387.h | 12 +- include/asm-x86_64/ia32.h | 4 +- include/asm-x86_64/ia32_unistd.h | 3 +- include/asm-x86_64/ide.h | 68 +- include/asm-x86_64/io.h | 9 +- include/asm-x86_64/page.h | 11 +- include/asm-x86_64/pgalloc.h | 5 + include/asm-x86_64/pgtable.h | 28 +- include/asm-x86_64/processor.h | 2 +- include/asm-x86_64/ptrace.h | 2 +- include/asm-x86_64/relay.h | 5 + include/asm-x86_64/resource.h | 2 +- include/asm-x86_64/rmap.h | 7 - include/asm-x86_64/semaphore.h | 14 +- include/asm-x86_64/sigcontext.h | 3 +- include/asm-x86_64/uaccess.h | 56 +- include/asm-x86_64/unistd.h | 1 - include/linux/aio.h | 11 +- include/linux/buffer_head.h | 1 + include/linux/capability.h | 6 + include/linux/cdrom.h | 4 +- include/linux/ckrm.h | 162 + include/linux/ckrm_ce.h | 91 + include/linux/ckrm_net.h | 41 + include/linux/ckrm_rc.h | 367 ++ include/linux/ckrm_tc.h | 18 + include/linux/ckrm_tsk.h | 41 + include/linux/compat_ioctl.h | 1 - include/linux/compiler-gcc+.h | 1 + include/linux/compiler-gcc3.h | 5 + include/linux/compiler.h | 8 + include/linux/config.h | 4 +- include/linux/cpumask.h | 1 - include/linux/dcache.h | 8 +- include/linux/delay.h | 17 +- include/linux/errno.h | 3 + include/linux/ext2_fs.h | 6 +- include/linux/ext3_fs.h | 97 +- include/linux/ext3_fs_i.h | 17 +- include/linux/ext3_fs_sb.h | 4 + include/linux/file.h | 2 + include/linux/fs.h | 23 +- include/linux/gfp.h | 7 +- include/linux/ghash.h | 236 ++ include/linux/highmem.h | 7 +- include/linux/hpet.h | 133 + include/linux/hugetlb.h | 3 +- include/linux/ide.h | 38 +- include/linux/if.h | 6 +- include/linux/if_bridge.h | 2 +- include/linux/init_task.h | 4 + include/linux/ip.h | 1 + include/linux/ipc.h | 1 + include/linux/jbd.h | 1 + include/linux/klog.h | 24 + include/linux/kmalloc_sizes.h | 1 + include/linux/mempolicy.h | 11 + include/linux/mm.h | 30 +- include/linux/module.h | 21 - include/linux/mroute.h | 2 +- include/linux/namei.h | 5 + include/linux/namespace.h | 1 + include/linux/net.h | 3 +- include/linux/netdevice.h | 2 +- include/linux/netfilter.h | 6 - include/linux/nfs_fs.h | 2 +- include/linux/nfsd/export.h | 3 +- include/linux/nfsd/nfsd.h | 2 +- include/linux/ninline.h | 159 + include/linux/page-flags.h | 6 +- include/linux/pci.h | 6 +- include/linux/pci_ids.h | 4 - include/linux/poll.h | 8 +- include/linux/proc_fs.h | 3 + include/linux/proc_mm.h | 48 + include/linux/rcfs.h | 98 + include/linux/reiserfs_fs.h | 7 + include/linux/relayfs_fs.h | 686 ++++ include/linux/resource.h | 5 +- include/linux/sched.h | 100 +- include/linux/skbuff.h | 2 + include/linux/smp_lock.h | 4 +- include/linux/socket.h | 5 + include/linux/syscalls.h | 3 +- include/linux/sysctl.h | 52 +- include/linux/taskdelays.h | 20 + include/linux/tcp.h | 44 +- include/linux/time.h | 14 +- include/linux/types.h | 2 + include/linux/usb.h | 1 - include/linux/vinline.h | 471 +++ include/linux/vmalloc.h | 1 + include/linux/vs_base.h | 78 + include/linux/vs_context.h | 128 + include/linux/vs_cvirt.h | 71 + include/linux/vs_dlimit.h | 169 + include/linux/vs_limit.h | 119 + include/linux/vs_memory.h | 132 + include/linux/vs_network.h | 154 + include/linux/vs_socket.h | 65 + include/linux/vserver.h | 13 + include/linux/vserver/context.h | 179 + include/linux/vserver/cvirt.h | 133 + include/linux/vserver/dlimit.h | 83 + include/linux/vserver/inode.h | 67 + include/linux/vserver/legacy.h | 54 + include/linux/vserver/limit.h | 140 + include/linux/vserver/namespace.h | 55 + include/linux/vserver/network.h | 146 + include/linux/vserver/sched.h | 139 + include/linux/vserver/signal.h | 19 + include/linux/vserver/switch.h | 96 + include/linux/vserver/xid.h | 94 + include/linux/wait.h | 4 +- include/net/af_unix.h | 27 +- include/net/bluetooth/hci_core.h | 12 +- include/net/bluetooth/rfcomm.h | 2 +- include/net/ip.h | 4 +- include/net/ip6_route.h | 2 +- include/net/ipv6.h | 3 +- include/net/route.h | 71 +- include/net/scm.h | 4 +- include/net/sock.h | 64 +- include/net/tcp.h | 151 +- include/net/tux.h | 800 ++++ include/net/tux_u.h | 163 + include/net/xfrm.h | 2 +- include/scsi/scsi_dbg.h | 18 + include/sound/asound.h | 8 +- include/sound/core.h | 4 +- include/sound/emu10k1.h | 6 +- include/sound/trident.h | 2 +- init/Kconfig | 80 +- init/main.c | 14 +- ipc/msg.c | 7 +- ipc/sem.c | 7 +- ipc/shm.c | 22 +- ipc/util.c | 13 +- kernel/Makefile | 7 +- kernel/ckrm/Makefile | 14 + kernel/ckrm/ckrm.c | 1009 +++++ kernel/ckrm/ckrm_listenaq.c | 503 +++ kernel/ckrm/ckrm_sockc.c | 554 +++ kernel/ckrm/ckrm_tasks.c | 509 +++ kernel/ckrm/ckrm_tc.c | 785 ++++ kernel/ckrm/ckrmutils.c | 207 ++ kernel/compat.c | 63 +- kernel/exit.c | 22 +- kernel/fork.c | 62 +- kernel/futex.c | 3 +- kernel/kallsyms.c | 2 - kernel/kmod.c | 20 +- kernel/pid.c | 3 +- kernel/printk.c | 5 +- kernel/sched.c | 119 +- kernel/signal.c | 46 +- kernel/sys.c | 118 +- kernel/sysctl.c | 111 +- kernel/timer.c | 11 +- kernel/user.c | 23 +- kernel/vserver/Kconfig | 72 + kernel/vserver/Makefile | 13 + kernel/vserver/context.c | 700 ++++ kernel/vserver/cvirt.c | 43 + kernel/vserver/dlimit.c | 439 +++ kernel/vserver/helper.c | 92 + kernel/vserver/init.c | 41 + kernel/vserver/inode.c | 221 ++ kernel/vserver/legacy.c | 170 + kernel/vserver/limit.c | 151 + kernel/vserver/namespace.c | 194 + kernel/vserver/network.c | 649 ++++ kernel/vserver/proc.c | 868 +++++ kernel/vserver/sched.c | 163 + kernel/vserver/signal.c | 86 + kernel/vserver/switch.c | 181 + kernel/vserver/sysctl.c | 160 + kernel/workqueue.c | 69 +- mm/Makefile | 2 + mm/filemap.c | 19 +- mm/fremap.c | 15 +- mm/memory.c | 124 +- mm/mempolicy.c | 18 +- mm/mlock.c | 20 +- mm/mmap.c | 175 +- mm/mprotect.c | 21 +- mm/mremap.c | 24 +- mm/oom_kill.c | 2 + mm/page-writeback.c | 68 +- mm/page_alloc.c | 23 +- mm/pdflush.c | 4 + mm/proc_mm.c | 174 + mm/rmap.c | 49 +- mm/shmem.c | 67 +- mm/slab.c | 31 +- mm/swap_state.c | 7 +- mm/swapfile.c | 5 +- mm/usercopy.c | 302 ++ mm/vmalloc.c | 22 + mm/vmscan.c | 366 +- net/Kconfig | 2 + net/Makefile | 1 + net/appletalk/ddp.c | 19 +- net/atm/ioctl.c | 10 +- net/ax25/af_ax25.c | 28 +- net/bluetooth/hci_conn.c | 12 +- net/bluetooth/hci_core.c | 22 +- net/bluetooth/hci_sock.c | 13 +- net/bluetooth/l2cap.c | 8 +- net/bluetooth/rfcomm/sock.c | 2 +- net/bluetooth/sco.c | 8 +- net/bluetooth/syms.c | 84 - net/bridge/br_ioctl.c | 18 +- net/bridge/br_private.h | 2 +- net/bridge/br_sysfs_br.c | 21 +- net/bridge/br_sysfs_if.c | 2 +- net/core/dev.c | 55 +- net/core/iovec.c | 2 +- net/core/netfilter.c | 8 + net/core/rtnetlink.c | 4 + net/core/sock.c | 60 +- net/core/stream.c | 41 + net/decnet/af_decnet.c | 10 +- net/decnet/dn_dev.c | 20 +- net/econet/af_econet.c | 23 +- net/ipv4/Kconfig | 23 + net/ipv4/af_inet.c | 59 +- net/ipv4/devinet.c | 33 + net/ipv4/fib_hash.c | 4 +- net/ipv4/ip_output.c | 11 +- net/ipv4/ipcomp.c | 45 +- net/ipv4/ipmr.c | 10 +- net/ipv4/ipvs/ip_vs_ctl.c | 4 +- net/ipv4/netfilter/arp_tables.c | 24 +- net/ipv4/netfilter/ip_conntrack_core.c | 11 +- net/ipv4/netfilter/ip_fw_compat.c | 3 +- net/ipv4/netfilter/ip_tables.c | 22 +- net/ipv4/raw.c | 43 +- net/ipv4/route.c | 16 +- net/ipv4/tcp.c | 268 +- net/ipv4/tcp_input.c | 10 +- net/ipv4/tcp_ipv4.c | 156 +- net/ipv4/tcp_minisocks.c | 21 + net/ipv4/tcp_timer.c | 53 +- net/ipv4/udp.c | 43 +- net/ipv6/ah6.c | 87 +- net/ipv6/exthdrs.c | 10 +- net/ipv6/ip6_input.c | 2 +- net/ipv6/ip6_output.c | 33 +- net/ipv6/ndisc.c | 6 +- net/ipv6/netfilter/ip6_tables.c | 21 +- net/ipv6/raw.c | 6 +- net/ipv6/route.c | 32 +- net/ipv6/tcp_ipv6.c | 55 +- net/ipv6/udp.c | 32 +- net/ipx/af_ipx.c | 29 +- net/irda/af_irda.c | 10 +- net/key/af_key.c | 2 +- net/netrom/af_netrom.c | 13 +- net/packet/af_packet.c | 2 +- net/rose/af_rose.c | 21 +- net/sctp/socket.c | 17 +- net/socket.c | 203 +- net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/auth_gss/svcauth_gss.c | 18 +- net/sunrpc/clnt.c | 9 +- net/tux/Kconfig | 25 + net/tux/Makefile | 12 + net/tux/abuf.c | 186 + net/tux/accept.c | 859 +++++ net/tux/cachemiss.c | 264 ++ net/tux/cgi.c | 173 + net/tux/directory.c | 297 ++ net/tux/extcgi.c | 329 ++ net/tux/gzip.c | 40 + net/tux/input.c | 641 ++++ net/tux/logger.c | 855 +++++ net/tux/main.c | 1413 +++++++ net/tux/mod.c | 262 ++ net/tux/output.c | 352 ++ net/tux/parser.h | 102 + net/tux/postpone.c | 77 + net/tux/proc.c | 1190 ++++++ net/tux/proto_ftp.c | 1549 ++++++++ net/tux/proto_http.c | 2199 +++++++++++ net/tux/redirect.c | 154 + net/tux/times.c | 392 ++ net/tux/times.h | 26 + net/tux/userspace.c | 27 + net/unix/af_unix.c | 14 +- net/wanrouter/af_wanpipe.c | 2 +- net/x25/af_x25.c | 27 +- scripts/checkstack.pl | 29 +- scripts/kconfig/Makefile | 12 +- scripts/kconfig/conf.c | 26 +- scripts/reference_discarded.pl | 2 +- security/commoncap.c | 2 +- security/dummy.c | 2 +- security/selinux/hooks.c | 43 +- security/selinux/nlmsgtab.c | 153 + security/selinux/selinuxfs.c | 25 +- sound/core/control.c | 56 +- sound/core/oss/Makefile | 1 + sound/core/oss/pcm_oss.c | 71 +- sound/core/pcm_native.c | 102 +- sound/core/rawmidi.c | 32 +- sound/core/seq/oss/seq_oss.c | 8 +- sound/core/timer.c | 42 +- sound/isa/sb/emu8000_patch.c | 6 +- sound/isa/sscape.c | 12 +- sound/isa/wavefront/wavefront_synth.c | 31 +- sound/oss/awe_wave.c | 4 +- sound/oss/cmpci.c | 140 +- sound/oss/i810_audio.c | 74 +- sound/oss/msnd.c | 22 +- sound/oss/opl3.c | 8 +- sound/oss/trident.c | 72 +- sound/oss/wavfront.c | 23 +- sound/pci/cs4281.c | 4 +- sound/pci/cs46xx/cs46xx_lib.c | 2 +- sound/pci/emu10k1/emufx.c | 36 +- sound/pci/es1938.c | 4 +- sound/pci/ice1712/prodigy.c | 663 ---- sound/pci/ice1712/prodigy.h | 67 - sound/pci/korg1212/korg1212.c | 10 +- sound/pci/mixart/mixart.c | 4 +- sound/pci/nm256/nm256.c | 2 +- sound/pci/rme32.c | 4 +- sound/pci/rme96.c | 4 +- sound/pci/rme9652/hdsp.c | 83 +- sound/pci/rme9652/rme9652.c | 4 +- 1521 files changed, 102811 insertions(+), 68683 deletions(-) create mode 100644 Documentation/COPYING.modules delete mode 100644 Documentation/arm/SA1100/PCMCIA create mode 100644 Documentation/arm/Sharp-LH/SDRAM create mode 100644 Documentation/arm/VFP/release-notes.txt delete mode 100644 Documentation/arm/XScale/ADIFCC/80200EVB delete mode 100644 Documentation/arm/XScale/IOP3XX/IQ80310 delete mode 100644 Documentation/arm/XScale/IOP3XX/IQ80321 delete mode 100644 Documentation/arm/XScale/IOP3XX/aau.txt delete mode 100644 Documentation/arm/XScale/IOP3XX/dma.txt delete mode 100644 Documentation/arm/XScale/IOP3XX/message.txt delete mode 100644 Documentation/arm/XScale/IOP3XX/pmon.txt delete mode 100644 Documentation/arm/XScale/cache-lock.txt delete mode 100644 Documentation/arm/XScale/pmu.txt delete mode 100644 Documentation/arm/XScale/tlb-lock.txt create mode 100644 Documentation/device-mapper/dm-io.txt create mode 100644 Documentation/device-mapper/kcopyd.txt create mode 100644 Documentation/device-mapper/linear.txt create mode 100644 Documentation/device-mapper/striped.txt create mode 100644 Documentation/device-mapper/zero.txt create mode 100644 Documentation/fb/sisfb.txt create mode 100644 Documentation/filesystems/relayfs.txt create mode 100644 Documentation/hpet.txt create mode 100644 arch/arm/mach-integrator/clock.c create mode 100644 arch/arm/mach-integrator/clock.h delete mode 100644 arch/arm/mach-omap/innovator1510.c delete mode 100644 arch/arm/mach-omap/innovator1610.c delete mode 100644 arch/arm/mach-omap/irq.h delete mode 100644 arch/arm/mach-omap/omap-generic.c delete mode 100644 arch/arm/mach-omap/omap-perseus2.c create mode 100644 arch/arm/mach-versatile/clock.c create mode 100644 arch/arm/mach-versatile/clock.h create mode 100644 arch/arm/vfp/Makefile create mode 100644 arch/arm/vfp/entry.S create mode 100644 arch/arm/vfp/vfp.h create mode 100644 arch/arm/vfp/vfpdouble.c create mode 100644 arch/arm/vfp/vfphw.S create mode 100644 arch/arm/vfp/vfpinstr.h create mode 100644 arch/arm/vfp/vfpmodule.c create mode 100644 arch/arm/vfp/vfpsingle.c delete mode 100644 arch/cris/kernel/hexify.c delete mode 100644 arch/cris/kernel/ksyms.c create mode 100644 arch/i386/kernel/entry_trampoline.c create mode 100644 arch/i386/lib/bitops.c delete mode 100644 arch/i386/mach-es7000/es7000.c delete mode 100644 arch/i386/mach-es7000/setup.c delete mode 100644 arch/i386/mach-es7000/topology.c delete mode 100644 arch/ia64/kernel/perfmon_hpsim.h create mode 100644 arch/ppc/kernel/head_e500.S delete mode 100644 arch/ppc/mm/cachemap.c create mode 100644 arch/ppc/mm/fsl_booke_mmu.c delete mode 100644 arch/ppc/ocp/Makefile delete mode 100644 arch/ppc/ocp/ocp-driver.c delete mode 100644 arch/ppc/ocp/ocp-probe.c delete mode 100644 arch/ppc/ocp/ocp.c create mode 100644 arch/ppc/platforms/85xx/Kconfig create mode 100644 arch/ppc/platforms/85xx/Makefile create mode 100644 arch/ppc/platforms/85xx/mpc8540.c create mode 100644 arch/ppc/platforms/85xx/mpc8540_ads.c create mode 100644 arch/ppc/platforms/85xx/mpc8540_ads.h create mode 100644 arch/ppc/platforms/85xx/mpc85xx_ads_common.c create mode 100644 arch/ppc/platforms/85xx/mpc85xx_ads_common.h create mode 100644 arch/ppc/syslib/ppc85xx_common.c create mode 100644 arch/ppc/syslib/ppc85xx_common.h create mode 100644 arch/ppc/syslib/ppc85xx_setup.c create mode 100644 arch/ppc/syslib/ppc85xx_setup.h create mode 100644 arch/um/drivers/cow_kern.c create mode 100644 arch/um/drivers/cow_sys.h create mode 100644 arch/um/drivers/net_kern.c.orig create mode 100644 arch/um/kernel/smp.c.orig delete mode 100644 arch/um/kernel/user_syms.c delete mode 100644 arch/um/sys-i386/extable.c create mode 100644 arch/um/sys-i386/time.c delete mode 100644 arch/x86_64/kernel/Makefile-HEAD create mode 100644 configs/kernel-2.6.6-1.422-vs1.9.1-ckrm-E13 create mode 100644 configs/kernel-2.6.6-i586-smp.config create mode 100644 configs/kernel-2.6.6-i586.config create mode 100644 configs/kernel-2.6.6-i686-planetlab.config create mode 100644 configs/kernel-2.6.6-i686-smp.config create mode 100644 configs/kernel-2.6.6-i686.config create mode 100644 configs/kernel-2.6.7-i586-smp.config create mode 100644 configs/kernel-2.6.7-i586.config create mode 100644 configs/kernel-2.6.7-i686-smp.config create mode 100644 configs/kernel-2.6.7-i686.config create mode 100644 drivers/char/crash.c delete mode 100644 drivers/char/dz.c delete mode 100644 drivers/char/dz.h create mode 100644 drivers/char/hpet.c delete mode 100644 drivers/char/sh-sci.c delete mode 100644 drivers/char/sh-sci.h delete mode 100644 drivers/i2c/busses/i2c-ixp42x.c delete mode 100644 drivers/ide/pci/amd74xx.h delete mode 100644 drivers/ide/pci/cmd640.h delete mode 100644 drivers/ide/ppc/swarm.c create mode 100644 drivers/md/dm-exception-store.c create mode 100644 drivers/md/dm-io.c create mode 100644 drivers/md/dm-io.h create mode 100644 drivers/md/dm-log.c create mode 100644 drivers/md/dm-log.h create mode 100644 drivers/md/dm-raid1.c create mode 100644 drivers/md/dm-snap.c create mode 100644 drivers/md/dm-snap.h create mode 100644 drivers/md/dm-zero.c create mode 100644 drivers/md/kcopyd.c create mode 100644 drivers/md/kcopyd.h create mode 100644 drivers/net/arm/smc91x.c create mode 100644 drivers/net/arm/smc91x.h delete mode 100644 drivers/net/auto_irq.c delete mode 100644 drivers/net/rcif.h delete mode 100644 drivers/net/rclanmtl.c delete mode 100644 drivers/net/rclanmtl.h delete mode 100644 drivers/net/rcpci45.c create mode 100644 drivers/net/via-velocity.c create mode 100644 drivers/net/via-velocity.h delete mode 100644 drivers/net/wan/comx-hw-comx.c delete mode 100644 drivers/net/wan/comx-hw-locomx.c delete mode 100644 drivers/net/wan/comx-hw-mixcom.c delete mode 100644 drivers/net/wan/comx-hw-munich.c delete mode 100644 drivers/net/wan/comx-proto-fr.c delete mode 100644 drivers/net/wan/comx-proto-lapb.c delete mode 100644 drivers/net/wan/comx-proto-ppp.c delete mode 100644 drivers/net/wan/comx.c delete mode 100644 drivers/net/wan/comx.h delete mode 100644 drivers/net/wan/comxhw.h delete mode 100644 drivers/net/wan/falc-lh.h delete mode 100644 drivers/net/wan/hscx.h delete mode 100644 drivers/net/wan/mixcom.h delete mode 100644 drivers/net/wan/munich32x.h delete mode 100644 drivers/net/wan/wanxlfw.inc create mode 100644 drivers/net/wireless/prism54/prismcompat.h delete mode 100644 drivers/pcmcia/sa1100.h delete mode 100644 drivers/pcmcia/sa11xx_core.c delete mode 100644 drivers/pcmcia/sa11xx_core.h create mode 100644 drivers/scsi/3w-9xxx.c create mode 100644 drivers/scsi/3w-9xxx.h delete mode 100644 drivers/scsi/pcmcia/qlogic_core.c delete mode 100644 drivers/scsi/qlogicfas.h create mode 100644 drivers/usb/class/cdc-acm.h delete mode 100644 drivers/usb/core/driverfs.c create mode 100644 drivers/usb/host/ohci-lh7a404.c create mode 100644 drivers/video/riva/rivafb-i2c.c create mode 100644 fs/Makefile.orig delete mode 100644 fs/intermezzo/Makefile delete mode 100644 fs/intermezzo/cache.c delete mode 100644 fs/intermezzo/dcache.c delete mode 100644 fs/intermezzo/dir.c delete mode 100644 fs/intermezzo/ext_attr.c delete mode 100644 fs/intermezzo/file.c delete mode 100644 fs/intermezzo/fileset.c delete mode 100644 fs/intermezzo/inode.c delete mode 100644 fs/intermezzo/intermezzo_fs.h delete mode 100644 fs/intermezzo/intermezzo_idl.h delete mode 100644 fs/intermezzo/intermezzo_journal.h delete mode 100644 fs/intermezzo/intermezzo_kml.h delete mode 100644 fs/intermezzo/intermezzo_lib.h delete mode 100644 fs/intermezzo/intermezzo_psdev.h delete mode 100644 fs/intermezzo/intermezzo_upcall.h delete mode 100644 fs/intermezzo/journal.c delete mode 100644 fs/intermezzo/journal_ext2.c delete mode 100644 fs/intermezzo/journal_ext3.c delete mode 100644 fs/intermezzo/journal_obdfs.c delete mode 100644 fs/intermezzo/journal_reiserfs.c delete mode 100644 fs/intermezzo/journal_tmpfs.c delete mode 100644 fs/intermezzo/journal_xfs.c delete mode 100644 fs/intermezzo/kml.c delete mode 100644 fs/intermezzo/kml_decode.c delete mode 100644 fs/intermezzo/kml_reint.c delete mode 100644 fs/intermezzo/kml_setup.c delete mode 100644 fs/intermezzo/kml_unpack.c delete mode 100644 fs/intermezzo/kml_utils.c delete mode 100644 fs/intermezzo/methods.c delete mode 100644 fs/intermezzo/presto.c delete mode 100644 fs/intermezzo/psdev.c delete mode 100644 fs/intermezzo/replicator.c delete mode 100644 fs/intermezzo/super.c delete mode 100644 fs/intermezzo/sysctl.c delete mode 100644 fs/intermezzo/upcall.c delete mode 100644 fs/intermezzo/vfs.c create mode 100644 fs/isofs/export.c create mode 100644 fs/rcfs/Makefile create mode 100644 fs/rcfs/dir.c create mode 100644 fs/rcfs/inode.c create mode 100644 fs/rcfs/magic.c create mode 100644 fs/rcfs/rootdir.c create mode 100644 fs/rcfs/socket_fs.c create mode 100644 fs/rcfs/super.c create mode 100644 fs/rcfs/tc_magic.c create mode 100644 fs/relayfs/Makefile create mode 100644 fs/relayfs/inode.c create mode 100644 fs/relayfs/klog.c create mode 100644 fs/relayfs/relay.c create mode 100644 fs/relayfs/relay_locking.c create mode 100644 fs/relayfs/relay_locking.h create mode 100644 fs/relayfs/relay_lockless.c create mode 100644 fs/relayfs/relay_lockless.h create mode 100644 fs/relayfs/resize.c create mode 100644 fs/relayfs/resize.h delete mode 100644 fs/xfs/linux/kmem.h delete mode 100644 fs/xfs/linux/mrlock.h delete mode 100644 fs/xfs/linux/mutex.h delete mode 100644 fs/xfs/linux/sema.h delete mode 100644 fs/xfs/linux/spin.h delete mode 100644 fs/xfs/linux/sv.h delete mode 100644 fs/xfs/linux/time.h delete mode 100644 fs/xfs/linux/xfs_aops.c delete mode 100644 fs/xfs/linux/xfs_buf.c delete mode 100644 fs/xfs/linux/xfs_buf.h delete mode 100644 fs/xfs/linux/xfs_cred.h delete mode 100644 fs/xfs/linux/xfs_file.c delete mode 100644 fs/xfs/linux/xfs_fs_subr.c delete mode 100644 fs/xfs/linux/xfs_fs_subr.h delete mode 100644 fs/xfs/linux/xfs_globals.c delete mode 100644 fs/xfs/linux/xfs_globals.h delete mode 100644 fs/xfs/linux/xfs_ioctl.c delete mode 100644 fs/xfs/linux/xfs_iops.c delete mode 100644 fs/xfs/linux/xfs_iops.h delete mode 100644 fs/xfs/linux/xfs_linux.h delete mode 100644 fs/xfs/linux/xfs_lrw.c delete mode 100644 fs/xfs/linux/xfs_lrw.h delete mode 100644 fs/xfs/linux/xfs_stats.c delete mode 100644 fs/xfs/linux/xfs_stats.h delete mode 100644 fs/xfs/linux/xfs_super.c delete mode 100644 fs/xfs/linux/xfs_super.h delete mode 100644 fs/xfs/linux/xfs_sysctl.c delete mode 100644 fs/xfs/linux/xfs_sysctl.h delete mode 100644 fs/xfs/linux/xfs_version.h delete mode 100644 fs/xfs/linux/xfs_vfs.c delete mode 100644 fs/xfs/linux/xfs_vfs.h delete mode 100644 fs/xfs/linux/xfs_vnode.c delete mode 100644 fs/xfs/linux/xfs_vnode.h create mode 100644 include/asm-alpha/relay.h delete mode 100644 include/asm-alpha/rmap.h delete mode 100644 include/asm-arm/arch-cl7500/ide.h delete mode 100644 include/asm-arm/arch-cl7500/keyboard.h delete mode 100644 include/asm-arm/arch-clps711x/keyboard.h delete mode 100644 include/asm-arm/arch-ebsa110/ide.h delete mode 100644 include/asm-arm/arch-ebsa285/ide.h delete mode 100644 include/asm-arm/arch-iop3xx/ide.h delete mode 100644 include/asm-arm/arch-l7200/ide.h delete mode 100644 include/asm-arm/arch-l7200/keyboard.h delete mode 100644 include/asm-arm/arch-nexuspci/ide.h delete mode 100644 include/asm-arm/arch-pxa/ide.h delete mode 100644 include/asm-arm/arch-pxa/keyboard.h delete mode 100644 include/asm-arm/arch-rpc/ide.h delete mode 100644 include/asm-arm/arch-s3c2410/ide.h delete mode 100644 include/asm-arm/arch-sa1100/keyboard.h delete mode 100644 include/asm-arm/arch-shark/ide.h delete mode 100644 include/asm-arm/arch-shark/keyboard.h delete mode 100644 include/asm-arm/arch-tbox/ide.h create mode 100644 include/asm-arm/hardware/clock.h create mode 100644 include/asm-arm/relay.h delete mode 100644 include/asm-arm/rmap.h create mode 100644 include/asm-arm/vfp.h create mode 100644 include/asm-arm/vfpmacros.h create mode 100644 include/asm-arm26/relay.h delete mode 100644 include/asm-arm26/rmap.h create mode 100644 include/asm-cris/relay.h delete mode 100644 include/asm-cris/rmap.h create mode 100644 include/asm-generic/relay.h delete mode 100644 include/asm-generic/rmap.h delete mode 100644 include/asm-h8300/aki3068net/machine-depend.h delete mode 100644 include/asm-h8300/edosk2674/machine-depend.h delete mode 100644 include/asm-h8300/generic/machine-depend.h delete mode 100644 include/asm-h8300/generic/timer_rate.h delete mode 100644 include/asm-h8300/h8300_smsc.h delete mode 100644 include/asm-h8300/h8max/machine-depend.h create mode 100644 include/asm-h8300/relay.h create mode 100644 include/asm-i386/atomic_kmap.h create mode 100644 include/asm-i386/crash.h create mode 100644 include/asm-i386/relay.h delete mode 100644 include/asm-i386/rmap.h create mode 100644 include/asm-ia64/crash.h create mode 100644 include/asm-ia64/relay.h delete mode 100644 include/asm-ia64/rmap.h create mode 100644 include/asm-m68k/relay.h delete mode 100644 include/asm-m68k/rmap.h create mode 100644 include/asm-m68knommu/relay.h delete mode 100644 include/asm-m68knommu/rmap.h create mode 100644 include/asm-mips/relay.h delete mode 100644 include/asm-mips/rmap.h create mode 100644 include/asm-mips64/relay.h create mode 100644 include/asm-parisc/relay.h delete mode 100644 include/asm-parisc/rmap.h create mode 100644 include/asm-ppc/fsl_ocp.h create mode 100644 include/asm-ppc/immap_85xx.h create mode 100644 include/asm-ppc/mpc85xx.h create mode 100644 include/asm-ppc/relay.h delete mode 100644 include/asm-ppc/rmap.h create mode 100644 include/asm-ppc64/relay.h delete mode 100644 include/asm-ppc64/rmap.h create mode 100644 include/asm-s390/relay.h delete mode 100644 include/asm-s390/rmap.h create mode 100644 include/asm-sh/relay.h delete mode 100644 include/asm-sh/rmap.h create mode 100644 include/asm-sparc/relay.h delete mode 100644 include/asm-sparc/rmap.h create mode 100644 include/asm-sparc64/relay.h delete mode 100644 include/asm-sparc64/rmap.h create mode 100644 include/asm-um/module-i386.h delete mode 100644 include/asm-um/rmap.h delete mode 100644 include/asm-um/smplock.h delete mode 100644 include/asm-um/spinlock.h create mode 100644 include/asm-v850/relay.h delete mode 100644 include/asm-v850/rmap.h create mode 100644 include/asm-x86_64/relay.h delete mode 100644 include/asm-x86_64/rmap.h create mode 100644 include/linux/ckrm.h create mode 100644 include/linux/ckrm_ce.h create mode 100644 include/linux/ckrm_net.h create mode 100644 include/linux/ckrm_rc.h create mode 100644 include/linux/ckrm_tc.h create mode 100644 include/linux/ckrm_tsk.h create mode 100644 include/linux/ghash.h create mode 100644 include/linux/hpet.h create mode 100644 include/linux/klog.h create mode 100644 include/linux/ninline.h create mode 100644 include/linux/proc_mm.h create mode 100644 include/linux/rcfs.h create mode 100644 include/linux/relayfs_fs.h create mode 100644 include/linux/taskdelays.h create mode 100644 include/linux/vinline.h create mode 100644 include/linux/vs_base.h create mode 100644 include/linux/vs_context.h create mode 100644 include/linux/vs_cvirt.h create mode 100644 include/linux/vs_dlimit.h create mode 100644 include/linux/vs_limit.h create mode 100644 include/linux/vs_memory.h create mode 100644 include/linux/vs_network.h create mode 100644 include/linux/vs_socket.h create mode 100644 include/linux/vserver.h create mode 100644 include/linux/vserver/context.h create mode 100644 include/linux/vserver/cvirt.h create mode 100644 include/linux/vserver/dlimit.h create mode 100644 include/linux/vserver/inode.h create mode 100644 include/linux/vserver/legacy.h create mode 100644 include/linux/vserver/limit.h create mode 100644 include/linux/vserver/namespace.h create mode 100644 include/linux/vserver/network.h create mode 100644 include/linux/vserver/sched.h create mode 100644 include/linux/vserver/signal.h create mode 100644 include/linux/vserver/switch.h create mode 100644 include/linux/vserver/xid.h create mode 100644 include/net/tux.h create mode 100644 include/net/tux_u.h create mode 100644 include/scsi/scsi_dbg.h create mode 100644 kernel/ckrm/Makefile create mode 100644 kernel/ckrm/ckrm.c create mode 100644 kernel/ckrm/ckrm_listenaq.c create mode 100644 kernel/ckrm/ckrm_sockc.c create mode 100644 kernel/ckrm/ckrm_tasks.c create mode 100644 kernel/ckrm/ckrm_tc.c create mode 100644 kernel/ckrm/ckrmutils.c create mode 100644 kernel/vserver/Kconfig create mode 100644 kernel/vserver/Makefile create mode 100644 kernel/vserver/context.c create mode 100644 kernel/vserver/cvirt.c create mode 100644 kernel/vserver/dlimit.c create mode 100644 kernel/vserver/helper.c create mode 100644 kernel/vserver/init.c create mode 100644 kernel/vserver/inode.c create mode 100644 kernel/vserver/legacy.c create mode 100644 kernel/vserver/limit.c create mode 100644 kernel/vserver/namespace.c create mode 100644 kernel/vserver/network.c create mode 100644 kernel/vserver/proc.c create mode 100644 kernel/vserver/sched.c create mode 100644 kernel/vserver/signal.c create mode 100644 kernel/vserver/switch.c create mode 100644 kernel/vserver/sysctl.c create mode 100644 mm/proc_mm.c create mode 100644 mm/usercopy.c delete mode 100644 net/bluetooth/syms.c create mode 100644 net/core/stream.c create mode 100644 net/tux/Kconfig create mode 100644 net/tux/Makefile create mode 100644 net/tux/abuf.c create mode 100644 net/tux/accept.c create mode 100644 net/tux/cachemiss.c create mode 100644 net/tux/cgi.c create mode 100644 net/tux/directory.c create mode 100644 net/tux/extcgi.c create mode 100644 net/tux/gzip.c create mode 100644 net/tux/input.c create mode 100644 net/tux/logger.c create mode 100644 net/tux/main.c create mode 100644 net/tux/mod.c create mode 100644 net/tux/output.c create mode 100644 net/tux/parser.h create mode 100644 net/tux/postpone.c create mode 100644 net/tux/proc.c create mode 100644 net/tux/proto_ftp.c create mode 100644 net/tux/proto_http.c create mode 100644 net/tux/redirect.c create mode 100644 net/tux/times.c create mode 100644 net/tux/times.h create mode 100644 net/tux/userspace.c create mode 100644 security/selinux/nlmsgtab.c delete mode 100644 sound/pci/ice1712/prodigy.c delete mode 100644 sound/pci/ice1712/prodigy.h diff --git a/Documentation/COPYING.modules b/Documentation/COPYING.modules new file mode 100644 index 000000000..da0266e78 --- /dev/null +++ b/Documentation/COPYING.modules @@ -0,0 +1,708 @@ +Date: Thu, 29 Apr 2004 14:10:41 -0700 (PDT) +From: Linus Torvalds +To: Giuliano Colla +cc: Linux Kernel Mailing List +Subject: Re: [hsflinux] [PATCH] Blacklist binary-only modules lying about + their license +Message-ID: + +On Thu, 29 Apr 2004, Giuliano Colla wrote: +> +> Let's try not to be ridiculous, please. + +It's not abotu being ridiculous. It's about honoring peoples copyrights. + +> As an end user, if I buy a full fledged modem, I get some amount of +> proprietary, non GPL, code which executes within the board or the +> PCMCIA card of the modem. The GPL driver may even support the +> functionality of downloading a new version of *proprietary* code into +> the flash Eprom of the device. The GPL linux driver interfaces with it, +> and all is kosher. + +Indeed. Everything is kosher, because the other piece of hardware and +software has _nothing_ to do with the kernel. It's not linked into it, it +cannot reasonably corrupt internal kernel data structures with random +pointer bugs, and in general you can think of firmware as part of the +_hardware_, not the software of the machine. + +> On the other hand, I have the misfortune of being stuck with a +> soft-modem, roughly the *same* proprietary code is provided as a binary +> file, and a linux driver (source provided) interfaces with it. In that +> case the kernel is flagged as "tainted". + +It is flagged as tainted, because your argument that it is "the same code" +is totally BOGUS AND UNTRUE! + +In the binary kernel module case, a bug in the code corrupts random data +structures, or accesses kernel internals without holding the proper locks, +or does a million other things wrong, BECAUSE A KERNEL MODULE IS VERY +INTIMATELY LINKED WITH THE KERNEL. + +A kernel module is _not_ a separate work, and can in _no_ way be seen as +"part of the hardware". It's very much a part of the _kernel_. And the +kernel developers require that such code be GPL'd so that it can be fixed, +or if there's a valid argument that it's not a derived work and not GPL'd, +then the kernel developers who have to support the end result mess most +definitely do need to know about the taint. + +You are not the first (and sadly, you likely won't be the last) person to +equate binary kernel modules with binary firmware. And I tell you that +such a comparison is ABSOLUTE CRAPOLA. There's a damn big difference +between running firmware on another chip behind a PCI bus, and linking +into the kernel directly. + +And if you don't see that difference, then you are either terminally +stupid, or you have some ulterior reason to claim that they are the same +case even though they clearly are NOT. + +> Can you honestly tell apart the two cases, if you don't make a it a case +> of "religion war"? + +It has absolutely nothing to do with religion. + + Linus + +Date: Fri, 5 Dec 2003 09:19:52 -0800 (PST) +From: Linus Torvalds +To: Peter Chubb +cc: linux-kernel@vger.kernel.org +Subject: Re: Linux GPL and binary module exception clause? +Message-ID: + +On Fri, 5 Dec 2003, Peter Chubb wrote: +> +> As I understand it, SCO is/was claiming that JFS and XFS are derived +> works of the UNIX source base, because they were developed to match +> the internal interfaces of UNIX, and with knowledge of the internals +> of UNIX -- and they hold the copyrights of and are the licensor of UNIX. + +Yes, and I'm not claiming anything like that. + +I claim that a "binary linux kernel module" is a derived work of the +kernel, and thus has to come with sources. + +But if you use those same sources (and _you_ wrote them) they do not +contain any Linux code, they are _clearly_ not derived from Linux, and you +can license and use your own code any way you want. + +You just can't make a binary module for Linux, and claim that that module +isn't derived from the kernel. Because it generally is - the binary +module not only included header files, but more importantly it clearly is +_not_ a standalone work any more. So even if you made your own prototypes +and tried hard to avoid kernel headers, it would _still_ be connected and +dependent on the kernel. + +And note that I'm very much talking about just the _binary_. Your source +code is still very much yours, and you have the right to distribute it +separately any which way you want. You wrote it, you own the copyrights to +it, and it is an independent work. + +But when you distribute it in a way that is CLEARLY tied to the GPL'd +kernel (and a binary module is just one such clear tie - a "patch" to +build it or otherwise tie it to the kernel is also such a tie, even if you +distribute it as source under some other license), you're BY DEFINITION +not an independent work any more. + +(But exactly because I'm not a black-and-white person, I reserve the right +to make a balanced decision on any particular case. I have several times +felt that the module author had a perfectly valid argument for why the +"default assumption" of being derived wasn't the case. That's why things +like the AFS module were accepted - but not liked - in the first place). + +This is why SCO's arguments are specious. IBM wrote their code, retained +their copyrights to their code AND THEY SEVERED THE CONNECTION TO SCO'S +CODE (and, arguably the connections didn't even exist in the first place, +since apparently things like JFS were written for OS/2 as well, and the +Linux port was based on that one - but that's a separate argument and +independent of my point). + +See the definition of "derivative" in USC 17.1.101: + + A "derivative work" is a work based upon one or more preexisting + works, such as a translation, musical arrangement, dramatization, + fictionalization, motion picture version, sound recording, art + reproduction, abridgment, condensation, or any other form in which + a work may be recast, transformed, or adapted. A work consisting + of editorial revisions, annotations, elaborations, or other + modifications which, as a whole, represent an original work of + authorship, is a "derivative work". + +And a binary module is an "elaboration" on the kernel. Sorry, but that is +how it IS. + +In short: your code is yours. The code you write is automatically +copyrighted by YOU, and as such you have the right to license and use it +any way you want (well, modulo _other_ laws, of course - in the US your +license can't be racist, for example, but that has nothing to do with +copyright laws, and would fall under a totally different legal framework). + +But when you use that code to create an "elaboration" to the kernel, that +makes it a derived work, and you cannot distribute it except as laid out +by the GPL. A binary module is one such case, but even just a source patch +is _also_ one such case. The lines you added are yours, but when you +distribute it as an elaboration, you are bound by the restriction on +derivative works. + +Or you had better have some other strong argument why it isn't. Which has +been my point all along. + + Linus + + +Date: Wed, 10 Dec 2003 09:10:18 -0800 (PST) +From: Linus Torvalds +To: Larry McVoy +Subject: Re: Linux GPL and binary module exception clause? + +On Wed, 10 Dec 2003, Larry McVoy wrote: +> +> Which is? How is it that you can spend a page of text saying a judge doesn't +> care about technicalities and then base the rest of your argument on the +> distinction between a "plugin" and a "kernel module"? + +I'll stop arguing, since you obviously do not get it. + +I explained the technicalities to _you_, and you are a technical person. + +But if you want to explain something to a judge, you get a real lawyer, +and you make sure that the lawyer tries to explain the issue in _non_ +technical terms. Because, quite frankly, the judge is not going to buy a +technical discussion he or she doesn't understand. + +Just as an example, how do you explain to a judge how much code the Linux +kernel contains? Do you say "it's 6 million lines of C code and header +files and documentation, for a total of about 175MB of data"? + +Yeah, maybe you'd _mention_ that, but to actually _illustrate_ the point +you'd say that if you printed it out, it would be a solid stack of papers +100 feet high. And you'd compare it to the height of the court building +you're in, or something. Maybe you'd print out _one_ file, bind it as a +book, and wave it around as one out of 15,000 files. + +But when _you_ ask me about how big the kernel is, I'd say "5 million +lines". See the difference? It would be silly for me to tell you how many +feet of paper the kernel would print out to, because we don't have those +kinds of associations. + +Similarly, if you want to explain the notion of a kernel module, you'd +compare it to maybe an extra chapter in a book. You'd make an analogy to +something that never _ever_ mentions "linking". + +Just imagine: distributing a compiled binary-only kernel module that can +be loaded into the kernel is not like distributing a new book: it's more +like distributing a extra chapter to a book that somebody else wrote, that +uses all the same characters and the plot, but more importantly it +literally can only be read _together_ with the original work. It doesn't +stand alone. + +In short, your honour, this extra chapter without any meaning on its own +is a derived work of the book. + +In contrast, maybe you can re-write your code and distribute it as a +short-story, which can be run on its own, and maybe the author has been +influenced by another book, but the short-story could be bound AS IS, and +a recipient would find it useful even without that other book. In that +case, the short story is not a derived work - it's only inspired. + +Notice? This is actually _exactly_ what I've been arguing all along, +except I've been arguing with a technical audience, so I've been using +technical examples and terminology. But my argument is that just the fact +that somebody compiled the code for Linux into a binary module that is +useless without a particular version of the kernel DOES MAKE IT A DERIVED +WORK. + +But also note how it's only the BINARY MODULE that is a derived work. Your +source code is _not_ necessarily a derived work, and if you compile it for +another operating system, I'd clearly not complain. + +This is the "stand-alone short story" vs "extra chapter without meaning +outside the book" argument. See? One is a work in its own right, the other +isn't. + + Linus + + +Please read the FAQ at http://www.tux.org/lkml/ +Date: Thu, 4 Dec 2003 22:43:42 -0800 (PST) +From: Linus Torvalds +To: David Schwartz +cc: linux-kernel@vger.kernel.org +Subject: RE: Linux GPL and binary module exception clause? + +On Thu, 4 Dec 2003, David Schwartz wrote: +> +> Yes, but they will cite the prohibition against *creating* derived +> works. + +So? + +The same prohibition exists with the GPL. You are not allowed to create +and distribute a derived work unless it is GPL'd. + +I don't see what you are arguing against. It is very clear: a kernel +module is a derived work of the kernel by default. End of story. + +You can then try to prove (through development history etc) that there +would be major reasons why it's not really derived. But your argument +seems to be that _nothing_ is derived, which is clearly totally false, as +you yourself admit when you replace "kernel" with "Harry Potter". + + Linus + +Date: Wed, 3 Dec 2003 16:00:21 -0800 (PST) +From: Linus Torvalds +To: Kendall Bennet +cc: linux-kernel@vger.kernel.org +Subject: Re: Linux GPL and binary module exception clause? + +On Wed, 3 Dec 2003, Kendall Bennett wrote: +> +> I have heard many people reference the fact that the although the Linux +> Kernel is under the GNU GPL license, that the code is licensed with an +> exception clause that says binary loadable modules do not have to be +> under the GPL. + +Nope. No such exception exists. + +There's a clarification that user-space programs that use the standard +system call interfaces aren't considered derived works, but even that +isn't an "exception" - it's just a statement of a border of what is +clearly considered a "derived work". User programs are _clearly_ not +derived works of the kernel, and as such whatever the kernel license is +just doesn't matter. + +And in fact, when it comes to modules, the GPL issue is exactly the same. +The kernel _is_ GPL. No ifs, buts and maybe's about it. As a result, +anything that is a derived work has to be GPL'd. It's that simple. + +Now, the "derived work" issue in copyright law is the only thing that +leads to any gray areas. There are areas that are not gray at all: user +space is clearly not a derived work, while kernel patches clearly _are_ +derived works. + +But one gray area in particular is something like a driver that was +originally written for another operating system (ie clearly not a derived +work of Linux in origin). At exactly what point does it become a derived +work of the kernel (and thus fall under the GPL)? + +THAT is a gray area, and _that_ is the area where I personally believe +that some modules may be considered to not be derived works simply because +they weren't designed for Linux and don't depend on any special Linux +behaviour. + +Basically: + - anything that was written with Linux in mind (whether it then _also_ + works on other operating systems or not) is clearly partially a derived + work. + - anything that has knowledge of and plays with fundamental internal + Linux behaviour is clearly a derived work. If you need to muck around + with core code, you're derived, no question about it. + +Historically, there's been things like the original Andrew filesystem +module: a standard filesystem that really wasn't written for Linux in the +first place, and just implements a UNIX filesystem. Is that derived just +because it got ported to Linux that had a reasonably similar VFS interface +to what other UNIXes did? Personally, I didn't feel that I could make that +judgment call. Maybe it was, maybe it wasn't, but it clearly is a gray +area. + +Personally, I think that case wasn't a derived work, and I was willing to +tell the AFS guys so. + +Does that mean that any kernel module is automatically not a derived work? +HELL NO! It has nothing to do with modules per se, except that non-modules +clearly are derived works (if they are so central to the kenrel that you +can't load them as a module, they are clearly derived works just by virtue +of being very intimate - and because the GPL expressly mentions linking). + +So being a module is not a sign of not being a derived work. It's just +one sign that _maybe_ it might have other arguments for why it isn't +derived. + + Linus + + +Date: Wed, 3 Dec 2003 16:23:33 -0800 (PST) +From: Linus Torvalds +To: Kendall Bennett +cc: linux-kernel@vger.kernel.org +Subject: Re: Linux GPL and binary module exception clause? + + +On Wed, 3 Dec 2003, Linus Torvalds wrote: +> +> So being a module is not a sign of not being a derived work. It's just +> one sign that _maybe_ it might have other arguments for why it isn't +> derived. + +Side note: historically, the Linux kernel module interfaces were really +quite weak, and only exported a few tens of entry-points, and really +mostly effectively only allowed character and block device drivers with +standard interfaces, and loadable filesystems. + +So historically, the fact that you could load a module using nothing but +these standard interfaces tended to be a much stronger argument for not +being very tightly coupled with the kernel. + +That has changed, and the kernel module interfaces we have today are MUCH +more extensive than they were back in '95 or so. These days modules are +used for pretty much everything, including stuff that is very much +"internal kernel" stuff and as a result the kind of historic "implied +barrier" part of modules really has weakened, and as a result there is not +avery strong argument for being an independent work from just the fact +that you're a module. + +Similarly, historically there was a much stronger argument for things like +AFS and some of the binary drivers (long forgotten now) for having been +developed totally independently of Linux: they literally were developed +before Linux even existed, by people who had zero knowledge of Linux. That +tends to strengthen the argument that they clearly aren't derived. + +In contrast, these days it would be hard to argue that a new driver or +filesystem was developed without any thought of Linux. I think the NVidia +people can probably reasonably honestly say that the code they ported had +_no_ Linux origin. But quite frankly, I'd be less inclined to believe that +for some other projects out there.. + + Linus + + + + +Date: Thu, 17 Oct 2002 10:08:19 -0700 (PDT) +From: Linus Torvalds +To: Christoph Hellwig +Cc: +Subject: Re: [PATCH] make LSM register functions GPLonly exports +In-Reply-To: <20021017175403.A32516@infradead.org> +Message-ID: + +Note that if this fight ends up being a major issue, I'm just going to +remove LSM and let the security vendors do their own thing. So far + + - I have not seen a lot of actual usage of the hooks + - seen a number of people who still worry that the hooks degrade + performance in critical areas + - the worry that people use it for non-GPL'd modules is apparently real, + considering Crispin's reply. + +I will re-iterate my stance on the GPL and kernel modules: + + There is NOTHING in the kernel license that allows modules to be + non-GPL'd. + + The _only_ thing that allows for non-GPL modules is copyright law, and + in particular the "derived work" issue. A vendor who distributes non-GPL + modules is _not_ protected by the module interface per se, and should + feel very confident that they can show in a court of law that the code + is not derived. + + The module interface has NEVER been documented or meant to be a GPL + barrier. The COPYING clearly states that the system call layer is such a + barrier, so if you do your work in user land you're not in any way + beholden to the GPL. The module interfaces are not system calls: there + are system calls used to _install_ them, but the actual interfaces are + not. + + The original binary-only modules were for things that were pre-existing + works of code, ie drivers and filesystems ported from other operating + systems, which thus could clearly be argued to not be derived works, and + the original limited export table also acted somewhat as a barrier to + show a level of distance. + +In short, Crispin: I'm going to apply the patch, and if you as a copyright +holder of that file disagree, I will simply remove all of he LSM code from +the kernel. I think it's very clear that a LSM module is a derived work, +and thus copyright law and the GPL are not in any way unclear about it. + +If people think they can avoid the GPL by using function pointers, they +are WRONG. And they have always been wrong. + + Linus + +------------------------------------------------------------------------ +Date: Fri, 19 Oct 2001 13:16:45 -0700 (PDT) +From: Linus Torvalds +To: Barnes +Subject: Re: GPL, Richard Stallman, and the Linux kernel + +[ This is not, of course, a legal document, but if you want to forward it + to anybody else, feel free to do so. And if you want to argue legal + points with me or point somehting out, I'm always interested. To a + point ;-] + +On Fri, 19 Oct 2001, Barnes wrote: +> +> I've been exchanging e-mail with Richard Stallman for a couple of +> weeks about the finer points of the GPL. + +I feel your pain. + +> I've have spent time pouring through mailing list archives, usenet, +> and web search engines to find out what's already been covered about +> your statement of allowing dynamically loaded kernel modules with +> proprietary code to co-exist with the Linux kernel. So far I've +> been unable to find anything beyond vague statements attributed to +> you. If these issues are addressed somewhere already, please refer +> me. + +Well, it really boils down to the equivalent of "_all_ derived modules +have to be GPL'd". An external module doesn't really change the GPL in +that respect. + +There are (mainly historical) examples of UNIX device drivers and some +UNIX filesystems that were pre-existing pieces of work, and which had +fairly well-defined and clear interfaces and that I personally could not +really consider any kind of "derived work" at all, and that were thus +acceptable. The clearest example of this is probably the AFS (the Andrew +Filesystem), but there have been various device drivers ported from SCO +too. + +> Issue #1 +> ======== +> Currently the GPL version 2 license is the only license covering the +> Linux kernel. I cannot find any alternative license explaining the +> loadable kernel module exception which makes your position difficult +> to legally analyze. +> +> There is a note at the top of www.kernel.org/pub/linux/kernel/COPYING, +> but that states "user programs" which would clearly not apply to +> kernel modules. +> +> Could you clarify in writing what the exception precisely states? + +Well, there really is no exception. However, copyright law obviously +hinges on the definition of "derived work", and as such anything can +always be argued on that point. + +I personally consider anything a "derived work" that needs special hooks +in the kernel to function with Linux (ie it is _not_ acceptable to make a +small piece of GPL-code as a hook for the larger piece), as that obviously +implies that the bigger module needs "help" from the main kernel. + +Similarly, I consider anything that has intimate knowledge about kernel +internals to be a derived work. + +What is left in the gray area tends to be clearly separate modules: code +that had a life outside Linux from the beginning, and that do something +self-containted that doesn't really have any impact on the rest of the +kernel. A device driver that was originally written for something else, +and that doesn't need any but the standard UNIX read/write kind of +interfaces, for example. + +> Issue #2 +> ======== +> I've found statements attributed to you that you think only 10% of +> the code in the current kernel was written by you. By not being the +> sole copyright holder of the Linux kernel, a stated exception to +> the GPL seems invalid unless all kernel copyright holders agreed on +> this exception. How does the exception cover GPL'd kernel code not +> written by you? Has everyone contributing to the kernel forfeited +> their copyright to you or agreed with the exception? + +Well, see above about the lack of exception, and about the fundamental +gray area in _any_ copyright issue. The "derived work" issue is obviously +a gray area, and I know lawyers don't like them. Crazy people (even +judges) have, as we know, claimed that even obvious spoofs of a work that +contain nothing of the original work itself, can be ruled to be "derived". + +I don't hold views that extreme, but at the same time I do consider a +module written for Linux and using kernel infrastructures to get its work +done, even if not actually copying any existing Linux code, to be a +derived work by default. You'd have to have a strong case to _not_ +consider your code a derived work.. + +> Issue #3 +> ======== +> This issue is related to issue #1. Exactly what is covered by the +> exception? For example, all code shipped with the Linux kernel +> archive and typically installed under /usr/src/linux, all code under +> /usr/src/linux except /usr/src/linux/drivers, or just the code in +> the /usr/src/linux/kernel directory? + +See above, and I think you'll see my point. + +The "user program" exception is not an exception at all, for example, it's +just a more clearly stated limitation on the "derived work" issue. If you +use standard UNIX system calls (with accepted Linux extensions), your +program obviously doesn't "derive" from the kernel itself. + +Whenever you link into the kernel, either directly or through a module, +the case is just a _lot_ more muddy. But as stated, by default it's +obviously derived - the very fact that you _need_ to do something as +fundamental as linking against the kernel very much argues that your +module is not a stand-alone thing, regardless of where the module source +code itself has come from. + +> Issue #4 +> ======== +> This last issue is not so much a issue for the Linux kernel +> exception, but a request for comment. +> +> Richard and I both agree that a "plug-in" and a "dynamically +> loaded kernel module" are effectively the same under the GPL. + +Agreed. + +The Linux kernel modules had (a long time ago), a more limited interface, +and not very many functions were actually exported. So five or six years +ago, we could believably claim that "if you only use these N interfaces +that are exported from the standard kernel, you've kind of implicitly +proven that you do not need the kernel infrastructure". + +That was never really documented either (more of a guideline for me and +others when we looked at the "derived work" issue), and as modules were +more-and-more used not for external stuff, but just for dynamic loading of +standard linux modules that were distributed as part of the kernel anyway, +the "limited interfaces" argument is no longer a very good guideline for +"derived work". + +So these days, we export many internal interfaces, not because we don't +think that they would "taint" the linker, but simply because it's useful +to do dynamic run-time loading of modules even with standard kernel +modules that _are_ supposed to know a lot about kernel internals, and are +obviously "derived works".. + +> However we disagree that a plug-in for a GPL'd program falls +> under the GPL as asserted in the GPL FAQ found in the answer: +> http://www.gnu.org/licenses/gpl-faq.html#GPLAndPlugins. + +I think you really just disagree on what is derived, and what is not. +Richard is very extreme: _anything_ that links is derived, regardless of +what the arguments against it are. I'm less extreme, and I bet you're even +less so (at least you would like to argue so for your company). + +> My assertion is that plug-ins are written to an interface, not a +> program. Since interfaces are not GPL'd, a plug-in cannot be GPL'd +> until the plug-in and program are placed together and run. That is +> done by the end user, not the plug-in creator. + +I agree, but also disrespectfully disagree ;) + +It's an issue of what a "plug-in" is - is it a way for the program to +internally load more modules as it needs them, or is it _meant_ to be a +public, published interface. + +For example, the "system call" interface could be considered a "plug-in +interface", and running a user mode program under Linux could easily be +construed as running a "plug-in" for the Linux kernel. No? + +And there, I obviously absolutely agree with you 100%: the interface is +published, and it's _meant_ for external and independent users. It's an +interface that we go to great lengths to preserve as well as we can, and +it's an interface that is designed to be independent of kernel versions. + +But maybe somebody wrote his program with the intention to dynamically +load "actors" as they were needed, as a way to maintain a good modularity, +and to try to keep the problem spaces well-defined. In that case, the +"plug-in" may technically follow all the same rules as the system call +interface, even though the author doesn't intend it that way. + +So I think it's to a large degree a matter of intent, but it could +arguably also be considered a matter of stability and documentation (ie +"require recompilation of the plug-in between version changes" would tend +to imply that it's an internal interface, while "documented binary +compatibility across many releases" implies a more stable external +interface, and less of a derived work) + +Does that make sense to you? + +> I asked Richard to comment on several scenarios involving plug-ins +> explain whether or not they were in violation of the GPL. So far he +> as only addressed one and has effectively admitted a hole. This is +> the one I asked that he's responded to: +> [A] non-GPL'd plug-in writer writes a plug-in for a non-GPL'd +> program. Another author writes a GPL'd program making the +> first author's plug-ins compatible with his program. Are now +> the plug-in author's plug-ins now retroactively required to be +> GPL'd? +> +> His response: +> No, because the plug-in was not written to extend this program. +> +> I find it suspicious that whether or not the GPL would apply to the +> plug-in depends on the mindset of the author. + +The above makes no sense if you think of it as a "plug in" issue, but it +makes sense if you think of it as a "derived work" issue, along with +taking "intent" into account. + +I know lawyers tend to not like the notion of "intent", because it brings +in another whole range of gray areas, but it's obviously a legal reality. + +Ok, enough blathering from me. I'd just like to finish off with a few +comments, just to clarify my personal stand: + + - I'm obviously not the only copyright holder of Linux, and I did so on + purpose for several reasons. One reason is just because I hate the + paperwork and other cr*p that goes along with copyright assignments. + + Another is that I don't much like copyright assignments at all: the + author is the author, and he may be bound by my requirement for GPL, + but that doesn't mean that he should give his copyright to me. + + A third reason, and the most relevant reason here, is that I want + people to _know_ that I cannot control the sources. I can write you a + note to say that "for use XXX, I do not consider module YYY to be a + derived work of my kernel", but that would not really matter that much. + Any other Linux copyright holder might still sue you. + + This third reason is what makes people who otherwise might not trust me + realize that I cannot screw people over. I am bound by the same + agreement that I require of everybody else, and the only special status + I really have is a totally non-legal issue: people trust me. + + (Yes, I realize that I probably would end up having more legal status + than most, even apart from the fact that I still am the largest single + copyright holder, if only because of appearances) + + - I don't really care about copyright law itself. What I care about is my + own morals. Whether I'd ever sue somebody or not (and quite frankly, + it's the last thing I ever want to do - if I never end up talking to + lawyers in a professional context, I'll be perfectly happy. No + disrespect intended) will be entirely up to whether I consider what + people do to me "moral" or not. Which is why intent matters to me a + lot - both the intent of the person/corporation doign the infringement, + _and_ the intent of me and others in issues like the module export + interface. + + Another way of putting this: I don't care about "legal loopholes" and + word-wrangling. + + - Finally: I don't trust the FSF. I like the GPL a lot - although not + necessarily as a legal piece of paper, but more as an intent. Which + explains why, if you've looked at the Linux COPYING file, you may have + noticed the explicit comment about "only _this_ particular version of + the GPL covers the kernel by default". + + That's because I agree with the GPL as-is, but I do not agree with the + FSF on many other matters. I don't like software patents much, for + example, but I do not want the code I write to be used as a weapon + against companies that have them. The FSF has long been discussing and + is drafting the "next generation" GPL, and they generally suggest that + people using the GPL should say "v2 or at your choice any later + version". + + Linux doesn't do that. The Linux kernel is v2 ONLY, apart from a few + files where the author put in the FSF extension (and see above about + copyright assignments why I would never remove such an extension). + +The "v2 only" issue might change some day, but only after all documented +copyright holders agree on it, and only after we've seen what the FSF +suggests. From what I've seen so far from the FSF drafts, we're not likely +to change our v2-only stance, but there might of course be legal reasons +why we'd have to do something like it (ie somebody challenging the GPLv2 +in court, and part of it to be found unenforceable or similar would +obviously mean that we'd have to reconsider the license). + + Linus + +PS. Historically, binary-only modules have not worked well under Linux, +quite regardless of any copyright issues. The kernel just develops too +quickly for binary modules to work well, and nobody really supports them. +Companies like Red Hat etc tend to refuse to have anything to do with +binary modules, because if something goes wrong there is nothing they can +do about it. So I just wanted to let you know that the _legal_ issue is +just the beginning. Even though you probably don't personally care ;) + + diff --git a/Documentation/arm/SA1100/PCMCIA b/Documentation/arm/SA1100/PCMCIA deleted file mode 100644 index 5eb5d3ab3..000000000 --- a/Documentation/arm/SA1100/PCMCIA +++ /dev/null @@ -1,374 +0,0 @@ -Kernel Low-Level PCMCIA Interface Documentation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -John G Dorsey -Updated: 30 June, 2000 - - -Note: this interface has not been finalized! -See also: http://www.cs.cmu.edu/~wearable/software/pcmcia-arm.html - - -Introduction - -Early versions of PCMCIA Card Services for StrongARM were designed to -permit a single socket driver to run on a variety of SA-1100 boards by -using a userland configuration process. During the conversion to the 2.3 -kernel series, all of the configuration has moved into sub-drivers in the -kernel proper (see linux/drivers/pcmcia/sa1100*). This document describes -the low-level interface between those sub-drivers and the sa1100 socket -driver module. - -Presently, there are six operations which must be provided by the -board-specific code. Only functions whose implementation is likely to -differ across board designs are required at this level. Some examples -include: - - - configuring card detect lines to generate interrupts - - sensing the legal voltage levels for inserted cards - - asserting the reset signal for a card - -Functions which are assumed to be the same across all designs are -performed within the generic socket driver itself. Some examples of these -kinds of operations include: - - - configuring memory access times based on the core clock frequency - - reads/writes on memory, byte swizzling, ... - -The current implementation allows the specific per-board set of low-level -operations to be determined at run time. For each specific board, the -following structure should be filled in: - - struct pcmcia_low_level { - int (*init)(struct pcmcia_init *); - int (*shutdown)(void); - int (*socket_state)(struct pcmcia_state_array *); - int (*get_irq_info)(struct pcmcia_irq_info *); - int (*configure_socket)(const struct pcmcia_configure *); - }; - -The component functions are described in detail below. Using the -machine_is_*() tests, the pointer `pcmcia_low_level' should be assigned to -the location of the table for your board. - - -0. init(struct pcmcia_init *init) - -This operation has three responsibilities: - - - perform any board-specific initialization tasks - - associate the given handler with any interrupt-generating signals - such as card detection, or battery voltage detection - - set up any necessary edge detection for card ready signals - -Argument passing for this operation is implemented by the following -structure: - - struct pcmcia_init { - void (*handler)(int irq, void *dev, struct pt_regs *regs); - struct pcmcia_maps *maps; - }; - -Here, `handler' is provided by the socket driver, and `maps' must be -modified if the default mapping isn't appropriate. This operation should -return one of two values: - - - the highest-numbered socket available, plus one - - a negative number, indicating an error in configuration - -Note that the former case is _not_ the same as "the number of sockets -available." In particular, if your design uses SA-1100 slot "one" but -not slot "zero," you MUST report "2" to the socket driver. - - -1. shutdown(void) - -This operation takes no arguments, and will be called during cleanup for -the socket driver module. Any state associated with the socket controller, -including allocated data structures, reserved IRQs, etc. should be -released in this routine. - -The return value for this operation is not examined. - - -2. socket_state(struct pcmcia_state_array *state_array) - -This operation will be invoked from the interrupt handler which was set up -in the earlier call to init(). Note, however, that it should not include -any side effects which would be inappropriate if the operation were to -occur when no interrupt is pending. (An extra invocation of this operation -currently takes place to initialize state in the socket driver.) - -Argument passing for this operation is handled by a structure which -contains an array of the following type: - - struct pcmcia_state { - unsigned detect: 1, - ready: 1, - bvd1: 1, - bvd2: 1, - wrprot: 1, - vs_3v: 1, - vs_Xv: 1; - }; - -Upon return from the operation, a struct pcmcia_state should be filled in -for each socket available in the hardware. For every array element (up to -`size' in the struct pcmcia_state_saarray) which does not correspond to an -available socket, zero the element bits. (This includes element [0] if -socket zero is not used.) - -Regardless of how the various signals are routed to the SA-1100, the bits -in struct pcmcia_state always have the following semantics: - - detect - 1 if a card is fully inserted, 0 otherwise - ready - 1 if the card ready signal is asserted, 0 otherwise - bvd1 - the value of the Battery Voltage Detect 1 signal - bvd2 - the value of the Battery Voltage Detect 2 signal - wrprot - 1 if the card is write-protected, 0 otherwise - vs_3v - 1 if the card must be operated at 3.3V, 0 otherwise - vs_Xv - 1 if the card must be operated at X.XV, 0 otherwise - -A note about the BVD signals: if your board does not make both lines -directly observable to the processor, just return reasonable values. The -standard interpretation of the BVD signals is: - - BVD1 BVD2 - - 0 x battery is dead - 1 0 battery warning - 1 1 battery ok - -Regarding the voltage sense flags (vs_3v, vs_Xv), these bits should be set -based on a sampling of the Voltage Sense pins, if available. The standard -interpretation of the VS signals (for a "low-voltage" socket) is: - - VS1 VS2 - - 0 0 X.XV, else 3.3V, else none - 0 1 3.3V, else none - 1 0 X.XV, else none - 1 1 5V, else none - -More information about the BVD and VS conventions is available in chapter -5 of "PCMCIA System Architecture," 2nd ed., by Don Anderson. - -This operation should return 1 if an IRQ is actually pending for the -socket controller, 0 if no IRQ is pending (but no error condition exists, -such as an undersized state array), or -1 on any error. - - -3. get_irq_info(struct pcmcia_irq_info *info) - -This operation obtains the IRQ assignment which is legal for the given -socket. An argument of the following type is passed: - - struct pcmcia_irq_info { - unsigned int sock; - unsigned int irq ; - }; - -The `sock' field contains the socket index being queried. The `irq' field -should contain the IRQ number corresponding to the card ready signal from -the device. - -This operation should return 0 on success, or -1 on any error. - - -4. configure_socket(const struct pcmcia_configure *configure) - -This operation allows the caller to apply power to the socket, issue a -reset, or enable various outputs. The argument is of the following type: - - struct pcmcia_configure { - unsigned sock: 8, - vcc: 8, - vpp: 8, - output: 1, - speaker: 1, - reset: 1; - }; - -The `sock' field contains the index of the socket to be configured. The -`vcc' and `vpp' fields contain the voltages to be applied for Vcc and Vpp, -respectively, in units of 0.1V. (Note that vpp==120 indicates that -programming voltage should be applied.) - -The two output enables, `output' and `speaker', refer to the card data -signal enable and the card speaker enable, respectively. The `reset' bit, -when set, indicates that the card reset should be asserted. - -This operation should return 0 on success, or -1 on any error. - - -Board-Specific Notes - -The following information is known about various SA-11x0 board designs -which may be used as reference while adding support to the kernel. - - -Carnegie Mellon Itsy/Cue (http://www.cs.cmu.edu/~wearable/itsy/) - - Itsy Chip Select 3 (CS3) Interface - ("ITSY MEMORY/PCMCIA ADD-ON BOARD with BATTERY and CHARGER CIRCUITRY," - memo dated 5-20-99, from Tim Manns to Richard Martin, et. al) - - Read: - ABVD2 (SS)D0 A slot, Battery Voltage Detect - ABVD1 (SS)D1 - AVSS2 (SS)D2 A slot, Voltage Sense - AVSS1 (SS)D3 - GND (SS)D4 - GND (SS)D5 - GND (SS)D6 - GND (SS)D7 - - BBVD2 (SS)D8 B slot, Battery Voltage Detect - BBVD1 (SS)D9 - BVSS2 (SS)D10 B slot, Voltage Sense - BVSS1 (SS)D11 - GND (SS)D12 - GND (SS)D13 - GND (SS)D14 - GND (SS)D15 - - Write: - (SS)D0 A_VPP_VCC LTC1472 VPPEN1 - (SS)D1 A_VPP_PGM LTC1472 VPPEN0 - (SS)D2 A_VCC_3 LTC1472 VCCEN0 - (SS)D3 A_VCC_5 LTC1472 VCCEN1 - (SS)D4 RESET (A SLOT) - (SS)D5 GND - (SS)D6 GND - (SS)D7 GND - - (SS)D8 B_VPP_VCC LTC1472 VPPEN1 - (SS)D9 B_VPP_PGM LTC1472 VPPEN0 - (SS)D10 B_VCC_3 LTC1472 VCCEN0 - (SS)D11 B_VCC_5 LTC1472 VCCEN1 - (SS)D12 RESET (B SLOT) - (SS)D13 GND - (SS)D14 GND - (SS)D15 GND - - GPIO pin assignments are as follows: (from schematics) - - GPIO 10 Slot 0 Card Detect - GPIO 11 Slot 1 Card Detect - GPIO 12 Slot 0 Ready/Interrupt - GPIO 13 Slot 1 Ready/Interrupt - - - -Intel SA-1100 Multimedia Board (http://developer.intel.com/design/strong/) - - CPLD Registers - SA-1100 Multimedia Development Board with Companion SA-1101 Development - Board User's Guide, p.4-42 - - This SA-1100/1101 development package uses only one GPIO pin (24) to - signal changes in card status, and requires software to inspect a - PCMCIA status register to determine the source. - - Read: (PCMCIA Power Sense Register - 0x19400000) - S0VS1 0 Slot 0 voltage sense - S0VS2 1 - S0BVD1 2 Slot 0 battery voltage sense - S0BVD2 3 - S1VS1 4 Slot 1 voltage sense - S1VS2 5 - S1BVD1 6 Slot 1 battery voltage sense - S1BVD2 7 - - Read/Write: (PCMCIA Power Control Register - 0x19400002) - S0VPP0 0 Slot 0 Vpp - S0VPP1 1 - S0VCC0 2 Slot 0 Vcc - S0VCC1 3 - S1VPP0 4 Slot 1 Vpp - S1VPP1 5 - S1VCC0 6 Slot 1 Vcc - S1VCC1 7 - - Read: (PCMCIA Status Register - 0x19400004) - S0CD1 0 Slot 0 Card Detect 1 - S0RDY 1 Slot 0 Ready/Interrupt - S0STSCHG 2 Slot 0 Status Change - S0Reset 3 Slot 0 Reset (RW) - S1CD1 4 Slot 1 Card Detect 1 - S1RDY 5 Slot 1 Ready/Interrupt - S1STSCHG 6 Slot 1 Status Change - S1Reset 7 Slot 1 Reset (RW) - - - -Intel SA-1100 Evaluation Platform (http://developer.intel.com/design/strong/) - - Brutus I/O Pins and Chipselect Register - pcmcia-brutus.c, by Ivo Clarysse - (What's the official reference for this info?) - - This SA-1100 development board uses more GPIO pins than say, the Itsy - or the SA-1100/1101 multimedia package. The pin assignments are as - follows: - - GPIO 2 Slot 0 Battery Voltage Detect 1 - GPIO 3 Slot 0 Ready/Interrupt - GPIO 4 Slot 0 Card Detect - GPIO 5 Slot 1 Battery Voltage Detect 1 - GPIO 6 Slot 1 Ready/Interrupt - GPIO 7 Slot 1 Card Detect - - Like the Itsy, Brutus uses a chipselect register in static memory - bank 3 for the other signals, such as voltage sense or reset: - - Read: - P0_VS1 8 Slot 0 Voltage Sense - P0_VS2 9 - P0_STSCHG 10 Slot 0 Status Change - P1_VS1 12 Slot 1 Voltage Sense - P1_VS2 13 - P1_STSCHG 14 Slot 1 Status Change - - Read/Write: - P0_ 16 Slot 0 MAX1600EAI control line - P0_ 17 Slot 0 MAX1600EAI control line - P0_ 18 Slot 0 MAX1600EAI control line - P0_ 19 Slot 0 MAX1600EAI control line - P0_ 20 Slot 0 12V - P0_ 21 Slot 0 Vpp to Vcc (CONFIRM?) - P0_ 22 Slot 0 enable fan-out drivers & xcvrs - P0_SW_RST 23 Slot 0 Reset - P1_ 24 Slot 1 MAX1600EAI control line - P1_ 25 Slot 1 MAX1600EAI control line - P1_ 26 Slot 1 MAX1600EAI control line - P1_ 27 Slot 1 MAX1600EAI control line - P1_ 28 Slot 1 12V - P1_ 29 Slot 1 Vpp to Vcc (CONFIRM?) - P1_ 30 Slot 1 enable fan-out drivers & xcvrs - P1_SW_RST 31 Slot 1 Reset - - For each slot, the bits labelled "MAX1600EAI" should (apparently) - be written with the value 0101 for Vcc 3.3V, and 1001 for Vcc 5V. - - - -Intel SA-1110 Development Platform (http://developer.intel.com/design/strong/) - - GPIO Pin Descriptions and Board Control Register - SA-1110 Microprocessor Development Board User's Guide, p.4-7, 4-10 - - The Assabet board contains only a single Compact Flash slot, - attached to slot 1 on the SA-1110. Card detect, ready, and BVD - signals are routed through GPIO, with power and reset placed in a - control register. Note that the CF bus must be enabled before use. - - GPIO 21 Slot 1 Compact Flash interrupt - GPIO 22 Slot 1 card detect (CD1 NOR CD2) - GPIO 24 Slot 1 Battery Voltage Detect 2 - GPIO 25 Slot 1 Battery Voltage Detect 1 - - Write-only: (Board Control Register - 0x12000000) - CF_PWR 0 CF bus power (3.3V) - CF_RST 1 CF reset - CF_Bus_On 7 CF bus enable - diff --git a/Documentation/arm/Sharp-LH/SDRAM b/Documentation/arm/Sharp-LH/SDRAM new file mode 100644 index 000000000..93ddc23c2 --- /dev/null +++ b/Documentation/arm/Sharp-LH/SDRAM @@ -0,0 +1,51 @@ +README on the SDRAM Controller for the LH7a40X +============================================== + +The standard configuration for the SDRAM controller generates a sparse +memory array. The precise layout is determined by the SDRAM chips. A +default kernel configuration assembles the discontiguous memory +regions into separate memory nodes via the NUMA (Non-Uniform Memory +Architecture) facilities. In this default configuration, the kernel +is forgiving about the precise layout. As long as it is given an +accurate picture of available memory by the bootloader the kernel will +execute correctly. + +The SDRC supports a mode where some of the chip select lines are +swapped in order to make SDRAM look like a synchronous ROM. Setting +this bit means that the RAM will present as a contiguous array. Some +programmers prefer this to the discontiguous layout. Be aware that +may be a penalty for this feature where some some configurations of +memory are significantly reduced; i.e. 64MiB of RAM appears as only 32 +MiB. + +There are a couple of configuration options to override the default +behavior. When the SROMLL bit is set and memory appears as a +contiguous array, there is no reason to support NUMA. +CONFIG_LH7A40X_CONTIGMEM disables NUMA support. When physical memory +is discontiguous, the memory tables are organized such that there are +two banks per nodes with a small gap between them. This layout wastes +some kernel memory for page tables representing non-existent memory. +CONFIG_LH7A40X_ONE_BANK_PER_NODE optimizes the node tables such that +there are no gaps. These options control the low level organization +of the memory management tables in ways that may prevent the kernel +from booting or may cause the kernel to allocated excessively large +page tables. Be warned. Only change these options if you know what +you are doing. The default behavior is a reasonable compromise that +will suit all users. + +-- + +A typical 32MiB system with the default configuration options will +find physical memory managed as follows. + + node 0: 0xc0000000 4MiB + 0xc1000000 4MiB + node 1: 0xc4000000 4MiB + 0xc5000000 4MiB + node 2: 0xc8000000 4MiB + 0xc9000000 4MiB + node 3: 0xcc000000 4MiB + 0xcd000000 4MiB + +Setting CONFIG_LH7A40X_ONE_BANK_PER_NODE will put each bank into a +separate node. diff --git a/Documentation/arm/VFP/release-notes.txt b/Documentation/arm/VFP/release-notes.txt new file mode 100644 index 000000000..f28e0222f --- /dev/null +++ b/Documentation/arm/VFP/release-notes.txt @@ -0,0 +1,55 @@ +Release notes for Linux Kernel VFP support code +----------------------------------------------- + +Date: 20 May 2004 +Author: Russell King + +This is the first release of the Linux Kernel VFP support code. It +provides support for the exceptions bounced from VFP hardware found +on ARM926EJ-S. + +This release has been validated against the SoftFloat-2b library by +John R. Hauser using the TestFloat-2a test suite. Details of this +library and test suite can be found at: + + http://www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html + +The operations which have been tested with this package are: + + - fdiv + - fsub + - fadd + - fmul + - fcmp + - fcmpe + - fcvtd + - fcvts + - fsito + - ftosi + - fsqrt + +All the above pass softfloat tests with the following exceptions: + +- fadd/fsub shows some differences in the handling of +0 / -0 results + when input operands differ in signs. +- the handling of underflow exceptions is slightly different. If a + result underflows before rounding, but becomes a normalised number + after rounding, we do not signal an underflow exception. + +Other operations which have been tested by basic assembly-only tests +are: + + - fcpy + - fabs + - fneg + - ftoui + - ftosiz + - ftouiz + +The combination operations have not been tested: + + - fmac + - fnmac + - fmsc + - fnmsc + - fnmul diff --git a/Documentation/arm/XScale/ADIFCC/80200EVB b/Documentation/arm/XScale/ADIFCC/80200EVB deleted file mode 100644 index 3762de418..000000000 --- a/Documentation/arm/XScale/ADIFCC/80200EVB +++ /dev/null @@ -1,110 +0,0 @@ - -Board Overview ------------------------------ - -This is an beta release of the Xscale Linux port to the ADI 80200EVB -evaluation board. - -The 80200EVB is an evaluation platform for ADI Engineering's high-performance -80200FCC chipset for the Intel 80200 XScale CPU. The 80200FCC is an open -source FPGA based system that contains a PCI unit and a high performance -memory controller. - -In addition to the 80200FCC, the board also contains a 16C550 UART, and 4MB -of flash. - -The board is still under development and currently only the UART is functional -as the PCI bits have not been programmed into the FPGA. - -For more information on the board, see http://www.adiengineering.com - -Port Status ------------------------------ - -Supported: - -- Onboard UART (Polled operation only) -- Cache/TLB locking on 80200 CPU - -TODO: - -- PCI when hardware supports it - -Building the Kernel ------------------------------ -change Linux makefile -make adi_evb_config -make oldconfig -make zImage - -Loading Linux ------------------------------ - -Before you can use Linux on the ADI board, you need to grab the following: - -ADI 80200EVB Monitor: - ftp://source.mvista.com/pub/xscale/ADI_EVB/monitor.srec - -ADI JFFS2 Image: - ftp://source.mvista.com/pub/xscale/ADI_EVB/adi.jffs2 - -Once you've got the Cygnus prompt, type in the following command: - - load - -On another terminal window: - - cat monitor.srec > /dev/ttyS0 - -(replace ttyS0 with the serial port you are using) - -Once completed, just type 'go' at the cygmon prompt and you should see: - - MontaVista IQ80310 Monitor Version 0.1 - monitor> - -Type 'b 115200' at the prompt and change your terminal speed to 115200 - -The first thing to do is to upload and burn the jffs2 filesystem image -onto the boards 4MB of flash: - - monitor> u c1000000 - Uploading file at 0xc1000000 - Now send file with ymodem - -Do as the monitor says and transfer the file adi.jffs2. Once complete, -the following will copy the jffs2 image to location 0x80000 in the flash. - - monitor> f 8000 c1000000 200000 - Erasing sector 0x00080000 - Writing sector 0x00080000 with data at 0xC1000000 - Erasing sector 0x000A0000 - Writing sector 0x000A0000 with data at 0xC1020000 - Erasing sector 0x000C0000 - ... - -Now use the same command as above to upload your zImage to location c1000000. -When you've done that, type 'j c1000000' to run Linux. Login as -root and you're all set to go. - -Misc Notes ------------------------------ - -The current version of the HW does not have an onboard timer, so the 80200 -PMU is not available for general use as it is being used for a timer source. - -By default, the MTD driver reserves the first 512K for bootloaders and -the remaining 3.5MB for the filesystem. You can edit drivers/mtd/map/adi_evb.c -to change this as needed for your application. - -Contributors ------------------------------ - -Thanks to ADI Engineering for providing the hardware for development - -Deepak Saxena - Initial port - ------------------------------ -Enjoy. If you have any problem please contact Deepak Saxena -dsaxena@mvista.com - diff --git a/Documentation/arm/XScale/IOP3XX/IQ80310 b/Documentation/arm/XScale/IOP3XX/IQ80310 deleted file mode 100644 index 5312a5742..000000000 --- a/Documentation/arm/XScale/IOP3XX/IQ80310 +++ /dev/null @@ -1,247 +0,0 @@ - -Board Overview ------------------------------ - -The Cyclone IQ80310 board is an evaluation platform for Intel's 80200 Xscale -CPU and 80312 Intelligent I/O chipset (collectively called IOP310 chipset). - -The 80312 contains dual PCI hoses (called the ATUs), a PCI-to-PCI bridge, -three DMA channels (1 on secondary PCI, one on primary PCI ), I2C, I2O -messaging unit, XOR unit for RAID operations, a bus performance monitoring -unit, and a memory controller with ECC features. - -For more information on the board, see http://developer.intel.com/iio - -Port Status ------------------------------ - -Supported: - -- MTD/JFFS/JFFS2 -- NFS root -- RAMDISK root -- 2ndary PCI slots -- Onboard ethernet -- Serial ports (ttyS0/S1) -- Cache/TLB locking on 80200 CPU -- Performance monitoring unit on 80200 CPU -- 80200 Performance Monitoring Unit -- Acting as a system controller on Cyclone 80303BP PCI backplane -- DMA engines (EXPERIMENTAL) -- 80312 Bus Performance Monitor (EXPERIMENTAL) -- Application Accelerator Unit (XOR engine for RAID) (EXPERIMENTAL) -- Messaging Unit (EXPERIMENTAL) - -TODO: -- I2C - -Building the Kernel ------------------------------ -make iq80310_config -make oldconfig -make zImage - -This will build an image setup for BOOTP/NFS root support. To change this, -just run make menuconfig and disable nfs root or add a "root=" option. - -Preparing the Hardware ------------------------------ - -This document assumes you're using a Rev D or newer board running -Redboot as the bootloader. Note that the version of RedBoot provided -with the boards has a major issue and you need to replace it with the -latest RedBoot. You can grab the source from the ECOS CVS or you can -get a prebuilt image and burn it in using FRU at: - - ftp://source.mvista.com/pub/xscale/iq80310/redboot.bin - -Make sure you do an 'fis init' command once you boot with the new -RedBoot image. - - - -Downloading Linux ------------------------------ - -Assuming you have your development system setup to act as a bootp/dhcp -server and running tftp: - - RedBoot> load -r -b 0xa1008000 /tftpboot/zImage.xs - Raw file loaded 0xa1008000-0xa1094bd8 - -If you're not using dhcp/tftp, you can use y-modem instead: - - RedBoot> load -r -b 0xa1008000 -m y - -Note that on Rev D. of the board, tftp does not work due to intermittent -interrupt issues, so you need to download using ymodem. - -Once the download is completed: - - RedBoot> go 0xa1008000 - -Root Devices ------------------------------ - -A kernel is not useful without a root filesystem, and you have several -choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development -purposes, it is suggested that you use NFS root for easy access to various -tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on -the flash device. - -MTD on the IQ80310 ------------------------------ - -Linux on the IQ80310 supports RedBoot FIS paritioning if it is enabled. -Out of the box, once you've done 'fis init' on RedBoot, you will get -the following partitioning scheme: - - root@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 0075f000 00020000 "unallocated space" - mtd3: 00001000 00020000 "RedBoot config" - mtd4: 00020000 00020000 "FIS directory" - -To create an FIS directory, you need to use the fis command in RedBoot. -As an example, you can burn the kernel into the flash once it's downloaded: - - RedBoot> fis create -b 0xa1008000 -l 0x8CBAC -r 0xa1008000 -f 0x80000 kernel - ... Erase from 0x00080000-0x00120000: ..... - ... Program from 0xa1008000-0xa1094bac at 0x00080000: ..... - ... Unlock from 0x007e0000-0x00800000: . - ... Erase from 0x007e0000-0x00800000: . - ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . - ... Lock from 0x007e0000-0x00800000: . - - RedBoot> fis list - Name FLASH addr Mem addr Length Entry point - RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 - RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 - RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 - FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 - kernel 0x00080000 0xA1008000 0x000A0000 0x00000000 - -This leads to the following Linux MTD setup: - - mtroot@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 000a0000 00020000 "kernel" - mtd3: 006bf000 00020000 "unallocated space" - mtd4: 00001000 00020000 "RedBoot config" - mtd5: 00020000 00020000 "FIS directory" - -Note that there is not a 1:1 mapping to the number of RedBoot paritions to -MTD partitions as unused space also gets allocated into MTD partitions. - -As an aside, the -r option when creating the Kernel entry allows you to -simply do an 'fis load kernel' to copy the image from flash into memory. -You can then do an 'fis go 0xa1008000' to start Linux. - -If you choose to use static partitioning instead of the RedBoot partioning: - - /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) - /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) - /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) - /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) - -To use a JFFS1/2 root FS, you need to donwload the JFFS image using either -tftp or ymodem, and then copy it to flash: - - RedBoot> load -r -b 0xa1000000 /tftpboot/jffs.img - Raw file loaded 0xa1000000-0xa1600000 - RedBoot> fis create -b 0xa1000000 -l 0x600000 -f 0x120000 jffs - ... Erase from 0x00120000-0x00720000: .................................. - ... Program from 0xa1000000-0xa1600000 at 0x00120000: .................. - ...................... - ... Unlock from 0x007e0000-0x00800000: . - ... Erase from 0x007e0000-0x00800000: . - ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . - ... Lock from 0x007e0000-0x00800000: . - RedBoot> fis list - Name FLASH addr Mem addr Length Entry point - RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 - RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 - RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 - FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 - kernel 0x00080000 0xA1008000 0x000A0000 0xA1008000 - jffs 0x00120000 0x00120000 0x00600000 0x00000000 - -This looks like this in Linux: - - root@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 000a0000 00020000 "kernel" - mtd3: 00600000 00020000 "jffs" - mtd4: 000bf000 00020000 "unallocated space" - mtd5: 00001000 00020000 "RedBoot config" - mtd6: 00020000 00020000 "FIS directory" - -You need to boot the kernel once and watch the boot messages to see how the -JFFS RedBoot partition mapped into the MTD partition scheme. - -You can grab a pre-built JFFS image to use as a root file system at: - - ftp://source.mvista.com/pub/xscale/iq80310/jffs.img - -For detailed info on using MTD and creating a JFFS image go to: - - http://www.linux-mtd.infradead.org. - -For details on using RedBoot's FIS commands, type 'fis help' or consult -your RedBoot manual. - -Contributors ------------------------------ - -Thanks to Intel Corporation for providing the hardware. - -John Clark - Initial discovery of RedBoot issues -Dave Jiang - IRQ demux fixes, AAU, DMA, MU -Nicolas Pitre - Initial port, cleanup, debugging -Matt Porter - PCI subsystem development, debugging -Tim Sanders - Initial PCI code -Mark Salter - RedBoot fixes -Deepak Saxena - Cleanup, debug, cache lock, PMU - ------------------------------ -Enjoy. - -If you have any problems please contact Deepak Saxena - -A few notes from rmk ------------------------------ - -These are notes of my initial experience getting the IQ80310 Rev D up and -running. In total, it has taken many hours to work out what's going on... -The version of redboot used is: - - RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001 - - -1. I've had a corrupted download of the redboot.bin file from Montavista's - FTP site. It would be a good idea if there were md5sums, sum or gpg - signatures available to ensure the integrity of the downloaded files. - The result of this was an apparantly 100% dead card. - -2. RedBoot Intel EtherExpress Pro 100 driver seems to be very unstable - - I've had it take out the whole of a 100mbit network for several minutes. - The Hub indiates ZERO activity, despite machines attempting to communicate. - Further to this, while tftping the kernel, the transfer will stall regularly, - and might even drop the link LED. - -3. There appears to be a bug in the Intel Documentation Pack that comes with - the IQ80310 board. Serial port 1, which is the socket next to the LEDs - is address 0xfe810000, not 0xfe800000. - - Note that RedBoot uses either serial port 1 OR serial port 2, so if you - have your console connected to the wrong port, you'll see redboot messages - but not kernel boot messages. - -4. Trying to use fconfig to setup a boot script fails - it hangs when trying - to erase the flash. diff --git a/Documentation/arm/XScale/IOP3XX/IQ80321 b/Documentation/arm/XScale/IOP3XX/IQ80321 deleted file mode 100644 index e3253279d..000000000 --- a/Documentation/arm/XScale/IOP3XX/IQ80321 +++ /dev/null @@ -1,215 +0,0 @@ - -Board Overview ------------------------------ - -The Worcester IQ80321 board is an evaluation platform for Intel's 80321 Xscale -CPU (sometimes called IOP321 chipset). - -The 80321 contains a single PCI hose (called the ATUs), a PCI-to-PCI bridge, -two DMA channels, I2C, I2O messaging unit, XOR unit for RAID operations, -a bus performance monitoring unit, and a memory controller with ECC features. - -For more information on the board, see http://developer.intel.com/iio - -Port Status ------------------------------ - -Supported: - -- MTD/JFFS/JFFS2 root -- NFS root -- RAMDISK root -- Serial port (ttyS0) -- Cache/TLB locking on 80321 CPU -- Performance monitoring unit on 80321 CPU - -TODO: - -- DMA engines -- I2C -- 80321 Bus Performance Monitor -- Application Accelerator Unit (XOR engine for RAID) -- I2O Messaging Unit -- I2C unit -- SSP - -Building the Kernel ------------------------------ -make iq80321_config -make oldconfig -make zImage - -This will build an image setup for BOOTP/NFS root support. To change this, -just run make menuconfig and disable nfs root or add a "root=" option. - -Preparing the Hardware ------------------------------ - -Make sure you do an 'fis init' command once you boot with the new -RedBoot image. - -Downloading Linux ------------------------------ - -Assuming you have your development system setup to act as a bootp/dhcp -server and running tftp: - -NOTE: The 80321 board uses a different default memory map than the 80310. - - RedBoot> load -r -b 0x01008000 -m y - -Once the download is completed: - - RedBoot> go 0x01008000 - -There is a version of RedBoot floating around that has DHCP support, but -I've never been able to cleanly transfer a kernel image and have it run. - -Root Devices ------------------------------ - -A kernel is not useful without a root filesystem, and you have several -choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development -purposes, it is suggested that you use NFS root for easy access to various -tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on -the flash device. - -MTD on the IQ80321 ------------------------------ - -Linux on the IQ80321 supports RedBoot FIS paritioning if it is enabled. -Out of the box, once you've done 'fis init' on RedBoot, you will get -the following partitioning scheme: - - root@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 0075f000 00020000 "unallocated space" - mtd3: 00001000 00020000 "RedBoot config" - mtd4: 00020000 00020000 "FIS directory" - -To create an FIS directory, you need to use the fis command in RedBoot. -As an example, you can burn the kernel into the flash once it's downloaded: - - RedBoot> fis create -b 0x01008000 -l 0x8CBAC -r 0x01008000 -f 0x80000 kernel - ... Erase from 0x00080000-0x00120000: ..... - ... Program from 0x01008000-0x01094bac at 0x00080000: ..... - ... Unlock from 0x007e0000-0x00800000: . - ... Erase from 0x007e0000-0x00800000: . - ... Program from 0x01fdf000-0x01fff000 at 0x007e0000: . - ... Lock from 0x007e0000-0x00800000: . - - RedBoot> fis list - Name FLASH addr Mem addr Length Entry point - RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 - RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 - RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 - FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 - kernel 0x00080000 0x01008000 0x000A0000 0x00000000 - -This leads to the following Linux MTD setup: - - mtroot@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 000a0000 00020000 "kernel" - mtd3: 006bf000 00020000 "unallocated space" - mtd4: 00001000 00020000 "RedBoot config" - mtd5: 00020000 00020000 "FIS directory" - -Note that there is not a 1:1 mapping to the number of RedBoot paritions to -MTD partitions as unused space also gets allocated into MTD partitions. - -As an aside, the -r option when creating the Kernel entry allows you to -simply do an 'fis load kernel' to copy the image from flash into memory. -You can then do an 'fis go 0x01008000' to start Linux. - -If you choose to use static partitioning instead of the RedBoot partioning: - - /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) - /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) - /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) - /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) - -To use a JFFS1/2 root FS, you need to donwload the JFFS image using either -tftp or ymodem, and then copy it to flash: - - RedBoot> load -r -b 0x01000000 /tftpboot/jffs.img - Raw file loaded 0x01000000-0x01600000 - RedBoot> fis create -b 0x01000000 -l 0x600000 -f 0x120000 jffs - ... Erase from 0x00120000-0x00720000: .................................. - ... Program from 0x01000000-0x01600000 at 0x00120000: .................. - ...................... - ... Unlock from 0x007e0000-0x00800000: . - ... Erase from 0x007e0000-0x00800000: . - ... Program from 0x01fdf000-0x01fff000 at 0x007e0000: . - ... Lock from 0x007e0000-0x00800000: . - RedBoot> fis list - Name FLASH addr Mem addr Length Entry point - RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 - RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 - RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 - FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 - kernel 0x00080000 0x01008000 0x000A0000 0x01008000 - jffs 0x00120000 0x00120000 0x00600000 0x00000000 - -This looks like this in Linux: - - root@192.168.0.14:~# cat /proc/mtd - dev: size erasesize name - mtd0: 00040000 00020000 "RedBoot" - mtd1: 00040000 00020000 "RedBoot[backup]" - mtd2: 000a0000 00020000 "kernel" - mtd3: 00600000 00020000 "jffs" - mtd4: 000bf000 00020000 "unallocated space" - mtd5: 00001000 00020000 "RedBoot config" - mtd6: 00020000 00020000 "FIS directory" - -You need to boot the kernel once and watch the boot messages to see how the -JFFS RedBoot partition mapped into the MTD partition scheme. - -You can grab a pre-built JFFS image to use as a root file system at: - - ftp://source.mvista.com/pub/xscale/iq80310/jffs.img - -For detailed info on using MTD and creating a JFFS image go to: - - http://www.linux-mtd.infradead.org. - -For details on using RedBoot's FIS commands, type 'fis help' or consult -your RedBoot manual. - -BUGS and ISSUES ------------------------------ - -* As shipped from Intel, pre-production boards have two issues: - -- The on board ethernet is disabled S8E1-2 is off. You will need to turn it on. - -- The PCIXCAPs are configured for a 100Mhz clock, but the clock selected is - actually only 66Mhz. This causes the wrong PPL multiplier to be used and the - board only runs at 400Mhz instead of 600Mhz. The way to observe this is to - use a independent clock to time a "sleep 10" command from the prompt. If it - takes 15 seconds instead of 10, you are running at 400Mhz. - -- The experimental IOP310 drivers for the AAU, DMA, etc. are not supported yet. - -Contributors ------------------------------ -The port to the IQ80321 was performed by: - -Rory Bolt - Initial port, debugging. - -This port was based on the IQ80310 port with the following contributors: - -Nicolas Pitre - Initial port, cleanup, debugging -Matt Porter - PCI subsystem development, debugging -Tim Sanders - Initial PCI code -Deepak Saxena - Cleanup, debug, cache lock, PMU - -The port is currently maintained by Deepak Saxena - ------------------------------ -Enjoy. diff --git a/Documentation/arm/XScale/IOP3XX/aau.txt b/Documentation/arm/XScale/IOP3XX/aau.txt deleted file mode 100644 index e3852ccbf..000000000 --- a/Documentation/arm/XScale/IOP3XX/aau.txt +++ /dev/null @@ -1,178 +0,0 @@ -Support functions for the Intel 80310 AAU -=========================================== - -Dave Jiang -Last updated: 09/18/2001 - -The Intel 80312 companion chip in the 80310 chipset contains an AAU. The -AAU is capable of processing up to 8 data block sources and perform XOR -operations on them. This unit is typically used to accelerated XOR -operations utilized by RAID storage device drivers such as RAID 5. This -API is designed to provide a set of functions to take adventage of the -AAU. The AAU can also be used to transfer data blocks and used as a memory -copier. The AAU transfer the memory faster than the operation performed by -using CPU copy therefore it is recommended to use the AAU for memory copy. - ------------------- -int aau_request(u32 *aau_context, const char *device_id); -This function allows the user the acquire the control of the the AAU. The -function will return a context of AAU to the user and allocate -an interrupt for the AAU. The user must pass the context as a parameter to -various AAU API calls. - -int aau_queue_buffer(u32 aau_context, aau_head_t *listhead); -This function starts the AAU operation. The user must create a SGL -header with a SGL attached. The format is presented below. The SGL is -built from kernel memory. - -/* hardware descriptor */ -typedef struct _aau_desc -{ - u32 NDA; /* next descriptor address [READONLY] */ - u32 SAR[AAU_SAR_GROUP]; /* src addrs */ - u32 DAR; /* destination addr */ - u32 BC; /* byte count */ - u32 DC; /* descriptor control */ - u32 SARE[AAU_SAR_GROUP]; /* extended src addrs */ -} aau_desc_t; - -/* user SGL format */ -typedef struct _aau_sgl -{ - aau_desc_t aau_desc; /* AAU HW Desc */ - u32 status; /* status of SGL [READONLY] */ - struct _aau_sgl *next; /* pointer to next SG [READONLY] */ - void *dest; /* destination addr */ - void *src[AAU_SAR_GROUP]; /* source addr[4] */ - void *ext_src[AAU_SAR_GROUP]; /* ext src addr[4] */ - u32 total_src; /* total number of source */ -} aau_sgl_t; - -/* header for user SGL */ -typedef struct _aau_head -{ - u32 total; /* total descriptors allocated */ - u32 status; /* SGL status */ - aau_sgl_t *list; /* ptr to head of list */ - aau_callback_t callback; /* callback func ptr */ -} aau_head_t; - - -The function will call aau_start() and start the AAU after it queues -the SGL to the processing queue. When the function will either -a. Sleep on the wait queue aau->wait_q if no callback has been provided, or -b. Continue and then call the provided callback function when DMA interrupt - has been triggered. - -int aau_suspend(u32 aau_context); -Stops/Suspends the AAU operation - -int aau_free(u32 aau_context); -Frees the ownership of AAU. Called when no longer need AAU service. - -aau_sgl_t * aau_get_buffer(u32 aau_context, int num_buf); -This function obtains an AAU SGL for the user. User must specify the number -of descriptors to be allocated in the chain that is returned. - -void aau_return_buffer(u32 aau_context, aau_sgl_t *list); -This function returns all SGL back to the API after user is done. - -int aau_memcpy(void *dest, void *src, u32 size); -This function is a short cut for user to do memory copy utilizing the AAU for -better large block memory copy vs using the CPU. This is similar to using -typical memcpy() call. - -* User is responsible for the source address(es) and the destination address. - The source and destination should all be cached memory. - - - -void aau_test() -{ - u32 aau; - char dev_id[] = "AAU"; - int size = 2; - int err = 0; - aau_head_t *head; - aau_sgl_t *list; - u32 i; - u32 result = 0; - void *src, *dest; - - printk("Starting AAU test\n"); - if((err = aau_request(&aau, dev_id))<0) - { - printk("test - AAU request failed: %d\n", err); - return; - } - else - { - printk("test - AAU request successful\n"); - } - - head = kmalloc(sizeof(aau_head_t), GFP_KERNEL); - head->total = size; - head->status = 0; - head->callback = NULL; - - list = aau_get_buffer(aau, size); - if(!list) - { - printk("Can't get buffers\n"); - return; - } - head->list = list; - - src = kmalloc(1024, GFP_KERNEL); - dest = kmalloc(1024, GFP_KERNEL); - - while(list) - { - list->status = 0; - list->aau_desc->SAR[0] = (u32)src; - list->aau_desc->DAR = (u32)dest; - list->aau_desc->BC = 1024; - - /* see iop310-aau.h for more DCR commands */ - list->aau_desc->DC = AAU_DCR_WRITE | AAU_DCR_BLKCTRL_1_DF; - if(!list->next) - { - list->aau_desc->DC = AAU_DCR_IE; - break; - } - list = list->next; - } - - printk("test- Queueing buffer for AAU operation\n"); - err = aau_queue_buffer(aau, head); - if(err >= 0) - { - printk("AAU Queue Buffer is done...\n"); - } - else - { - printk("AAU Queue Buffer failed...: %d\n", err); - } - - - -#if 1 - printk("freeing the AAU\n"); - aau_return_buffer(aau, head->list); - aau_free(aau); - kfree(src); - kfree(dest); - kfree((void *)head); -#endif -} - -All Disclaimers apply. Use this at your own discretion. Neither Intel nor I -will be responsible if anything goes wrong. =) - - -TODO -____ -* Testing -* Do zero-size AAU transfer/channel at init - so all we have to do is chainining - diff --git a/Documentation/arm/XScale/IOP3XX/dma.txt b/Documentation/arm/XScale/IOP3XX/dma.txt deleted file mode 100644 index 50c7f99e4..000000000 --- a/Documentation/arm/XScale/IOP3XX/dma.txt +++ /dev/null @@ -1,214 +0,0 @@ -Support functions forthe Intel 80310 DMA channels -================================================== - -Dave Jiang -Last updated: 09/18/2001 - -The Intel 80310 XScale chipset provides 3 DMA channels via the 80312 I/O -companion chip. Two of them resides on the primary PCI bus and one on the -secondary PCI bus. - -The DMA API provided is not compatible with the generic interface in the -ARM tree unfortunately due to how the 80312 DMACs work. Hopefully some time -in the near future a software interface can be done to bridge the differences. -The DMA API has been modeled after Nicholas Pitre's SA11x0 DMA API therefore -they will look somewhat similar. - - -80310 DMA API -------------- - -int dma_request(dmach_t channel, const char *device_id); - -This function will attempt to allocate the channel depending on what the -user requests: - -IOP310_DMA_P0: PCI Primary 1 -IOP310_DMA_P1: PCI Primary 2 -IOP310_DMA_S0: PCI Secondary 1 -/*EOF*/ - -Once the user allocates the DMA channel it is owned until released. Although -other users can also use the same DMA channel, but no new resources will be -allocated. The function will return the allocated channel number if successful. - -int dma_queue_buffer(dmach_t channel, dma_sghead_t *listhead); - -The user will construct a SGL in the form of below: -/* - * Scattered Gather DMA List for user - */ -typedef struct _dma_desc -{ - u32 NDAR; /* next descriptor adress [READONLY] */ - u32 PDAR; /* PCI address */ - u32 PUADR; /* upper PCI address */ - u32 LADR; /* local address */ - u32 BC; /* byte count */ - u32 DC; /* descriptor control */ -} dma_desc_t; - -typedef struct _dma_sgl -{ - dma_desc_t dma_desc; /* DMA descriptor */ - u32 status; /* descriptor status [READONLY] */ - u32 data; /* user defined data */ - struct _dma_sgl *next; /* next descriptor [READONLY] */ -} dma_sgl_t; - -/* dma sgl head */ -typedef struct _dma_head -{ - u32 total; /* total elements in SGL */ - u32 status; /* status of sgl */ - u32 mode; /* read or write mode */ - dma_sgl_t *list; /* pointer to list */ - dma_callback_t callback; /* callback function */ -} dma_head_t; - - -The user shall allocate user SGL elements by calling the function: -dma_get_buffer(). This function will give the user an SGL element. The user -is responsible for creating the SGL head however. The user is also -responsible for allocating the memory for DMA data. The following code segment -shows how a DMA operation can be performed: - -#include - -void dma_test(void) -{ - char dev_id[] = "Primary 0"; - dma_head_t *sgl_head = NULL; - dma_sgl_t *sgl = NULL; - int err = 0; - int channel = -1; - u32 *test_ptr = 0; - DECLARE_WAIT_QUEUE_HEAD(wait_q); - - - *(IOP310_ATUCR) = (IOP310_ATUCR_PRIM_OUT_ENAB | - IOP310_ATUCR_DIR_ADDR_ENAB); - - channel = dma_request(IOP310_DMA_P0, dev_id); - - sgl_head = (dma_head_t *)kmalloc(sizeof(dma_head_t), GFP_KERNEL); - sgl_head->callback = NULL; /* no callback created */ - sgl_head->total = 2; /* allocating 2 DMA descriptors */ - sgl_head->mode = (DMA_MOD_WRITE); - sgl_head->status = 0; - - /* now we get the two descriptors */ - sgl = dma_get_buffer(channel, 2); - - /* we set the header to point to the list we allocated */ - sgl_head->list = sgl; - - /* allocate 1k of DMA data */ - sgl->data = (u32)kmalloc(1024, GFP_KERNEL); - - /* Local address is physical */ - sgl->dma_desc.LADR = (u32)virt_to_phys(sgl->data); - - /* write to arbitrary location over the PCI bus */ - sgl->dma_desc.PDAR = 0x00600000; - sgl->dma_desc.PUADR = 0; - sgl->dma_desc.BC = 1024; - - /* set write & invalidate PCI command */ - sgl->dma_desc.DC = DMA_DCR_PCI_MWI; - sgl->status = 0; - - /* set a pattern */ - memset(sgl->data, 0xFF, 1024); - - /* User's responsibility to keep buffers cached coherent */ - cpu_dcache_clean(sgl->data, sgl->data + 1024); - - sgl = sgl->next; - - sgl->data = (u32)kmalloc(1024, GFP_KERNEL); - sgl->dma_desc.LADR = (u32)virt_to_phys(sgl->data); - sgl->dma_desc.PDAR = 0x00610000; - sgl->dma_desc.PUADR = 0; - sgl->dma_desc.BC = 1024; - - /* second descriptor has interrupt flag enabled */ - sgl->dma_desc.DC = (DMA_DCR_PCI_MWI | DMA_DCR_IE); - - /* must set end of chain flag */ - sgl->status = DMA_END_CHAIN; /* DO NOT FORGET THIS!!!! */ - - memset(sgl->data, 0x0f, 1024); - /* User's responsibility to keep buffers cached coherent */ - cpu_dcache_clean(sgl->data, sgl->data + 1024); - - /* queuing the buffer, this function will sleep since no callback */ - err = dma_queue_buffer(channel, sgl_head); - - /* now we are woken from DMA complete */ - - /* do data operations here */ - - /* free DMA data if necessary */ - - /* return the descriptors */ - dma_return_buffer(channel, sgl_head->list); - - /* free the DMA */ - dma_free(channel); - - kfree((void *)sgl_head); -} - - -dma_sgl_t * dma_get_buffer(dmach_t channel, int buf_num); - -This call allocates DMA descriptors for the user. - - -void dma_return_buffer(dmach_t channel, dma_sgl_t *list); - -This call returns the allocated descriptors back to the API. - - -int dma_suspend(dmach_t channel); - -This call suspends any DMA transfer on the given channel. - - - -int dma_resume(dmach_t channel); - -This call resumes a DMA transfer which would have been stopped through -dma_suspend(). - - -int dma_flush_all(dmach_t channel); - -This completely flushes all queued buffers and on-going DMA transfers on a -given channel. This is called when DMA channel errors have occurred. - - -void dma_free(dmach_t channel); - -This clears all activities on a given DMA channel and releases it for future -requests. - - - -Buffer Allocation ------------------ -It is the user's responsibility to allocate, free, and keep track of the -allocated DMA data memory. Upon calling dma_queue_buffer() the user must -relinquish the control of the buffers to the kernel and not change the -state of the buffers that it has passed to the kernel. The user will regain -the control of the buffers when it has been woken up by the bottom half of -the DMA interrupt handler. The user can allocate cached buffers or non-cached -via pci_alloc_consistent(). It is the user's responsibility to ensure that -the data is cache coherent. - -*Reminder* -The user is responsble to ensure the ATU is setup properly for DMA transfers. - -All Disclaimers apply. Use this at your own discretion. Neither Intel nor I -will be responsible ifanything goes wrong. diff --git a/Documentation/arm/XScale/IOP3XX/message.txt b/Documentation/arm/XScale/IOP3XX/message.txt deleted file mode 100644 index 480d13e7a..000000000 --- a/Documentation/arm/XScale/IOP3XX/message.txt +++ /dev/null @@ -1,110 +0,0 @@ -Support functions for the Intel 80310 MU -=========================================== - -Dave Jiang -Last updated: 10/11/2001 - -The messaging unit of the IOP310 contains 4 components and is utilized for -passing messages between the PCI agents on the primary bus and the Intel(R) -80200 CPU. The four components are: -Messaging Component -Doorbell Component -Circular Queues Component -Index Registers Component - -Messaging Component: -Contains 4 32bit registers, 2 in and 2 out. Writing to the registers assert -interrupt on the PCI bus or to the 80200 depend on incoming or outgoing. - -int mu_msg_request(u32 *mu_context); -Request the usage of Messaging Component. mu_context is written back by the -API. The MU context is passed to other Messaging calls as a parameter. - -int mu_msg_set_callback(u32 mu_context, u8 reg, mu_msg_cb_t func); -Setup the callback function for incoming messages. Callback can be setup for -outbound 0, 1, or both outbound registers. - -int mu_msg_post(u32 mu_context, u32 val, u8 reg); -Posting a message in the val parameter. The reg parameter denotes whether -to use register 0, 1. - -int mu_msg_free(u32 mu_context, u8 mode); -Free the usage of messaging component. mode can be specified soft or hard. In -hardmode all resources are unallocated. - -Doorbell Component: -The doorbell registers contains 1 inbound and 1 outbound. Depending on the bits -being set different interrupts are asserted. - -int mu_db_request(u32 *mu_context); -Request the usage of the doorbell register. - -int mu_db_set_callback(u32 mu_context, mu_db_cb_t func); -Setting up the inbound callback. - -void mu_db_ring(u32 mu_context, u32 mask); -Write to the outbound db register with mask. - -int mu_db_free(u32 mu_context); -Free the usage of doorbell component. - -Circular Queues Component: -The circular queue component has 4 circular queues. Inbound post, inbound free, -outbound post, outbound free. These queues are used to pass messages. - -int mu_cq_request(u32 *mu_context, u32 q_size); -Request the usage of the queue. See code comment header for q_size. It tells -the API how big of queues to setup. - -int mu_cq_inbound_init(u32 mu_context, mfa_list_t *list, u32 size, - mu_cq_cb_t func); -Init inbound queues. The user must provide a list of free message frames to -be put in inbound free queue and the callback function to handle the inbound -messages. - -int mu_cq_enable(u32 mu_context); -Enables the circular queues mechanism. Called once all the setup functions -are called. - -u32 mu_cq_get_frame(u32 mu_context); -Obtain the address of an outbound free frame for the user. - -int mu_cq_post_frame(u32 mu_context, u32 mfa); -The user can post the frame once getting the frame and put information in the -frame. - -int mu_cq_free(u32 mu_context); -Free the usage of circular queues mechanism. - -Index Registers Component: -The index register provides the mechanism to receive inbound messages. - -int mu_ir_request(u32 *mu_context); -Request of Index Register component usage. - -int mu_ir_set_callback(u32 mu_context, mu_ir_cb_t callback); -Setting up callback for inbound messages. The callback will receive the -value of the register that IAR offsets to. - -int mu_ir_free(u32 mu_context); -Free the usage of Index Registers component. - -void mu_set_irq_threshold(u32 mu_context, int thresh); -Setup the IRQ threshold before relinquish processing in IRQ space. Default -is set at 10 loops. - - -*NOTE: Example of host driver that utilize the MU can be found in the Linux I2O -driver. Specifically i2o_pci and some functions of i2o_core. The I2O driver -only utilize the circular queues mechanism. The other 3 components are simple -enough that they can be easily setup. The MU API provides no flow control for -the messaging mechanism. Flow control of the messaging needs to be established -by a higher layer of software on the IOP or the host driver. - -All Disclaimers apply. Use this at your own discretion. Neither Intel nor I -will be responsible if anything goes wrong. =) - - -TODO -____ - diff --git a/Documentation/arm/XScale/IOP3XX/pmon.txt b/Documentation/arm/XScale/IOP3XX/pmon.txt deleted file mode 100644 index 7978494a9..000000000 --- a/Documentation/arm/XScale/IOP3XX/pmon.txt +++ /dev/null @@ -1,71 +0,0 @@ - -Intel's XScale Microarchitecture 80312 companion processor provides a -Performance Monitoring Unit (PMON) that can be utilized to provide -information that can be useful for fine tuning of code. This text -file describes the API that's been developed for use by Linux kernel -programmers. Note that to get the most usage out of the PMON, -I highly reccomend getting the XScale reference manual from Intel[1] -and looking at chapter 12. - -To use the PMON, you must #include in your -source file. - -Since there's only one PMON, only one user can currently use the PMON -at a given time. To claim the PMON for usage, call iop310_pmon_claim() which -returns an identifier. When you are done using the PMON, call -iop310_pmon_release() with the id you were given earlier. - -The PMON consists of 14 registers that can be used for performance measurements. -By combining different statistics, you can derive complex performance metrics. - -To start the PMON, just call iop310_pmon_start(mode). Mode tells the PMON what -statistics to capture and can each be one of: - - IOP310_PMU_MODE0 - Performance Monitoring Disabled - - IOP310_PMU_MODE1 - Primary PCI bus and internal agents (bridge, dma Ch0, dam Ch1, patu) - - IOP310_PMU_MODE2 - Secondary PCI bus and internal agents (bridge, dma Ch0, dam Ch1, patu) - - IOP310_PMU_MODE3 - Secondary PCI bus and internal agents (external masters 0..2 and Intel - 80312 I/O companion chip) - - IOP310_PMU_MODE4 - Secondary PCI bus and internal agents (external masters 3..5 and Intel - 80312 I/O companion chip) - - IOP310_PMU_MODE5 - Intel 80312 I/O companion chip internal bus, DMA Channels and Application - Accelerator - - IOP310_PMU_MODE6 - Intel 80312 I/O companion chip internal bus, PATU, SATU and Intel 80200 - processor - - IOP310_PMU_MODE7 - Intel 80312 I/O companion chip internal bus, Primary PCI bus, Secondary - PCI bus and Secondary PCI agents (external masters 0..5 & Intel 80312 I/O - companion chip) - -To get the results back, call iop310_pmon_stop(&results) where results is -defined as follows: - -typedef struct _iop310_pmon_result -{ - u32 timestamp; /* Global Time Stamp Register */ - u32 timestamp_overflow; /* Time Stamp overflow count */ - u32 event_count[14]; /* Programmable Event Counter - Registers 1-14 */ - u32 event_overflow[14]; /* Overflow counter for PECR1-14 */ -} iop310_pmon_res_t; - - --- -This code is still under development, so please feel free to send patches, -questions, comments, etc to me. - -Deepak Saxena diff --git a/Documentation/arm/XScale/cache-lock.txt b/Documentation/arm/XScale/cache-lock.txt deleted file mode 100644 index 9728c94f1..000000000 --- a/Documentation/arm/XScale/cache-lock.txt +++ /dev/null @@ -1,123 +0,0 @@ - -Intel's XScale Microarchitecture provides support for locking of data -and instructions into the appropriate caches. This file provides -an overview of the API that has been developed to take advantage of this -feature from kernel space. Note that there is NO support for user space -cache locking. - -For example usage of this code, grab: - - ftp://source.mvista.com/pub/xscale/cache-test.c - -If you have any questions, comments, patches, etc, please contact me. - -Deepak Saxena - -API DESCRIPTION - - -I. Header File - - #include - -II. Cache Capability Discovery - - SYNOPSIS - - int cache_query(u8 cache_type, - struct cache_capabilities *pcache); - - struct cache_capabilities - { - u32 flags; /* Flags defining capabilities */ - u32 cache_size; /* Cache size in K (1024 bytes) */ - u32 max_lock; /* Maximum lockable region in K */ - } - - /* - * Flags - */ - - /* - * Bit 0: Cache lockability - * Bits 1-31: Reserved for future use - */ - #define CACHE_LOCKABLE 0x00000001 /* Cache can be locked */ - - /* - * Cache Types - */ - #define ICACHE 0x00 - #define DCACHE 0x01 - - DESCRIPTION - - This function fills out the pcache capability identifier for the - requested cache. cache_type is either DCACHE or ICACHE. This - function is not very useful at the moment as all XScale CPU's - have the same size Cache, but is is provided for future XScale - based processors that may have larger cache sizes. - - RETURN VALUE - - This function returns 0 if no error occurs, otherwise it returns - a negative, errno compatible value. - - -EIO Unknown hardware error - -III. Cache Locking - - SYNOPSIS - - int cache_lock(void *addr, u32 len, u8 cache_type, const char *desc); - - DESCRIPTION - - This function locks a physically contigous portion of memory starting - at the virtual address pointed to by addr into the cache referenced - by cache_type. - - The address of the data/instruction that is to be locked must be - aligned on a cache line boundary (L1_CACHE_ALIGNEMENT). - - The desc parameter is an optional (pass NULL if not used) human readable - descriptor of the locked memory region that is used by the cache - management code to build the /proc/cache_locks table. - - Note that this function does not check whether the address is valid - or not before locking it into the cache. That duty is up to the - caller. Also, it does not check for duplicate or overlaping - entries. - - RETURN VALUE - - If the function is successful in locking the entry into cache, a - zero is returned. - - If an error occurs, an appropriate error value is returned. - - -EINVAL The memory address provided was not cache line aligned - -ENOMEM Could not allocate memory to complete operation - -ENOSPC Not enough space left on cache to lock in requested region - -EIO Unknown error - -III. Cache Unlocking - - SYNOPSIS - - int cache_unlock(void *addr) - - DESCRIPTION - - This function unlocks a portion of memory that was previously locked - into either the I or D cache. - - RETURN VALUE - - If the entry is cleanly unlocked from the cache, a 0 is returned. - In the case of an error, an appropriate error is returned. - - -ENOENT No entry with given address associated with this cache - -EIO Unknown error - - diff --git a/Documentation/arm/XScale/pmu.txt b/Documentation/arm/XScale/pmu.txt deleted file mode 100644 index 508575d65..000000000 --- a/Documentation/arm/XScale/pmu.txt +++ /dev/null @@ -1,168 +0,0 @@ - -Intel's XScale Microarchitecture processors provide a Performance -Monitoring Unit (PMU) that can be utilized to provide information -that can be useful for fine tuning of code. This text file describes -the API that's been developed for use by Linux kernel programmers. -When I have some extra time on my hand, I will extend the code to -provide support for user mode performance monitoring (which is -probably much more useful). Note that to get the most usage out -of the PMU, I highly reccomend getting the XScale reference manual -from Intel and looking at chapter 12. - -To use the PMU, you must #include in your source file. - -Since there's only one PMU, only one user can currently use the PMU -at a given time. To claim the PMU for usage, call pmu_claim() which -returns an identifier. When you are done using the PMU, call -pmu_release() with the identifier that you were given by pmu_claim. - -In addition, the PMU can only be used on XScale based systems that -provide an external timer. Systems that the PMU is currently supported -on are: - - - Cyclone IQ80310 - -Before delving into how to use the PMU code, let's do a quick overview -of the PMU itself. The PMU consists of three registers that can be -used for performance measurements. The first is the CCNT register with -provides the number of clock cycles elapsed since the PMU was started. -The next two register, PMN0 and PMN1, are eace user programmable to -provide 1 of 20 different performance statistics. By combining different -statistics, you can derive complex performance metrics. - -To start the PMU, just call pmu_start(pm0, pmn1). pmn0 and pmn1 tell -the PMU what statistics to capture and can each be one of: - -EVT_ICACHE_MISS - Instruction fetches requiring access to external memory - -EVT_ICACHE_NO_DELIVER - Instruction cache could not deliver an instruction. Either an - ICACHE miss or an instruction TLB miss. - -EVT_ICACHE_DATA_STALL - Stall in execution due to a data dependency. This counter is - incremented each cycle in which the condition is present. - -EVT_ITLB_MISS - Instruction TLB miss - -EVT_DTLB_MISS - Data TLB miss - -EVT_BRANCH - A branch instruction was executed and it may or may not have - changed program flow - -EVT_BRANCH_MISS - A branch (B or BL instructions only) was mispredicted - -EVT_INSTRUCTION - An instruction was executed - -EVT_DCACHE_FULL_STALL - Stall because data cache buffers are full. Incremented on every - cycle in which condition is present. - -EVT_DCACHE_FULL_STALL_CONTIG - Stall because data cache buffers are full. Incremented on every - cycle in which condition is contigous. - -EVT_DCACHE_ACCESS - Data cache access (data fetch) - -EVT_DCACHE_MISS - Data cache miss - -EVT_DCACHE_WRITE_BACK - Data cache write back. This counter is incremented for every - 1/2 line (four words) that are written back. - -EVT_PC_CHANGED - Software changed the PC. This is incremented only when the - software changes the PC and there is no mode change. For example, - a MOV instruction that targets the PC would increment the counter. - An SWI would not as it triggers a mode change. - -EVT_BCU_REQUEST - The Bus Control Unit(BCU) received a request from the core - -EVT_BCU_FULL - The BCU request queue if full. A high value for this event means - that the BCU is often waiting for to complete on the external bus. - -EVT_BCU_DRAIN - The BCU queues were drained due to either a Drain Write Buffer - command or an I/O transaction for a page that was marked as - uncacheable and unbufferable. - -EVT_BCU_ECC_NO_ELOG - The BCU detected an ECC error on the memory bus but noe ELOG - register was available to to log the errors. - -EVT_BCU_1_BIT_ERR - The BCU detected a 1-bit error while reading from the bus. - -EVT_RMW - An RMW cycle occurred due to narrow write on ECC protected memory. - -To get the results back, call pmu_stop(&results) where results is defined -as a struct pmu_results: - - struct pmu_results - { - u32 ccnt; /* Clock Counter Register */ - u32 ccnt_of; / - u32 pmn0; /* Performance Counter Register 0 */ - u32 pmn0_of; - u32 pmn1; /* Performance Counter Register 1 */ - u32 pmn1_of; - }; - -Pretty simple huh? Following are some examples of how to get some commonly -wanted numbers out of the PMU data. Note that since you will be dividing -things, this isn't super useful from the kernel and you need to printk the -data out to syslog. See [1] for more examples. - -Instruction Cache Efficiency - - pmu_start(EVT_INSTRUCTION, EVT_ICACHE_MISS); - ... - pmu_stop(&results); - - icache_miss_rage = results.pmn1 / results.pmn0; - cycles_per_instruction = results.ccnt / results.pmn0; - -Data Cache Efficiency - - pmu_start(EVT_DCACHE_ACCESS, EVT_DCACHE_MISS); - ... - pmu_stop(&results); - - dcache_miss_rage = results.pmn1 / results.pmn0; - -Instruction Fetch Latency - - pmu_start(EVT_ICACHE_NO_DELIVER, EVT_ICACHE_MISS); - ... - pmu_stop(&results); - - average_stall_waiting_for_instruction_fetch = - results.pmn0 / results.pmn1; - - percent_stall_cycles_due_to_instruction_fetch = - results.pmn0 / results.ccnt; - - -ToDo: - -- Add support for usermode PMU usage. This might require hooking into - the scheduler so that we pause the PMU when the task that requested - statistics is scheduled out. - --- -This code is still under development, so please feel free to send patches, -questions, comments, etc to me. - -Deepak Saxena - diff --git a/Documentation/arm/XScale/tlb-lock.txt b/Documentation/arm/XScale/tlb-lock.txt deleted file mode 100644 index 1ba3e11d0..000000000 --- a/Documentation/arm/XScale/tlb-lock.txt +++ /dev/null @@ -1,64 +0,0 @@ - -Intel's XScale Microarchitecture provides support for locking of TLB -entries in both the instruction and data TLBs. This file provides -an overview of the API that has been developed to take advantage of this -feature from kernel space. Note that there is NO support for user space. - -In general, this feature should be used in conjunction with locking -data or instructions into the appropriate caches. See the file -cache-lock.txt in this directory. - -If you have any questions, comments, patches, etc, please contact me. - -Deepak Saxena - - -API DESCRIPTION - -I. Header file - - #include - -II. Locking an entry into the TLB - - SYNOPSIS - - xscale_tlb_lock(u8 tlb_type, u32 addr); - - /* - * TLB types - */ - #define ITLB 0x0 - #define DTLB 0x1 - - DESCRIPTION - - This function locks the virtual to physical mapping for virtual - address addr into the requested TLB. - - RETURN VALUE - - If the entry is properly locked into the TLB, a 0 is returned. - In case of an error, an appropriate error is returned. - - -ENOSPC No more entries left in the TLB - -EIO Unknown error - -III. Unlocking an entry from a TLB - - SYNOPSIS - - xscale_tlb_unlock(u8 tlb_type, u32 addr); - - DESCRIPTION - - This function unlocks the entry for virtual address addr from the - specified cache. - - RETURN VALUE - - If the TLB entry is properly unlocked, a 0 is returned. - In case of an error, an appropriate error is returned. - - -ENOENT No entry for given address in specified TLB - diff --git a/Documentation/device-mapper/dm-io.txt b/Documentation/device-mapper/dm-io.txt new file mode 100644 index 000000000..3b5d9a52c --- /dev/null +++ b/Documentation/device-mapper/dm-io.txt @@ -0,0 +1,75 @@ +dm-io +===== + +Dm-io provides synchronous and asynchronous I/O services. There are three +types of I/O services available, and each type has a sync and an async +version. + +The user must set up an io_region structure to describe the desired location +of the I/O. Each io_region indicates a block-device along with the starting +sector and size of the region. + + struct io_region { + struct block_device *bdev; + sector_t sector; + sector_t count; + }; + +Dm-io can read from one io_region or write to one or more io_regions. Writes +to multiple regions are specified by an array of io_region structures. + +The first I/O service type takes a list of memory pages as the data buffer for +the I/O, along with an offset into the first page. + + struct page_list { + struct page_list *next; + struct page *page; + }; + + int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + unsigned long *error_bits); + int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + io_notify_fn fn, void *context); + +The second I/O service type takes an array of bio vectors as the data buffer +for the I/O. This service can be handy if the caller has a pre-assembled bio, +but wants to direct different portions of the bio to different devices. + + int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, + int rw, struct bio_vec *bvec, + unsigned long *error_bits); + int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, + int rw, struct bio_vec *bvec, + io_notify_fn fn, void *context); + +The third I/O service type takes a pointer to a vmalloc'd memory buffer as the +data buffer for the I/O. This service can be handy if the caller needs to do +I/O to a large region but doesn't want to allocate a large number of individual +memory pages. + + int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, unsigned long *error_bits); + int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, io_notify_fn fn, void *context); + +Callers of the asynchronous I/O services must include the name of a completion +callback routine and a pointer to some context data for the I/O. + + typedef void (*io_notify_fn)(unsigned long error, void *context); + +The "error" parameter in this callback, as well as the "*error" parameter in +all of the synchronous versions, is a bitset (instead of a simple error value). +In the case of an write-I/O to multiple regions, this bitset allows dm-io to +indicate success or failure on each individual region. + +Before using any of the dm-io services, the user should call dm_io_get() +and specify the number of pages they expect to perform I/O on concurrently. +Dm-io will attempt to resize its mempool to make sure enough pages are +always available in order to avoid unnecessary waiting while performing I/O. + +When the user is finished using the dm-io services, they should call +dm_io_put() and specify the same number of pages that were given on the +dm_io_get() call. + diff --git a/Documentation/device-mapper/kcopyd.txt b/Documentation/device-mapper/kcopyd.txt new file mode 100644 index 000000000..820382c4c --- /dev/null +++ b/Documentation/device-mapper/kcopyd.txt @@ -0,0 +1,47 @@ +kcopyd +====== + +Kcopyd provides the ability to copy a range of sectors from one block-device +to one or more other block-devices, with an asynchronous completion +notification. It is used by dm-snapshot and dm-mirror. + +Users of kcopyd must first create a client and indicate how many memory pages +to set aside for their copy jobs. This is done with a call to +kcopyd_client_create(). + + int kcopyd_client_create(unsigned int num_pages, + struct kcopyd_client **result); + +To start a copy job, the user must set up io_region structures to describe +the source and destinations of the copy. Each io_region indicates a +block-device along with the starting sector and size of the region. The source +of the copy is given as one io_region structure, and the destinations of the +copy are given as an array of io_region structures. + + struct io_region { + struct block_device *bdev; + sector_t sector; + sector_t count; + }; + +To start the copy, the user calls kcopyd_copy(), passing in the client +pointer, pointers to the source and destination io_regions, the name of a +completion callback routine, and a pointer to some context data for the copy. + + int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, + unsigned int num_dests, struct io_region *dests, + unsigned int flags, kcopyd_notify_fn fn, void *context); + + typedef void (*kcopyd_notify_fn)(int read_err, unsigned int write_err, + void *context); + +When the copy completes, kcopyd will call the user's completion routine, +passing back the user's context pointer. It will also indicate if a read or +write error occurred during the copy. + +When a user is done with all their copy jobs, they should call +kcopyd_client_destroy() to delete the kcopyd client, which will release the +associated memory pages. + + void kcopyd_client_destroy(struct kcopyd_client *kc); + diff --git a/Documentation/device-mapper/linear.txt b/Documentation/device-mapper/linear.txt new file mode 100644 index 000000000..d5307d380 --- /dev/null +++ b/Documentation/device-mapper/linear.txt @@ -0,0 +1,61 @@ +dm-linear +========= + +Device-Mapper's "linear" target maps a linear range of the Device-Mapper +device onto a linear range of another device. This is the basic building +block of logical volume managers. + +Parameters: + : Full pathname to the underlying block-device, or a + "major:minor" device-number. + : Starting sector within the device. + + +Example scripts +=============== +[[ +#!/bin/sh +# Create an identity mapping for a device +echo "0 `blockdev --getsize $1` linear $1 0" | dmsetup create identity +]] + + +[[ +#!/bin/sh +# Join 2 devices together +size1=`blockdev --getsize $1` +size2=`blockdev --getsize $2` +echo "0 $size1 linear $1 0 +$size1 $size2 linear $2 0" | dmsetup create joined +]] + + +[[ +#!/usr/bin/perl -w +# Split a device into 4M chunks and then join them together in reverse order. + +my $name = "reverse"; +my $extent_size = 4 * 1024 * 2; +my $dev = $ARGV[0]; +my $table = ""; +my $count = 0; + +if (!defined($dev)) { + die("Please specify a device.\n"); +} + +my $dev_size = `blockdev --getsize $dev`; +my $extents = int($dev_size / $extent_size) - + (($dev_size % $extent_size) ? 1 : 0); + +while ($extents > 0) { + my $this_start = $count * $extent_size; + $extents--; + $count++; + my $this_offset = $extents * $extent_size; + + $table .= "$this_start $extent_size linear $dev $this_offset\n"; +} + +`echo \"$table\" | dmsetup create $name`; +]] diff --git a/Documentation/device-mapper/striped.txt b/Documentation/device-mapper/striped.txt new file mode 100644 index 000000000..f34d3236b --- /dev/null +++ b/Documentation/device-mapper/striped.txt @@ -0,0 +1,58 @@ +dm-stripe +========= + +Device-Mapper's "striped" target is used to create a striped (i.e. RAID-0) +device across one or more underlying devices. Data is written in "chunks", +with consecutive chunks rotating among the underlying devices. This can +potentially provide improved I/O throughput by utilizing several physical +devices in parallel. + +Parameters: [ ]+ + : Number of underlying devices. + : Size of each chunk of data. Must be a power-of-2 and at + least as large as the system's PAGE_SIZE. + : Full pathname to the underlying block-device, or a + "major:minor" device-number. + : Starting sector within the device. + +One or more underlying devices can be specified. The striped device size must +be a multiple of the chunk size and a multiple of the number of underlying +devices. + + +Example scripts +=============== + +[[ +#!/usr/bin/perl -w +# Create a striped device across any number of underlying devices. The device +# will be called "stripe_dev" and have a chunk-size of 128k. + +my $chunk_size = 128 * 2; +my $dev_name = "stripe_dev"; +my $num_devs = @ARGV; +my @devs = @ARGV; +my ($min_dev_size, $stripe_dev_size, $i); + +if (!$num_devs) { + die("Specify at least one device\n"); +} + +$min_dev_size = `blockdev --getsize $devs[0]`; +for ($i = 1; $i < $num_devs; $i++) { + my $this_size = `blockdev --getsize $devs[$i]`; + $min_dev_size = ($min_dev_size < $this_size) ? + $min_dev_size : $this_size; +} + +$stripe_dev_size = $min_dev_size * $num_devs; +$stripe_dev_size -= $stripe_dev_size % ($chunk_size * $num_devs); + +$table = "0 $stripe_dev_size striped $num_devs $chunk_size"; +for ($i = 0; $i < $num_devs; $i++) { + $table .= " $devs[$i] 0"; +} + +`echo $table | dmsetup create $dev_name`; +]] + diff --git a/Documentation/device-mapper/zero.txt b/Documentation/device-mapper/zero.txt new file mode 100644 index 000000000..20fb38e7f --- /dev/null +++ b/Documentation/device-mapper/zero.txt @@ -0,0 +1,37 @@ +dm-zero +======= + +Device-Mapper's "zero" target provides a block-device that always returns +zero'd data on reads and silently drops writes. This is similar behavior to +/dev/zero, but as a block-device instead of a character-device. + +Dm-zero has no target-specific parameters. + +One very interesting use of dm-zero is for creating "sparse" devices in +conjunction with dm-snapshot. A sparse device reports a device-size larger +than the amount of actual storage space available for that device. A user can +write data anywhere within the sparse device and read it back like a normal +device. Reads to previously unwritten areas will return a zero'd buffer. When +enough data has been written to fill up the actual storage space, the sparse +device is deactivated. This can be very useful for testing device and +filesystem limitations. + +To create a sparse device, start by creating a dm-zero device that's the +desired size of the sparse device. For this example, we'll assume a 10TB +sparse device. + +TEN_TERABYTES=`expr 10 \* 1024 \* 1024 \* 1024 \* 2` # 10 TB in sectors +echo "0 $TEN_TERABYTES zero" | dmsetup create zero1 + +Then create a snapshot of the zero device, using any available block-device as +the COW device. The size of the COW device will determine the amount of real +space available to the sparse device. For this example, we'll assume /dev/sdb1 +is an available 10GB partition. + +echo "0 $TEN_TERABYTES snapshot /dev/mapper/zero1 /dev/sdb1 p 128" | \ + dmsetup create sparse1 + +This will create a 10TB sparse device called /dev/mapper/sparse1 that has +10GB of actual storage space available. If more than 10GB of data is written +to this device, it will start returning I/O errors. + diff --git a/Documentation/fb/sisfb.txt b/Documentation/fb/sisfb.txt new file mode 100644 index 000000000..3b50c517a --- /dev/null +++ b/Documentation/fb/sisfb.txt @@ -0,0 +1,158 @@ + +What is sisfb? +============== + +sisfb is a framebuffer device driver for SiS (Silicon Integrated Systems) +graphics chips. Supported are: + +- SiS 300 series: SiS 300/305, 540, 630(S), 730(S) +- SiS 315 series: SiS 315/H/PRO, 55x, (M)65x, 740, (M)661(F/M)X, (M)741(GX) +- SiS 330 series: SiS 330 ("Xabre"), (M)760 + + +Why do I need a framebuffer driver? +=================================== + +sisfb is eg. useful if you want a high-resolution text console. Besides that, +sisfb is required to run DirectFB (which comes with an additional, dedicated +driver for the 315 series). + +On the 300 series, sisfb on kernels older than 2.6.3 furthermore plays an +important role in connection with DRM/DRI: Sisfb manages the memory heap +used by DRM/DRI for 3D texture and other data. This memory management is +required for using DRI/DRM. + +Kernels >= around 2.6.3 do not need sisfb any longer for DRI/DRM memory +management. The SiS DRM driver has been updated and features a memory manager +of its own (which will be used if sisfb is not compiled). So unless you want +a graphical console, you don't need sisfb on kernels >=2.6.3. + +Sidenote: Since this seems to be a commonly made mistake: sisfb and vesafb +cannot be active at the same time! Do only select one of them in your kernel +configuration. + + +How are parameters passed to sisfb? +=================================== + +Well, it depends: If compiled statically into the kernel, use lilo's append +statement to add the parameters to the kernel command line. Please see lilo's +(or GRUB's) documentation for more information. If sisfb is a kernel module, +parameters are given with the modprobe (or insmod) command. + +Example for sisfb as part of the static kernel: Add the following line to your +lilo.conf: + + append="video=sisfb:mode:1024x768x16,mem:12288,rate:75" + +Example for sisfb as a module: Start sisfb by typing + + modprobe sisfb mode=1024x768x16 rate=75 mem=12288 + +A common mistake is that folks use a wrong parameter format when using the +driver compiled into the kernel. Please note: If compiled into the kernel, +the parameter format is video=sisfb:mode:none or video=sisfb:mode:1024x768x16 +(or whatever mode you want to use, alternatively using any other format +described above or the vesa keyword instead of mode). If compiled as a module, +the parameter format reads mode=none or mode=1024x768x16 (or whatever mode you +want to use). Using a "=" for a ":" (and vice versa) is a huge difference! +Additionally: If you give more than one argument to the in-kernel sisfb, the +arguments are separated with ",". For example: + + video=sisfb:mode:1024x768x16,rate:75,mem:12288 + + +How do I use it? +================ + +Preface statement: This file only covers very little of the driver's +capabilities and features. Please refer to the author's and maintainer's +website at http://www.winischhofer.net/linuxsisvga.shtml for more +information. Additionally, "modinfo sisfb" gives an overview over all +supported options including some explanation. + +The desired display mode can be specified using the keyword "mode" with +a parameter in one of the follwing formats: + - XxYxDepth or + - XxY-Depth or + - XxY-Depth@Rate or + - XxY + - or simply use the VESA mode number in hexadecimal or decimal. + +For example: 1024x768x16, 1024x768-16@75, 1280x1024-16. If no depth is +specified, it defaults to 8. If no rate is given, it defaults to 60Hz. Depth 32 +means 24bit color depth (but 32 bit framebuffer depth, which is not relevant +to the user). + +Additionally, sisfb understands the keyword "vesa" followed by a VESA mode +number in decimal or hexadecimal. For example: vesa=791 or vesa=0x117. Please +use either "mode" or "vesa" but not both. + +Linux 2.4 only: If no mode is given, sisfb defaults to "no mode" (mode=none) if +compiled as a module; if sisfb is statically compiled into the kernel, it +defaults to 800x600x8 unless CRT2 type is LCD, in which case the LCD's native +resolution is used. If you want to switch to a different mode, use the fbset +shell command. + +Linux 2.6 only: If no mode is given, sisfb defaults to 800x600x8 unless CRT2 +type is LCD, in which case it defaults to the LCD's native resolution. If +you want to switch to another mode, use the stty shell command. + +You should compile in both vgacon (to boot if you remove you SiS card from +your system) and sisfb (for graphics mode). Under Linux 2.6, also "Framebuffer +console support" (fbcon) is needed for a graphical console. + +You should *not* compile-in vesafb. And please do not use the "vga=" keyword +in lilo's or grub's configuration file; mode selection is done using the +"mode" or "vesa" keywords as a parameter. See above and below. + + +X11 +=== + +If using XFree86 or X.org, it is recommended that you don't use the "fbdev" +driver but the dedicated "sis" X driver. The "sis" X driver and sisfb are +developed by the same person (Thomas Winischhofer) and cooperate well with +each other. + + +SVGALib +======= + +SVGALib, if directly accessing the hardware, never restores the screen +correctly, especially on laptops or if the output devices are LCD or TV. +Therefore, use the chipset "FBDEV" in SVGALib configuration. This will make +SVGALib use the framebuffer device for mode switches and restoration. + + +Configuration +============= + +(Some) accepted options: + +off - Disable sisfb. This option is only understood if sisfb is + in-kernel, not a module. +mem:X - size of memory for the console, rest will be used for DRI/DRM. X + is in kilobytes. On 300 series, the default is 4096, 8192 or + 16384 (each in kilobyte) depending on how much video ram the card + has. On 315/330 series, the default is the maximum available ram + (since DRI/DRM is not supported for these chipsets). +noaccel - do not use 2D acceleration engine. (Default: use acceleration) +noypan - disable y-panning and scroll by redrawing the entire screen. + This is much slower than y-panning. (Default: use y-panning) +vesa:X - selects startup videomode. X is number from 0 to 0x1FF and + represents the VESA mode number (can be given in decimal or + hexadecimal form, the latter prefixed with "0x"). +mode:X - selects startup videomode. Please see above for the format of + "X". + +Boolean options such as "noaccel" or "noypan" are to be given without a +parameter if sisfb is in-kernel (for example "video=sisfb:noypan). If +sisfb is a module, these are to be set to 1 (for example "modprobe sisfb +noypan=1"). + +-- +Thomas Winischhofer +May 27, 2004 + + diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index 018ec9693..1cdc5d274 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt @@ -273,21 +273,6 @@ ChangeLog Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. -2.1.14: - - Fix an NFSd caused deadlock reported by several users. -2.1.13: - - Implement writing of inodes (access time updates are not implemented - yet so mounting with -o noatime,nodiratime is enforced). - - Enable writing out of resident files so you can now overwrite any - uncompressed, unencrypted, nonsparse file as long as you do not - change the file size. - - Add housekeeping of ntfs system files so that ntfsfix no longer needs - to be run after writing to an NTFS volume. - NOTE: This still leaves quota tracking and user space journalling on - the side but they should not cause data corruption. In the worst - case the charged quotas will be out of date ($Quota) and some - userspace applications might get confused due to the out of date - userspace journal ($UsnJrnl). 2.1.12: - Fix the second fix to the decompression engine from the 2.1.9 release and some further internals cleanups. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index bc552015b..7dd9fc9ed 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1212,14 +1212,6 @@ On the other hand, enabling this feature can cause you to run out of memory and thrash the system to death, so large and/or important servers will want to set this value to 0. -nr_hugepages and hugetlb_shm_group ----------------------------------- - -nr_hugepages configures number of hugetlb page reserved for the system. - -hugetlb_shm_group contains group id that is allowed to create SysV shared -memory segment using hugetlb page. - 2.5 /proc/sys/dev - Device specific parameters ---------------------------------------------- @@ -1860,3 +1852,10 @@ need to recompile the kernel, or even to reboot the system. The files in the command to write value into these files, thereby changing the default settings of the kernel. ------------------------------------------------------------------------------ + + + + + + + diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt new file mode 100644 index 000000000..7397bdb23 --- /dev/null +++ b/Documentation/filesystems/relayfs.txt @@ -0,0 +1,812 @@ + +relayfs - a high-speed data relay filesystem +============================================ + +relayfs is a filesystem designed to provide an efficient mechanism for +tools and facilities to relay large amounts of data from kernel space +to user space. + +The main idea behind relayfs is that every data flow is put into a +separate "channel" and each channel is a file. In practice, each +channel is a separate memory buffer allocated from within kernel space +upon channel instantiation. Software needing to relay data to user +space would open a channel or a number of channels, depending on its +needs, and would log data to that channel. All the buffering and +locking mechanics are taken care of by relayfs. The actual format and +protocol used for each channel is up to relayfs' clients. + +relayfs makes no provisions for copying the same data to more than a +single channel. This is for the clients of the relay to take care of, +and so is any form of data filtering. The purpose is to keep relayfs +as simple as possible. + + +Usage +===== + +In addition to the relayfs kernel API described below, relayfs +implements basic file operations. Here are the file operations that +are available and some comments regarding their behavior: + +open() enables user to open an _existing_ channel. A channel can be + opened in blocking or non-blocking mode, and can be opened + for reading as well as for writing. Readers will by default + be auto-consuming. + +mmap() results in channel's memory buffer being mmapped into the + caller's memory space. + +read() since we are dealing with circular buffers, the user is only + allowed to read forward. Some apps may want to loop around + read() waiting for incoming data - if there is no data + available, read will put the reader on a wait queue until + data is available (blocking mode). Non-blocking reads return + -EAGAIN if data is not available. + + +write() writing from user space operates exactly as relay_write() does + (described below). + +poll() POLLIN/POLLRDNORM/POLLOUT/POLLWRNORM/POLLERR supported. + +close() decrements the channel's refcount. When the refcount reaches + 0 i.e. when no process or kernel client has the file open + (see relay_close() below), the channel buffer is freed. + + +In order for a user application to make use of relayfs files, the +relayfs filesystem must be mounted. For example, + + mount -t relayfs relayfs /mountpoint + + +The relayfs kernel API +====================== + +relayfs channels are implemented as circular buffers subdivided into +'sub-buffers'. kernel clients write data into the channel using +relay_write(), and are notified via a set of callbacks when +significant events occur within the channel. 'Significant events' +include: + +- a sub-buffer has been filled i.e. the current write won't fit into the + current sub-buffer, and a 'buffer-switch' is triggered, after which + the data is written into the next buffer (if the next buffer is + empty). The client is notified of this condition via two callbacks, + one providing an opportunity to perform start-of-buffer tasks, the + other end-of-buffer tasks. + +- data is ready for the client to process. The client can choose to + be notified either on a per-sub-buffer basis (bulk delivery) or + per-write basis (packet delivery). + +- data has been written to the channel from user space. The client can + use this notification to accept and process 'commands' sent to the + channel via write(2). + +- the channel has been opened/closed/mapped/unmapped from user space. + The client can use this notification to trigger actions within the + kernel application, such as enabling/disabling logging to the + channel. It can also return result codes from the callback, + indicating that the operation should fail e.g. in order to restrict + more than one user space open or mmap. + +- the channel needs resizing, or needs to update its + state based on the results of the resize. Resizing the channel is + up to the kernel client to actually perform. If the channel is + configured for resizing, the client is notified when the unread data + in the channel passes a preset threshold, giving it the opportunity + to allocate a new channel buffer and replace the old one. + +Reader objects +-------------- + +Channel readers use an opaque rchan_reader object to read from +channels. For VFS readers (those using read(2) to read from a +channel), these objects are automatically created and used internally; +only kernel clients that need to directly read from channels, or whose +userspace applications use mmap to access channel data, need to know +anything about rchan_readers - others may skip this section. + +A relay channel can have any number of readers, each represented by an +rchan_reader instance, which is used to encapsulate reader settings +and state. rchan_reader objects should be treated as opaque by kernel +clients. To create a reader object for directly accessing a channel +from kernel space, call the add_rchan_reader() kernel API function: + +rchan_reader *add_rchan_reader(rchan_id, auto_consume) + +This function returns an rchan_reader instance if successful, which +should then be passed to relay_read() when the kernel client is +interested in reading from the channel. + +The auto_consume parameter indicates whether a read done by this +reader will automatically 'consume' that portion of the unread channel +buffer when relay_read() is called (see below for more details). + +To close the reader, call + +remove_rchan_reader(reader) + +which will remove the reader from the list of current readers. + + +To create a reader object representing a userspace mmap reader in the +kernel application, call the add_map_reader() kernel API function: + +rchan_reader *add_map_reader(rchan_id) + +This function returns an rchan_reader instance if successful, whose +main purpose is as an argument to be passed into +relay_buffers_consumed() when the kernel client becomes aware that +data has been read by a user application using mmap to read from the +channel buffer. There is no auto_consume option in this case, since +only the kernel client/user application knows when data has been read. + +To close the map reader, call + +remove_map_reader(reader) + +which will remove the reader from the list of current readers. + +Consumed count +-------------- + +A relayfs channel is a circular buffer, which means that if there is +no reader reading from it or a reader reading too slowly, at some +point the channel writer will 'lap' the reader and data will be lost. +In normal use, readers will always be able to keep up with writers and +the buffer is thus never in danger of becoming full. In many +applications, it's sufficient to ensure that this is practically +speaking always the case, by making the buffers large enough. These +types of applications can basically open the channel as +RELAY_MODE_CONTINOUS (the default anyway) and not worry about the +meaning of 'consume' and skip the rest of this section. + +If it's important for the application that a kernel client never allow +writers to overwrite unread data, the channel should be opened using +RELAY_MODE_NO_OVERWRITE and must be kept apprised of the count of +bytes actually read by the (typically) user-space channel readers. +This count is referred to as the 'consumed count'. read(2) channel +readers automatically update the channel's 'consumed count' as they +read. If the usage mode is to have only read(2) readers, which is +typically the case, the kernel client doesn't need to worry about any +of the relayfs functions having to do with 'bytes consumed' and can +skip the rest of this section. (Note that it is possible to have +multiple read(2) or auto-consuming readers, but like having multiple +readers on a pipe, these readers will race with each other i.e. it's +supported, but doesn't make much sense). + +If the kernel client cannot rely on an auto-consuming reader to keep +the 'consumed count' up-to-date, then it must do so manually, by +making the appropriate calls to relay_buffers_consumed() or +relay_bytes_consumed(). In most cases, this should only be necessary +for bulk mmap clients - almost all packet clients should be covered by +having auto-consuming read(2) readers. For mmapped bulk clients, for +instance, there are no auto-consuming VFS readers, so the kernel +client needs to make the call to relay_buffers_consumed() after +sub-buffers are read. + +Kernel API +---------- + +Here's a summary of the API relayfs provides to in-kernel clients: + +int relay_open(channel_path, bufsize, nbufs, channel_flags, + channel_callbacks, start_reserve, end_reserve, + rchan_start_reserve, resize_min, resize_max, mode, + init_buf, init_buf_size) +int relay_write(channel_id, *data_ptr, count, time_delta_offset, **wrote) +rchan_reader *add_rchan_reader(channel_id, auto_consume) +int remove_rchan_reader(rchan_reader *reader) +rchan_reader *add_map_reader(channel_id) +int remove_map_reader(rchan_reader *reader) +int relay_read(reader, buf, count, wait, *actual_read_offset) +void relay_buffers_consumed(reader, buffers_consumed) +void relay_bytes_consumed(reader, bytes_consumed, read_offset) +int relay_bytes_avail(reader) +int rchan_full(reader) +int rchan_empty(reader) +int relay_info(channel_id, *channel_info) +int relay_close(channel_id) +int relay_realloc_buffer(channel_id, nbufs, async) +int relay_replace_buffer(channel_id) +int relay_reset(int rchan_id) + +---------- +int relay_open(channel_path, bufsize, nbufs, + channel_flags, channel_callbacks, start_reserve, + end_reserve, rchan_start_reserve, resize_min, resize_max, mode) + +relay_open() is used to create a new entry in relayfs. This new entry +is created according to channel_path. channel_path contains the +absolute path to the channel file on relayfs. If, for example, the +caller sets channel_path to "/xlog/9", a "xlog/9" entry will appear +within relayfs automatically and the "xlog" directory will be created +in the filesystem's root. relayfs does not implement any policy on +its content, except to disallow the opening of two channels using the +same file. There are, nevertheless a set of guidelines for using +relayfs. Basically, each facility using relayfs should use a top-level +directory identifying it. The entry created above, for example, +presumably belongs to the "xlog" software. + +The remaining parameters for relay_open() are as follows: + +- channel_flags - an ORed combination of attribute values controlling + common channel characteristics: + + - logging scheme - relayfs use 2 mutually exclusive schemes + for logging data to a channel. The 'lockless scheme' + reserves and writes data to a channel without the need of + any type of locking on the channel. This is the preferred + scheme, but may not be available on a given architecture (it + relies on the presence of a cmpxchg instruction). It's + specified by the RELAY_SCHEME_LOCKLESS flag. The 'locking + scheme' either obtains a lock on the channel for writing or + disables interrupts, depending on whether the channel was + opened for SMP or global usage (see below). It's specified + by the RELAY_SCHEME_LOCKING flag. While a client may want + to explicitly specify a particular scheme to use, it's more + convenient to specify RELAY_SCHEME_ANY for this flag, which + will allow relayfs to choose the best available scheme i.e. + lockless if supported. + + - overwrite mode (default is RELAY_MODE_CONTINUOUS) - + If RELAY_MODE_CONTINUOUS is specified, writes to the channel + will succeed regardless of whether there are up-to-date + consumers or not. If RELAY_MODE_NO_OVERWRITE is specified, + the channel becomes 'full' when the total amount of buffer + space unconsumed by readers equals or exceeds the total + buffer size. With the buffer in this state, writes to the + buffer will fail - clients need to check the return code from + relay_write() to determine if this is the case and act + accordingly - 0 or a negative value indicate the write failed. + + - SMP usage - this applies only when the locking scheme is in + use. If RELAY_USAGE_SMP is specified, it's assumed that the + channel will be used in a per-CPU fashion and consequently, + the only locking that will be done for writes is to disable + local irqs. If RELAY_USAGE_GLOBAL is specified, it's assumed + that writes to the buffer can occur within any CPU context, + and spinlock_irq_save will be used to lock the buffer. + + - delivery mode - if RELAY_DELIVERY_BULK is specified, the + client will be notified via its deliver() callback whenever a + sub-buffer has been filled. Alternatively, + RELAY_DELIVERY_PACKET will cause delivery to occur after the + completion of each write. See the description of the channel + callbacks below for more details. + + - timestamping - if RELAY_TIMESTAMP_TSC is specified and the + architecture supports it, efficient TSC 'timestamps' can be + associated with each write, otherwise more expensive + gettimeofday() timestamping is used. At the beginning of + each sub-buffer, a gettimeofday() timestamp and the current + TSC, if supported, are read, and are passed on to the client + via the buffer_start() callback. This allows correlation of + the current time with the current TSC for subsequent writes. + Each subsequent write is associated with a 'time delta', + which is either the current TSC, if the channel is using + TSCs, or the difference between the buffer_start gettimeofday + timestamp and the gettimeofday time read for the current + write. Note that relayfs never writes either a timestamp or + time delta into the buffer unless explicitly asked to (see + the description of relay_write() for details). + +- bufsize - the size of the 'sub-buffers' making up the circular channel + buffer. For the lockless scheme, this must be a power of 2. + +- nbufs - the number of 'sub-buffers' making up the circular + channel buffer. This must be a power of 2. + + The total size of the channel buffer is bufsize * nbufs rounded up + to the next kernel page size. If the lockless scheme is used, both + bufsize and nbufs must be a power of 2. If the locking scheme is + used, the bufsize can be anything and nbufs must be a power of 2. If + RELAY_SCHEME_ANY is used, the bufsize and nbufs should be a power of 2. + + NOTE: if nbufs is 1, relayfs will bypass the normal size + checks and will allocate an rvmalloced buffer of size bufsize. + This buffer will be freed when relay_close() is called, if the channel + isn't still being referenced. + +- callbacks - a table of callback functions called when events occur + within the data relay that clients need to know about: + + - int buffer_start(channel_id, current_write_pos, buffer_id, + start_time, start_tsc, using_tsc) - + + called at the beginning of a new sub-buffer, the + buffer_start() callback gives the client an opportunity to + write data into space reserved at the beginning of a + sub-buffer. The client should only write into the buffer + if it specified a value for start_reserve and/or + channel_start_reserve (see below) when the channel was + opened. In the latter case, the client can determine + whether to write its one-time rchan_start_reserve data by + examining the value of buffer_id, which will be 0 for the + first sub-buffer. The address that the client can write + to is contained in current_write_pos (the client by + definition knows how much it can write i.e. the value it + passed to relay_open() for start_reserve/ + channel_start_reserve). start_time contains the + gettimeofday() value for the start of the buffer and start + TSC contains the TSC read at the same time. The using_tsc + param indicates whether or not start_tsc is valid (it + wouldn't be if TSC timestamping isn't being used). + + The client should return the number of bytes it wrote to + the channel, 0 if none. + + - int buffer_end(channel_id, current_write_pos, end_of_buffer, + end_time, end_tsc, using_tsc) + + called at the end of a sub-buffer, the buffer_end() + callback gives the client an opportunity to perform + end-of-buffer processing. Note that the current_write_pos + is the position where the next write would occur, but + since the current write wouldn't fit (which is the trigger + for the buffer_end event), the buffer is considered full + even though there may be unused space at the end. The + end_of_buffer param pointer value can be used to determine + exactly the size of the unused space. The client should + only write into the buffer if it specified a value for + end_reserve when the channel was opened. If the client + doesn't write anything i.e. returns 0, the unused space at + the end of the sub-buffer is available via relay_info() - + this data may be needed by the client later if it needs to + process raw sub-buffers (an alternative would be to save + the unused bytes count value in end_reserve space at the + end of each sub-buffer during buffer_end processing and + read it when needed at a later time. The other + alternative would be to use read(2), which makes the + unused count invisible to the caller). end_time contains + the gettimeofday() value for the end of the buffer and end + TSC contains the TSC read at the same time. The using_tsc + param indicates whether or not end_tsc is valid (it + wouldn't be if TSC timestamping isn't being used). + + The client should return the number of bytes it wrote to + the channel, 0 if none. + + - void deliver(channel_id, from, len) + + called when data is ready for the client. This callback + is used to notify a client when a sub-buffer is complete + (in the case of bulk delivery) or a single write is + complete (packet delivery). A bulk delivery client might + wish to then signal a daemon that a sub-buffer is ready. + A packet delivery client might wish to process the packet + or send it elsewhere. The from param is a pointer to the + delivered data and len specifies how many bytes are ready. + + - void user_deliver(channel_id, from, len) + + called when data has been written to the channel from user + space. This callback is used to notify a client when a + successful write from userspace has occurred, independent + of whether bulk or packet delivery is in use. This can be + used to allow userspace programs to communicate with the + kernel client through the channel via out-of-band write(2) + 'commands' instead of via ioctls, for instance. The from + param is a pointer to the delivered data and len specifies + how many bytes are ready. Note that this callback occurs + after the bytes have been successfully written into the + channel, which means that channel readers must be able to + deal with the 'command' data which will appear in the + channel data stream just as any other userspace or + non-userspace write would. + + - int needs_resize(channel_id, resize_type, + suggested_buf_size, suggested_n_bufs) + + called when a channel's buffers are in danger of becoming + full i.e. the number of unread bytes in the channel passes + a preset threshold, or when the current capacity of a + channel's buffer is no longer needed. Also called to + notify the client when a channel's buffer has been + replaced. If resize_type is RELAY_RESIZE_EXPAND or + RELAY_RESIZE_SHRINK, the kernel client should arrange to + call relay_realloc_buffer() with the suggested buffer size + and buffer count, which will allocate (but will not + replace the old one) a new buffer of the recommended size + for the channel. When the allocation has completed, + needs_resize() is again called, this time with a + resize_type of RELAY_RESIZE_REPLACE. The kernel client + should then arrange to call relay_replace_buffer() to + actually replace the old channel buffer with the newly + allocated buffer. Finally, once the buffer replacement + has completed, needs_resize() is again called, this time + with a resize_type of RELAY_RESIZE_REPLACED, to inform the + client that the replacement is complete and additionally + confirming the current sub-buffer size and number of + sub-buffers. Note that a resize can be canceled if + relay_realloc_buffer() is called with the async param + non-zero and the resize conditions no longer hold. In + this case, the RELAY_RESIZE_REPLACED suggested number of + sub-buffers will be the same as the number of sub-buffers + that existed before the RELAY_RESIZE_SHRINK or EXPAND i.e. + values indicating that the resize didn't actually occur. + + - int fileop_notify(channel_id, struct file *filp, enum relay_fileop) + + called when a userspace file operation has occurred or + will occur on a relayfs channel file. These notifications + can be used by the kernel client to trigger actions within + the kernel client when the corresponding event occurs, + such as enabling logging only when a userspace application + opens or mmaps a relayfs file and disabling it again when + the file is closed or unmapped. The kernel client can + also return its own return value, which can affect the + outcome of file operation - returning 0 indicates that the + operation should succeed, and returning a negative value + indicates that the operation should be failed, and that + the returned value should be returned to the ultimate + caller e.g. returning -EPERM from the open fileop will + cause the open to fail with -EPERM. Among other things, + the return value can be used to restrict a relayfs file + from being opened or mmap'ed more than once. The currently + implemented fileops are: + + RELAY_FILE_OPEN - a relayfs file is being opened. Return + 0 to allow it to succeed, negative to + have it fail. A negative return value will + be passed on unmodified to the open fileop. + RELAY_FILE_CLOSE- a relayfs file is being closed. The return + value is ignored. + RELAY_FILE_MAP - a relayfs file is being mmap'ed. Return 0 + to allow it to succeed, negative to have + it fail. A negative return value will be + passed on unmodified to the mmap fileop. + RELAY_FILE_UNMAP- a relayfs file is being unmapped. The return + value is ignored. + + - void ioctl(rchan_id, cmd, arg) + + called when an ioctl call is made using a relayfs file + descriptor. The cmd and arg are passed along to this + callback unmodified for it to do as it wishes with. The + return value from this callback is used as the return value + of the ioctl call. + + If the callbacks param passed to relay_open() is NULL, a set of + default do-nothing callbacks will be defined for the channel. + Likewise, any NULL rchan_callback function contained in a non-NULL + callbacks struct will be filled in with a default callback function + that does nothing. + +- start_reserve - the number of bytes to be reserved at the start of + each sub-buffer. The client can do what it wants with this number + of bytes when the buffer_start() callback is invoked. Typically + clients would use this to write per-sub-buffer header data. + +- end_reserve - the number of bytes to be reserved at the end of each + sub-buffer. The client can do what it wants with this number of + bytes when the buffer_end() callback is invoked. Typically clients + would use this to write per-sub-buffer footer data. + +- channel_start_reserve - the number of bytes to be reserved, in + addition to start_reserve, at the beginning of the first sub-buffer + in the channel. The client can do what it wants with this number of + bytes when the buffer_start() callback is invoked. Typically + clients would use this to write per-channel header data. + +- resize_min - if set, this signifies that the channel is + auto-resizeable. The value specifies the size that the channel will + try to maintain as a normal working size, and that it won't go + below. The client makes use of the resizing callbacks and + relay_realloc_buffer() and relay_replace_buffer() to actually effect + the resize. + +- resize_max - if set, this signifies that the channel is + auto-resizeable. The value specifies the maximum size the channel + can have as a result of resizing. + +- mode - if non-zero, specifies the file permissions that will be given + to the channel file. If 0, the default rw user perms will be used. + +- init_buf - if non-NULL, rather than allocating the channel buffer, + this buffer will be used as the initial channel buffer. The kernel + API function relay_discard_init_buf() can later be used to have + relayfs allocate a normal mmappable channel buffer and switch over + to using it after copying the init_buf contents into it. Currently, + the size of init_buf must be exactly buf_size * n_bufs. The caller + is responsible for managing the init_buf memory. This feature is + typically used for init-time channel use and should normally be + specified as NULL. + +- init_buf_size - the total size of init_buf, if init_buf is specified + as non-NULL. Currently, the size of init_buf must be exactly + buf_size * n_bufs. + +Upon successful completion, relay_open() returns a channel id +to be used for all other operations with the relay. All buffers +managed by the relay are allocated using rvmalloc/rvfree to allow +for easy mmapping to user-space. + +---------- +int relay_write(channel_id, *data_ptr, count, time_delta_offset, **wrote_pos) + +relay_write() reserves space in the channel and writes count bytes of +data pointed to by data_ptr to it. Automatically performs any +necessary locking, depending on the scheme and SMP usage in effect (no +locking is done for the lockless scheme regardless of usage). It +returns the number of bytes written, or 0/negative on failure. If +time_delta_offset is >= 0, the internal time delta, the internal time +delta calculated when the slot was reserved will be written at that +offset. This is the TSC or gettimeofday() delta between the current +write and the beginning of the buffer, whichever method is being used +by the channel. Trying to write a count larger than the bufsize +specified to relay_open() (taking into account the reserved +start-of-buffer and end-of-buffer space as well) will fail. If +wrote_pos is non-NULL, it will receive the location the data was +written to, which may be needed for some applications but is not +normally interesting. Most applications should pass in NULL for this +param. + +---------- +struct rchan_reader *add_rchan_reader(int rchan_id, int auto_consume) + +add_rchan_reader creates and initializes a reader object for a +channel. An opaque rchan_reader object is returned on success, and is +passed to relay_read() when reading the channel. If the boolean +auto_consume parameter is 1, the reader is defined to be +auto-consuming. auto-consuming reader objects are automatically +created and used for VFS read(2) readers. + +---------- +void remove_rchan_reader(struct rchan_reader *reader) + +remove_rchan_reader finds and removes the given reader from the +channel. This function is used only by non-VFS read(2) readers. VFS +read(2) readers are automatically removed when the corresponding file +object is closed. + +---------- +reader add_map_reader(int rchan_id) + +Creates and initializes an rchan_reader object for channel map +readers, and is needed for updating relay_bytes/buffers_consumed() +when kernel clients become aware of the need to do so by their mmap +user clients. + +---------- +int remove_map_reader(reader) + +Finds and removes the given map reader from the channel. This function +is useful only for map readers. + +---------- +int relay_read(reader, buf, count, wait, *actual_read_offset) + +Reads count bytes from the channel, or as much as is available within +the sub-buffer currently being read. The read offset that will be +read from is the position contained within the reader object. If the +wait flag is set, buf is non-NULL, and there is nothing available, it +will wait until there is. If the wait flag is 0 and there is nothing +available, -EAGAIN is returned. If buf is NULL, the value returned is +the number of bytes that would have been read. actual_read_offset is +the value that should be passed as the read offset to +relay_bytes_consumed, needed only if the reader is not auto-consuming +and the channel is MODE_NO_OVERWRITE, but in any case, it must not be +NULL. + +---------- + +int relay_bytes_avail(reader) + +Returns the number of bytes available relative to the reader's current +read position within the corresponding sub-buffer, 0 if there is +nothing available. Note that this doesn't return the total bytes +available in the channel buffer - this is enough though to know if +anything is available, however, or how many bytes might be returned +from the next read. + +---------- +void relay_buffers_consumed(reader, buffers_consumed) + +Adds to the channel's consumed buffer count. buffers_consumed should +be the number of buffers newly consumed, not the total number +consumed. NOTE: kernel clients don't need to call this function if +the reader is auto-consuming or the channel is MODE_CONTINUOUS. + +In order for the relay to detect the 'buffers full' condition for a +channel, it must be kept up-to-date with respect to the number of +buffers consumed by the client. If the addition of the value of the +bufs_consumed param to the current bufs_consumed count for the channel +would exceed the bufs_produced count for the channel, the channel's +bufs_consumed count will be set to the bufs_produced count for the +channel. This allows clients to 'catch up' if necessary. + +---------- +void relay_bytes_consumed(reader, bytes_consumed, read_offset) + +Adds to the channel's consumed count. bytes_consumed should be the +number of bytes actually read e.g. return value of relay_read() and +the read_offset should be the actual offset the bytes were read from +e.g. the actual_read_offset set by relay_read(). NOTE: kernel clients +don't need to call this function if the reader is auto-consuming or +the channel is MODE_CONTINUOUS. + +In order for the relay to detect the 'buffers full' condition for a +channel, it must be kept up-to-date with respect to the number of +bytes consumed by the client. For packet clients, it makes more sense +to update after each read rather than after each complete sub-buffer +read. The bytes_consumed count updates bufs_consumed when a buffer +has been consumed so this count remains consistent. + +---------- +int relay_info(channel_id, *channel_info) + +relay_info() fills in an rchan_info struct with channel status and +attribute information such as usage modes, sub-buffer size and count, +the allocated size of the entire buffer, buffers produced and +consumed, current buffer id, count of writes lost due to buffers full +condition. + +The virtual address of the channel buffer is also available here, for +those clients that need it. + +Clients may need to know how many 'unused' bytes there are at the end +of a given sub-buffer. This would only be the case if the client 1) +didn't either write this count to the end of the sub-buffer or +otherwise note it (it's available as the difference between the buffer +end and current write pos params in the buffer_end callback) (if the +client returned 0 from the buffer_end callback, it's assumed that this +is indeed the case) 2) isn't using the read() system call to read the +buffer. In other words, if the client isn't annotating the stream and +is reading the buffer by mmaping it, this information would be needed +in order for the client to 'skip over' the unused bytes at the ends of +sub-buffers. + +Additionally, for the lockless scheme, clients may need to know +whether a particular sub-buffer is actually complete. An array of +boolean values, one per sub-buffer, contains non-zero if the buffer is +complete, non-zero otherwise. + +---------- +int relay_close(channel_id) + +relay_close() is used to close the channel. It finalizes the last +sub-buffer (the one currently being written to) and marks the channel +as finalized. The channel buffer and channel data structure are then +freed automatically when the last reference to the channel is given +up. + +---------- +int relay_realloc_buffer(channel_id, nbufs, async) + +Allocates a new channel buffer using the specified sub-buffer count +(note that resizing can't change sub-buffer sizes). If async is +non-zero, the allocation is done in the background using a work queue. +When the allocation has completed, the needs_resize() callback is +called with a resize_type of RELAY_RESIZE_REPLACE. This function +doesn't replace the old buffer with the new - see +relay_replace_buffer(). + +This function is called by kernel clients in response to a +needs_resize() callback call with a resize type of RELAY_RESIZE_EXPAND +or RELAY_RESIZE_SHRINK. That callback also includes a suggested +new_bufsize and new_nbufs which should be used when calling this +function. + +Returns 0 on success, or errcode if the channel is busy or if +the allocation couldn't happen for some reason. + +NOTE: if async is not set, this function should not be called with a +lock held, as it may sleep. + +---------- +int relay_replace_buffer(channel_id) + +Replaces the current channel buffer with the new buffer allocated by +relay_realloc_buffer and contained in the channel struct. When the +replacement is complete, the needs_resize() callback is called with +RELAY_RESIZE_REPLACED. This function is called by kernel clients in +response to a needs_resize() callback having a resize type of +RELAY_RESIZE_REPLACE. + +Returns 0 on success, or errcode if the channel is busy or if the +replacement or previous allocation didn't happen for some reason. + +NOTE: This function will not sleep, so can called in any context and +with locks held. The client should, however, ensure that the channel +isn't actively being read from or written to. + +---------- +int relay_reset(rchan_id) + +relay_reset() has the effect of erasing all data from the buffer and +restarting the channel in its initial state. The buffer itself is not +freed, so any mappings are still in effect. NOTE: Care should be +taken that the channnel isn't actually being used by anything when +this call is made. + +---------- +int rchan_full(reader) + +returns 1 if the channel is full with respect to the reader, 0 if not. + +---------- +int rchan_empty(reader) + +returns 1 if the channel is empty with respect to the reader, 0 if not. + +---------- +int relay_discard_init_buf(rchan_id) + +allocates an mmappable channel buffer, copies the contents of init_buf +into it, and sets the current channel buffer to the newly allocated +buffer. This function is used only in conjunction with the init_buf +and init_buf_size params to relay_open(), and is typically used when +the ability to write into the channel at init-time is needed. The +basic usage is to specify an init_buf and init_buf_size to relay_open, +then call this function when it's safe to switch over to a normally +allocated channel buffer. 'Safe' means that the caller is in a +context that can sleep and that nothing is actively writing to the +channel. Returns 0 if successful, negative otherwise. + + +Writing directly into the channel +================================= + +Using the relay_write() API function as described above is the +preferred means of writing into a channel. In some cases, however, +in-kernel clients might want to write directly into a relay channel +rather than have relay_write() copy it into the buffer on the client's +behalf. Clients wishing to do this should follow the model used to +implement relay_write itself. The general sequence is: + +- get a pointer to the channel via rchan_get(). This increments the + channel's reference count. +- call relay_lock_channel(). This will perform the proper locking for + the channel given the scheme in use and the SMP usage. +- reserve a slot in the channel via relay_reserve() +- write directly to the reserved address +- call relay_commit() to commit the write +- call relay_unlock_channel() +- call rchan_put() to release the channel reference + +In particular, clients should make sure they call rchan_get() and +rchan_put() and not hold on to references to the channel pointer. +Also, forgetting to use relay_lock_channel()/relay_unlock_channel() +has no effect if the lockless scheme is being used, but could result +in corrupted buffer contents if the locking scheme is used. + + +Limitations +=========== + +Writes made via the write() system call are currently limited to 2 +pages worth of data. There is no such limit on the in-kernel API +function relay_write(). + +User applications can currently only mmap the complete buffer (it +doesn't really make sense to mmap only part of it, given its purpose). + + +Latest version +============== + +The latest version can be found at: + +http://www.opersys.com/relayfs + +Example relayfs clients, such as dynamic printk and the Linux Trace +Toolkit, can also be found there. + + +Credits +======= + +The ideas and specs for relayfs came about as a result of discussions +on tracing involving the following: + +Michel Dagenais +Richard Moore +Bob Wisniewski +Karim Yaghmour +Tom Zanussi + +Also thanks to Hubertus Franke for a lot of useful suggestions and bug +reports, and for contributing the klog code. diff --git a/Documentation/hpet.txt b/Documentation/hpet.txt new file mode 100644 index 000000000..584ebc277 --- /dev/null +++ b/Documentation/hpet.txt @@ -0,0 +1,298 @@ + High Precision Event Timer Driver for Linux + +The High Precision Event Timer (HPET) hardware is the future replacement for the 8254 and Real +Time Clock (RTC) periodic timer functionality. Each HPET can have up two 32 timers. It is possible +to configure the first two timers as legacy replacements for 8254 and RTC periodic. A specification +done by INTEL and Microsoft can be found at http://www.intel.com/labs/platcomp/hpet/hpetspec.htm. + +The driver supports detection of HPET driver allocation and initialization of the HPET before the +driver module_init routine is called. This enables platform code which uses timer 0 or 1 as the +main timer to intercept HPET initialization. An example of this initialization can be found in +arch/i386/kernel/time_hpet.c. + +The driver provides two APIs which are very similar to the API found in the rtc.c driver. +There is a user space API and a kernel space API. An example user space program is provided +below. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern void hpet_open_close(int, const char **); +extern void hpet_info(int, const char **); +extern void hpet_poll(int, const char **); +extern void hpet_fasync(int, const char **); +extern void hpet_read(int, const char **); + +#include +#include +#include + +struct hpet_command { + char *command; + void (*func)(int argc, const char ** argv); +} hpet_command[] = { + { + "open-close", + hpet_open_close + }, + { + "info", + hpet_info + }, + { + "poll", + hpet_poll + }, + { + "fasync", + hpet_fasync + }, +}; + +int +main(int argc, const char ** argv) +{ + int i; + + argc--; + argv++; + + if (!argc) { + fprintf(stderr, "-hpet: requires command\n"); + return -1; + } + + + for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++) + if (!strcmp(argv[0], hpet_command[i].command)) { + argc--; + argv++; + fprintf(stderr, "-hpet: executing %s\n", + hpet_command[i].command); + hpet_command[i].func(argc, argv); + return 0; + } + + fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]); + + return -1; +} + +void +hpet_open_close(int argc, const char **argv) +{ + int fd; + + if (argc != 1) { + fprintf(stderr, "hpet_open_close: device-name\n"); + return; + } + + fd = open(argv[0], O_RDWR); + if (fd < 0) + fprintf(stderr, "hpet_open_close: open failed\n"); + else + close(fd); + + return; +} + +void +hpet_info(int argc, const char **argv) +{ +} + +void +hpet_poll(int argc, const char **argv) +{ + unsigned long freq; + int iterations, i, fd; + struct pollfd pfd; + struct hpet_info info; + struct timeval stv, etv; + struct timezone tz; + long usec; + + if (argc != 3) { + fprintf(stderr, "hpet_poll: device-name freq iterations\n"); + return; + } + + freq = atoi(argv[1]); + iterations = atoi(argv[2]); + + fd = open(argv[0], O_RDWR); + + if (fd < 0) { + fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]); + return; + } + + if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { + fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n"); + goto out; + } + + if (ioctl(fd, HPET_INFO, &info) < 0) { + fprintf(stderr, "hpet_poll: failed to get info\n"); + goto out; + } + + fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags); + + if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { + fprintf(stderr, "hpet_poll: HPET_EPI failed\n"); + goto out; + } + + if (ioctl(fd, HPET_IE_ON, 0) < 0) { + fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n"); + goto out; + } + + pfd.fd = fd; + pfd.events = POLLIN; + + for (i = 0; i < iterations; i++) { + pfd.revents = 0; + gettimeofday(&stv, &tz); + if (poll(&pfd, 1, -1) < 0) + fprintf(stderr, "hpet_poll: poll failed\n"); + else { + long data; + + gettimeofday(&etv, &tz); + usec = stv.tv_sec * 1000000 + stv.tv_usec; + usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec; + + fprintf(stderr, + "hpet_poll: expired time = 0x%lx\n", usec); + + fprintf(stderr, "hpet_poll: revents = 0x%x\n", + pfd.revents); + + if (read(fd, &data, sizeof(data)) != sizeof(data)) { + fprintf(stderr, "hpet_poll: read failed\n"); + } + else + fprintf(stderr, "hpet_poll: data 0x%lx\n", + data); + } + } + +out: + close(fd); + return; +} + +static int hpet_sigio_count; + +static void +hpet_sigio(int val) +{ + fprintf(stderr, "hpet_sigio: called\n"); + hpet_sigio_count++; +} + +void +hpet_fasync(int argc, const char **argv) +{ + unsigned long freq; + int iterations, i, fd, value; + sig_t oldsig; + struct hpet_info info; + + hpet_sigio_count = 0; + fd = -1; + + if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) { + fprintf(stderr, "hpet_fasync: failed to set signal handler\n"); + return; + } + + if (argc != 3) { + fprintf(stderr, "hpet_fasync: device-name freq iterations\n"); + goto out; + } + + fd = open(argv[0], O_RDWR); + + if (fd < 0) { + fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]); + return; + } + + + if ((fcntl(fd, F_SETOWN, getpid()) == 1) || + ((value = fcntl(fd, F_GETFL)) == 1) || + (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) { + fprintf(stderr, "hpet_fasync: fcntl failed\n"); + goto out; + } + + freq = atoi(argv[1]); + iterations = atoi(argv[2]); + + if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { + fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n"); + goto out; + } + + if (ioctl(fd, HPET_INFO, &info) < 0) { + fprintf(stderr, "hpet_fasync: failed to get info\n"); + goto out; + } + + fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags); + + if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { + fprintf(stderr, "hpet_fasync: HPET_EPI failed\n"); + goto out; + } + + if (ioctl(fd, HPET_IE_ON, 0) < 0) { + fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n"); + goto out; + } + + for (i = 0; i < iterations; i++) { + (void) pause(); + fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count); + } + +out: + signal(SIGIO, oldsig); + + if (fd >= 0) + close(fd); + + return; +} + +The kernel API has three interfaces exported from the driver: + + hpet_register(struct hpet_task *tp, int periodic) + hpet_unregister(struct hpet_task *tp) + hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) + +The kernel module using this interface fills in the ht_func and ht_data members of the +hpet_task structure before calling hpet_register. hpet_control simply vectors to the hpet_ioctl +routine and has the same commands and respective arguments as the user API. hpet_unregister +is used to terminate usage of the HPET timer reserved by hpet_register. + + diff --git a/MAINTAINERS b/MAINTAINERS index 553945d52..5f2455edb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -944,15 +944,15 @@ S: Maintained IA64 (Itanium) PLATFORM P: David Mosberger-Tang M: davidm@hpl.hp.com -L: linux-ia64@vger.kernel.org -W: http://www.ia64-linux.org/ +L: linux-ia64@linuxia64.org +W: http://www.linuxia64.org/ S: Maintained SN-IA64 (Itanium) SUB-PLATFORM P: Jesse Barnes M: jbarnes@sgi.com L: linux-altix@sgi.com -L: linux-ia64@vger.kernel.org +L: linux-ia64@linuxia64.org W: http://www.sgi.com/altix S: Maintained @@ -1390,6 +1390,8 @@ S: Maintained NCP FILESYSTEM P: Petr Vandrovec M: vandrove@vc.cvut.cz +P: Volker Lendecke +M: vl@kki.org L: linware@sh.cvut.cz S: Maintained diff --git a/Makefile b/Makefile index 08d3b92ae..3a78846b9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 -SUBLEVEL = 7 -EXTRAVERSION = +SUBLEVEL = 6 +EXTRAVERSION = -1.422-vs1.9.1 NAME=Zonked Quokka # *DOCUMENTATION* @@ -1062,7 +1062,6 @@ versioncheck: buildcheck: $(PERL) scripts/reference_discarded.pl - $(PERL) scripts/reference_init.pl endif #ifeq ($(config-targets),1) endif #ifeq ($(mixed-targets),1) diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index e1f20ca1c..d770bb867 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -692,6 +692,8 @@ config DEBUG_INFO endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index aa654cc85..5d9aae6be 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -287,6 +287,8 @@ do_sys_ptrace(long request, long pid, long addr, long data, read_unlock(&tasklist_lock); if (!child) goto out_notsk; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 7caf209d6..57052d8a3 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -240,7 +240,15 @@ sys_call_table: .quad alpha_ni_syscall .quad alpha_ni_syscall /* 220 */ .quad alpha_ni_syscall +#ifdef CONFIG_TUX + .quad __sys_tux +#else +# ifdef CONFIG_TUX_MODULE + .quad sys_tux +# else .quad alpha_ni_syscall +# endif +#endif .quad alpha_ni_syscall .quad alpha_ni_syscall .quad alpha_ni_syscall /* 225 */ @@ -291,7 +299,7 @@ sys_call_table: .quad alpha_ni_syscall /* 270 */ .quad alpha_ni_syscall .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_vserver /* 273 sys_vserver */ .quad alpha_ni_syscall .quad alpha_ni_syscall /* 275 */ .quad alpha_ni_syscall diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9743a22fd..db1feb1b3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -581,7 +581,7 @@ config LEDS_CPU config ALIGNMENT_TRAP bool depends on CPU_32 - default y if !ARCH_EBSA110 + default y help ARM processors can not fetch/store information which is not naturally aligned on the bus, i.e., a 4 byte fetch must start at an @@ -808,6 +808,8 @@ config DEBUG_S3C2410_UART endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 480344606..c7e543972 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -86,20 +86,6 @@ .macro writeb, rb strb \rb, [r3, #0] .endm -#elif defined(CONFIG_ARCH_OMAP) - .macro loadsp, rb - mov \rb, #0xff000000 @ physical base address - add \rb, \rb, #0x00fb0000 -#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3) - add \rb, \rb, #0x00000800 -#endif -#ifdef CONFIG_OMAP_LL_DEBUG_UART3 - add \rb, \rb, #0x00009000 -#endif - .endm - .macro writeb, rb - strb \rb, [r3] - .endm #else #error no serial architecture defined #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 8af6251f3..40058170e 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -679,19 +679,19 @@ ENTRY(soft_irq_mask) .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \base, =IO_ADDRESS(OMAP_IH1_BASE) - ldr \irqnr, [\base, #IRQ_ITR_REG_OFFSET] - ldr \tmp, [\base, #IRQ_MIR_REG_OFFSET] + ldr \irqnr, [\base, #IRQ_ITR] + ldr \tmp, [\base, #IRQ_MIR] mov \irqstat, #0xffffffff bic \tmp, \irqstat, \tmp tst \irqnr, \tmp beq 1510f - ldr \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET] + ldr \irqnr, [\base, #IRQ_SIR_FIQ] cmp \irqnr, #0 - ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET] + ldreq \irqnr, [\base, #IRQ_SIR_IRQ] cmpeq \irqnr, #INT_IH2_IRQ ldreq \base, =IO_ADDRESS(OMAP_IH2_BASE) - ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET] + ldreq \irqnr, [\base, #IRQ_SIR_IRQ] addeqs \irqnr, \irqnr, #32 1510: .endm diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index fd3d5b2ba..4bcf7f6a4 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -754,6 +754,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 4aef80895..9cb5cb994 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -253,9 +253,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) - goto badframe; - /* Send SIGTRAP if we're single-stepping */ if (current->ptrace & PT_SINGLESTEP) { ptrace_cancel_bpt(current); @@ -405,7 +402,6 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); - stack_t stack; int err = 0; if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) @@ -415,14 +411,8 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); - __put_user_error(0, &frame->uc.uc_flags, err); - __put_user_error(NULL, &frame->uc.uc_link, err); - - memset(&stack, 0, sizeof(stack)); - stack.ss_sp = (void *)current->sas_ss_sp; - stack.ss_flags = sas_ss_flags(regs->ARM_sp); - stack.ss_size = current->sas_ss_size; - err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); + /* Clear all the bits of the ucontext we don't use. */ + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ regs, set->sig[0]); diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c new file mode 100644 index 000000000..6af3715ad --- /dev/null +++ b/arch/arm/mach-integrator/clock.c @@ -0,0 +1,138 @@ +/* + * linux/arch/arm/mach-integrator/clock.c + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +int clk_use(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_use); + +void clk_unuse(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_unuse); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EIO; + if (clk->setvco) { + struct icst525_vco vco; + + vco = icst525_khz_to_vco(clk->params, rate); + clk->rate = icst525_khz(clk->params, vco); + + printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", + clk->name, vco.s, vco.r, vco.v); + + clk->setvco(clk, vco); + ret = 0; + } + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +/* + * These are fixed clocks. + */ +static struct clk kmi_clk = { + .name = "KMIREFCLK", + .rate = 24000000, +}; + +static struct clk uart_clk = { + .name = "UARTCLK", + .rate = 14745600, +}; + +int clk_register(struct clk *clk) +{ + down(&clocks_sem); + list_add(&clk->node, &clocks); + up(&clocks_sem); + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + down(&clocks_sem); + list_del(&clk->node); + up(&clocks_sem); +} +EXPORT_SYMBOL(clk_unregister); + +static int __init clk_init(void) +{ + clk_register(&kmi_clk); + clk_register(&uart_clk); + return 0; +} +arch_initcall(clk_init); diff --git a/arch/arm/mach-integrator/clock.h b/arch/arm/mach-integrator/clock.h new file mode 100644 index 000000000..09e6328ce --- /dev/null +++ b/arch/arm/mach-integrator/clock.h @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-integrator/clock.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +struct module; +struct icst525_params; + +struct clk { + struct list_head node; + unsigned long rate; + struct module *owner; + const char *name; + const struct icst525_params *params; + void *data; + void (*setvco)(struct clk *, struct icst525_vco vco); +}; + +int clk_register(struct clk *clk); +void clk_unregister(struct clk *clk); diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c index e0b09f86a..bf739b5df 100644 --- a/arch/arm/mach-omap/board-generic.c +++ b/arch/arm/mach-omap/board-generic.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -65,7 +64,7 @@ static void __init omap_generic_map_io(void) omap_map_io(); } -MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610/1710") +MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610") MAINTAINER("Tony Lindgren ") BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) BOOT_PARAMS(0x10000100) diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c index c65f38f58..c11880123 100644 --- a/arch/arm/mach-omap/board-innovator.c +++ b/arch/arm/mach-omap/board-innovator.c @@ -19,10 +19,8 @@ #include #include #include -#include #include -#include #include #include @@ -38,14 +36,14 @@ extern int omap_gpio_init(void); /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc innovator1510_io_desc[] __initdata = { -{ OMAP1510_FPGA_BASE, OMAP1510_FPGA_START, OMAP1510_FPGA_SIZE, +{ OMAP1510P1_FPGA_BASE, OMAP1510P1_FPGA_START, OMAP1510P1_FPGA_SIZE, MT_DEVICE }, }; static struct resource innovator1510_smc91x_resources[] = { [0] = { - .start = OMAP1510_FPGA_ETHR_START, /* Physical */ - .end = OMAP1510_FPGA_ETHR_START + 16, + .start = OMAP1510P1_FPGA_ETHR_START, /* Physical */ + .end = OMAP1510P1_FPGA_ETHR_START + 16, .flags = IORESOURCE_MEM, }, [1] = { @@ -134,13 +132,12 @@ static void __init innovator_map_io(void) #ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc)); - udelay(10); /* Delay needed for FPGA */ /* Dump the Innovator FPGA rev early - useful info for support. */ printk("Innovator FPGA Rev %d.%d Board Rev %d\n", - fpga_read(OMAP1510_FPGA_REV_HIGH), - fpga_read(OMAP1510_FPGA_REV_LOW), - fpga_read(OMAP1510_FPGA_BOARD_REV)); + fpga_read(OMAP1510P1_FPGA_REV_HIGH), + fpga_read(OMAP1510P1_FPGA_REV_LOW), + fpga_read(OMAP1510P1_FPGA_BOARD_REV)); } #endif #ifdef CONFIG_ARCH_OMAP1610 diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c index 8044dd190..521683496 100644 --- a/arch/arm/mach-omap/board-osk.c +++ b/arch/arm/mach-omap/board-osk.c @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c index e938ea4b6..3843d6a6d 100644 --- a/arch/arm/mach-omap/board-perseus2.c +++ b/arch/arm/mach-omap/board-perseus2.c @@ -3,9 +3,6 @@ * * Modified from board-generic.c * - * Original OMAP730 support by Jean Pihet - * Updated for 2.6 by Kevin Hilman - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -16,7 +13,6 @@ #include #include -#include #include #include @@ -106,7 +102,7 @@ static void __init omap_perseus2_map_io(void) } MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") - MAINTAINER("Kevin Hilman ") + MAINTAINER("Kevin Hilman ") BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) BOOT_PARAMS(0x10000100) MAPIO(omap_perseus2_map_io) diff --git a/arch/arm/mach-omap/bus.c b/arch/arm/mach-omap/bus.c index 07da30d52..ba5dd2a8c 100644 --- a/arch/arm/mach-omap/bus.c +++ b/arch/arm/mach-omap/bus.c @@ -39,7 +39,6 @@ #include #include -#include #include #include #include @@ -266,7 +265,7 @@ static void __exit omap_bus_exit(void) } } -postcore_initcall(omap_bus_init); +module_init(omap_bus_init); module_exit(omap_bus_exit); MODULE_DESCRIPTION("Virtual bus for OMAP"); diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c index 385b4d1cc..29c62e141 100644 --- a/arch/arm/mach-omap/dma.c +++ b/arch/arm/mach-omap/dma.c @@ -92,124 +92,45 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, { u16 w; - w = omap_readw(OMAP_DMA_CSDP(lch)); + w = omap_readw(OMAP_DMA_CSDP_REG(lch)); w &= ~0x03; w |= data_type; - omap_writew(w, OMAP_DMA_CSDP(lch)); + omap_writew(w, OMAP_DMA_CSDP_REG(lch)); - w = omap_readw(OMAP_DMA_CCR(lch)); + w = omap_readw(OMAP_DMA_CCR_REG(lch)); w &= ~(1 << 5); if (sync_mode == OMAP_DMA_SYNC_FRAME) w |= 1 << 5; - omap_writew(w, OMAP_DMA_CCR(lch)); + omap_writew(w, OMAP_DMA_CCR_REG(lch)); - w = omap_readw(OMAP_DMA_CCR2(lch)); + w = omap_readw(OMAP_DMA_CCR2_REG(lch)); w &= ~(1 << 2); if (sync_mode == OMAP_DMA_SYNC_BLOCK) w |= 1 << 2; - omap_writew(w, OMAP_DMA_CCR2(lch)); + omap_writew(w, OMAP_DMA_CCR2_REG(lch)); - omap_writew(elem_count, OMAP_DMA_CEN(lch)); - omap_writew(frame_count, OMAP_DMA_CFN(lch)); + omap_writew(elem_count, OMAP_DMA_CEN_REG(lch)); + omap_writew(frame_count, OMAP_DMA_CFN_REG(lch)); } -void omap_set_dma_constant_fill(int lch, u32 color) -{ - u16 w; - -#ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { - printk(KERN_ERR "OMAP DMA constant fill not available in 1510 mode."); - BUG(); - return; - } -#endif - w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03; - w |= 0x01; - omap_writew(w, OMAP_DMA_CCR2(lch)); - - omap_writew((u16)color, OMAP_DMA_COLOR_L(lch)); - omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch)); - - w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f; - w |= 1; /* Channel type G */ - omap_writew(w, OMAP_DMA_LCH_CTRL(lch)); -} - -void omap_set_dma_transparent_copy(int lch, u32 color) -{ - u16 w; - -#ifdef CONFIG_DEBUG_KERNEL - if (omap_dma_in_1510_mode) { - printk(KERN_ERR "OMAP DMA transparent copy not available in 1510 mode."); - BUG(); - } -#endif - w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03; - w |= 0x02; - omap_writew(w, OMAP_DMA_CCR2(lch)); - - omap_writew((u16)color, OMAP_DMA_COLOR_L(lch)); - omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch)); - - w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f; - w |= 1; /* Channel type G */ - omap_writew(w, OMAP_DMA_LCH_CTRL(lch)); -} void omap_set_dma_src_params(int lch, int src_port, int src_amode, unsigned long src_start) { u16 w; - w = omap_readw(OMAP_DMA_CSDP(lch)); + w = omap_readw(OMAP_DMA_CSDP_REG(lch)); w &= ~(0x1f << 2); w |= src_port << 2; - omap_writew(w, OMAP_DMA_CSDP(lch)); + omap_writew(w, OMAP_DMA_CSDP_REG(lch)); - w = omap_readw(OMAP_DMA_CCR(lch)); + w = omap_readw(OMAP_DMA_CCR_REG(lch)); w &= ~(0x03 << 12); w |= src_amode << 12; - omap_writew(w, OMAP_DMA_CCR(lch)); - - omap_writew(src_start >> 16, OMAP_DMA_CSSA_U(lch)); - omap_writew(src_start, OMAP_DMA_CSSA_L(lch)); -} - -void omap_set_dma_src_index(int lch, int eidx, int fidx) -{ - omap_writew(eidx, OMAP_DMA_CSEI(lch)); - omap_writew(fidx, OMAP_DMA_CSFI(lch)); -} - -void omap_set_dma_src_data_pack(int lch, int enable) -{ - u16 w; - - w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 6); - w |= enable ? (1 << 6) : 0; - omap_writew(w, OMAP_DMA_CSDP(lch)); -} - -void omap_set_dma_src_burst_mode(int lch, int burst_mode) -{ - u16 w; + omap_writew(w, OMAP_DMA_CCR_REG(lch)); - w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 7); - switch (burst_mode) { - case OMAP_DMA_DATA_BURST_4: - w |= (0x01 << 7); - break; - case OMAP_DMA_DATA_BURST_8: - w |= (0x03 << 7); - break; - default: - printk(KERN_ERR "Invalid DMA burst mode\n"); - BUG(); - return; - } - omap_writew(w, OMAP_DMA_CSDP(lch)); + omap_writew(src_start >> 16, OMAP_DMA_CSSA_U_REG(lch)); + omap_writew(src_start, OMAP_DMA_CSSA_L_REG(lch)); } void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, @@ -217,53 +138,18 @@ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, { u16 w; - w = omap_readw(OMAP_DMA_CSDP(lch)); + w = omap_readw(OMAP_DMA_CSDP_REG(lch)); w &= ~(0x1f << 9); w |= dest_port << 9; - omap_writew(w, OMAP_DMA_CSDP(lch)); + omap_writew(w, OMAP_DMA_CSDP_REG(lch)); - w = omap_readw(OMAP_DMA_CCR(lch)); + w = omap_readw(OMAP_DMA_CCR_REG(lch)); w &= ~(0x03 << 14); w |= dest_amode << 14; - omap_writew(w, OMAP_DMA_CCR(lch)); - - omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U(lch)); - omap_writew(dest_start, OMAP_DMA_CDSA_L(lch)); -} - -void omap_set_dma_dest_index(int lch, int eidx, int fidx) -{ - omap_writew(eidx, OMAP_DMA_CDEI(lch)); - omap_writew(fidx, OMAP_DMA_CDFI(lch)); -} - -void omap_set_dma_dest_data_pack(int lch, int enable) -{ - u16 w; + omap_writew(w, OMAP_DMA_CCR_REG(lch)); - w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 13); - w |= enable ? (1 << 13) : 0; - omap_writew(w, OMAP_DMA_CSDP(lch)); -} - -void omap_set_dma_dest_burst_mode(int lch, int burst_mode) -{ - u16 w; - - w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 14); - switch (burst_mode) { - case OMAP_DMA_DATA_BURST_4: - w |= (0x01 << 14); - break; - case OMAP_DMA_DATA_BURST_8: - w |= (0x03 << 14); - break; - default: - printk(KERN_ERR "Invalid DMA burst mode\n"); - BUG(); - return; - } - omap_writew(w, OMAP_DMA_CSDP(lch)); + omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U_REG(lch)); + omap_writew(dest_start, OMAP_DMA_CDSA_L_REG(lch)); } void omap_start_dma(int lch) @@ -278,38 +164,38 @@ void omap_start_dma(int lch) /* Enable the queue, if needed so. */ if (next_lch != -1) { /* Clear the STOP_LNK bits */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w = omap_readw(OMAP_DMA_CLNK_CTRL_REG(lch)); w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); + omap_writew(w, OMAP_DMA_CLNK_CTRL_REG(lch)); + w = omap_readw(OMAP_DMA_CLNK_CTRL_REG(next_lch)); w &= ~(1 << 14); - omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); + omap_writew(w, OMAP_DMA_CLNK_CTRL_REG(next_lch)); /* And set the ENABLE_LNK bits */ omap_writew(next_lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(lch)); + OMAP_DMA_CLNK_CTRL_REG(lch)); /* The loop case */ if (dma_chan[next_lch].next_lch == lch) omap_writew(lch | (1 << 15), - OMAP_DMA_CLNK_CTRL(next_lch)); + OMAP_DMA_CLNK_CTRL_REG(next_lch)); /* Read CSR to make sure it's cleared. */ - w = omap_readw(OMAP_DMA_CSR(next_lch)); + w = omap_readw(OMAP_DMA_CSR_REG(next_lch)); /* Enable some nice interrupts. */ omap_writew(dma_chan[next_lch].enabled_irqs, - OMAP_DMA_CICR(next_lch)); + OMAP_DMA_CICR_REG(next_lch)); dma_chan[next_lch].flags |= OMAP_DMA_ACTIVE; } } /* Read CSR to make sure it's cleared. */ - w = omap_readw(OMAP_DMA_CSR(lch)); + w = omap_readw(OMAP_DMA_CSR_REG(lch)); /* Enable some nice interrupts. */ - omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); + omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR_REG(lch)); - w = omap_readw(OMAP_DMA_CCR(lch)); + w = omap_readw(OMAP_DMA_CCR_REG(lch)); w |= OMAP_DMA_CCR_EN; - omap_writew(w, OMAP_DMA_CCR(lch)); + omap_writew(w, OMAP_DMA_CCR_REG(lch)); dma_chan[lch].flags |= OMAP_DMA_ACTIVE; } @@ -319,12 +205,12 @@ void omap_stop_dma(int lch) int next_lch; /* Disable all interrupts on the channel */ - omap_writew(0, OMAP_DMA_CICR(lch)); + omap_writew(0, OMAP_DMA_CICR_REG(lch)); if (omap_dma_in_1510_mode()) { - w = omap_readw(OMAP_DMA_CCR(lch)); + w = omap_readw(OMAP_DMA_CCR_REG(lch)); w &= ~OMAP_DMA_CCR_EN; - omap_writew(w, OMAP_DMA_CCR(lch)); + omap_writew(w, OMAP_DMA_CCR_REG(lch)); dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; return; } @@ -335,16 +221,16 @@ void omap_stop_dma(int lch) * According to thw HW spec, enabling the STOP_LNK bit * resets the CCR_EN bit at the same time. */ - w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); + w = omap_readw(OMAP_DMA_CLNK_CTRL_REG(lch)); w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); + w = omap_writew(w, OMAP_DMA_CLNK_CTRL_REG(lch)); dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; if (next_lch != -1) { - omap_writew(0, OMAP_DMA_CICR(next_lch)); - w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch)); + omap_writew(0, OMAP_DMA_CICR_REG(next_lch)); + w = omap_readw(OMAP_DMA_CLNK_CTRL_REG(next_lch)); w |= (1 << 14); - w = omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch)); + w = omap_writew(w, OMAP_DMA_CLNK_CTRL_REG(next_lch)); dma_chan[next_lch].flags &= ~OMAP_DMA_ACTIVE; } } @@ -367,7 +253,7 @@ static int dma_handle_ch(int ch) csr = dma_chan[ch].saved_csr; dma_chan[ch].saved_csr = 0; } else - csr = omap_readw(OMAP_DMA_CSR(ch)); + csr = omap_readw(OMAP_DMA_CSR_REG(ch)); if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) { dma_chan[ch + 6].saved_csr = csr >> 7; csr &= 0x7f; @@ -453,9 +339,9 @@ int omap_request_dma(int dev_id, const char *dev_name, } /* Disable the 1510 compatibility mode and set the sync device * id. */ - omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR(free_ch)); + omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR_REG(free_ch)); } else { - omap_writew(dev_id, OMAP_DMA_CCR(free_ch)); + omap_writew(dev_id, OMAP_DMA_CCR_REG(free_ch)); } *dma_ch_out = free_ch; @@ -476,9 +362,9 @@ void omap_free_dma(int ch) spin_unlock_irqrestore(&dma_chan_lock, flags); /* Disable all DMA interrupts for the channel. */ - omap_writew(0, OMAP_DMA_CICR(ch)); + omap_writew(0, OMAP_DMA_CICR_REG(ch)); /* Make sure the DMA transfer is stopped. */ - omap_writew(0, OMAP_DMA_CCR(ch)); + omap_writew(0, OMAP_DMA_CCR_REG(ch)); } int omap_dma_in_1510_mode(void) @@ -715,19 +601,19 @@ static int __init omap_init_dma(void) enable_1510_mode = 1; } else if (cpu_is_omap1610() || cpu_is_omap5912()) { printk(KERN_INFO "OMAP DMA hardware version %d\n", - omap_readw(OMAP_DMA_HW_ID)); + omap_readw(OMAP_DMA_HW_ID_REG)); printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", - (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | omap_readw(OMAP_DMA_CAPS_0_L), - (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | omap_readw(OMAP_DMA_CAPS_1_L), - omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3), - omap_readw(OMAP_DMA_CAPS_4)); + (omap_readw(OMAP_DMA_CAPS_0_U_REG) << 16) | omap_readw(OMAP_DMA_CAPS_0_L_REG), + (omap_readw(OMAP_DMA_CAPS_1_U_REG) << 16) | omap_readw(OMAP_DMA_CAPS_1_L_REG), + omap_readw(OMAP_DMA_CAPS_2_REG), omap_readw(OMAP_DMA_CAPS_3_REG), + omap_readw(OMAP_DMA_CAPS_4_REG)); if (!enable_1510_mode) { u16 w; /* Disable OMAP 3.0/3.1 compatibility mode. */ - w = omap_readw(OMAP_DMA_GSCR); + w = omap_readw(OMAP_DMA_GSCR_REG); w |= 1 << 3; - omap_writew(w, OMAP_DMA_GSCR); + omap_writew(w, OMAP_DMA_GSCR_REG); dma_chan_count = OMAP_LOGICAL_DMA_CH_COUNT; } else dma_chan_count = 9; @@ -771,21 +657,9 @@ EXPORT_SYMBOL(omap_request_dma); EXPORT_SYMBOL(omap_free_dma); EXPORT_SYMBOL(omap_start_dma); EXPORT_SYMBOL(omap_stop_dma); - EXPORT_SYMBOL(omap_set_dma_transfer_params); -EXPORT_SYMBOL(omap_set_dma_constant_fill); -EXPORT_SYMBOL(omap_set_dma_transparent_copy); - EXPORT_SYMBOL(omap_set_dma_src_params); -EXPORT_SYMBOL(omap_set_dma_src_index); -EXPORT_SYMBOL(omap_set_dma_src_data_pack); -EXPORT_SYMBOL(omap_set_dma_src_burst_mode); - EXPORT_SYMBOL(omap_set_dma_dest_params); -EXPORT_SYMBOL(omap_set_dma_dest_index); -EXPORT_SYMBOL(omap_set_dma_dest_data_pack); -EXPORT_SYMBOL(omap_set_dma_dest_burst_mode); - EXPORT_SYMBOL(omap_dma_link_lch); EXPORT_SYMBOL(omap_dma_unlink_lch); diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c index 2f052a959..fce61a1b5 100644 --- a/arch/arm/mach-omap/gpio.c +++ b/arch/arm/mach-omap/gpio.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,7 @@ #define OMAP730_GPIO_INT_MASK 0x10 #define OMAP730_GPIO_INT_STATUS 0x14 -#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff) +#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff) struct gpio_bank { u32 base; @@ -212,12 +213,12 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) reg += OMAP730_GPIO_DIR_CONTROL; break; } - l = __raw_readl(reg); + l = omap_readl(reg); if (is_input) l |= 1 << gpio; else l &= ~(1 << gpio); - __raw_writel(l, reg); + omap_writel(l, reg); } void omap_set_gpio_direction(int gpio, int is_input) @@ -239,8 +240,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) switch (bank->method) { case METHOD_MPUIO: - reg += OMAP_MPUIO_OUTPUT; - l = __raw_readl(reg); + reg += OMAP_MPUIO_OUTPUT_REG; + l = omap_readl(reg); if (enable) l |= 1 << gpio; else @@ -248,7 +249,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) break; case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DATA_OUTPUT; - l = __raw_readl(reg); + l = omap_readl(reg); if (enable) l |= 1 << gpio; else @@ -263,7 +264,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) break; case METHOD_GPIO_730: reg += OMAP730_GPIO_DATA_OUTPUT; - l = __raw_readl(reg); + l = omap_readl(reg); if (enable) l |= 1 << gpio; else @@ -273,7 +274,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) BUG(); return; } - __raw_writel(l, reg); + omap_writel(l, reg); } void omap_set_gpio_dataout(int gpio, int enable) @@ -311,7 +312,7 @@ int omap_get_gpio_datain(int gpio) BUG(); return -1; } - return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; + return (omap_readl(reg) & (1 << get_gpio_index(gpio))) != 0; } static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) @@ -321,22 +322,22 @@ static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) switch (bank->method) { case METHOD_MPUIO: - reg += OMAP_MPUIO_GPIO_INT_EDGE; - l = __raw_readl(reg); + reg += OMAP_MPUIO_GPIO_INT_EDGE_REG; + l = omap_readl(reg); if (edge == OMAP_GPIO_RISING_EDGE) l |= 1 << gpio; else l &= ~(1 << gpio); - __raw_writel(l, reg); + omap_writel(l, reg); break; case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; - l = __raw_readl(reg); + l = omap_readl(reg); if (edge == OMAP_GPIO_RISING_EDGE) l |= 1 << gpio; else l &= ~(1 << gpio); - __raw_writel(l, reg); + omap_writel(l, reg); break; case METHOD_GPIO_1610: edge &= 0x03; @@ -345,19 +346,19 @@ static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) else reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; - l = __raw_readl(reg); + l = omap_readl(reg); l &= ~(3 << (gpio << 1)); l |= edge << (gpio << 1); - __raw_writel(l, reg); + omap_writel(l, reg); break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_CONTROL; - l = __raw_readl(reg); + l = omap_readl(reg); if (edge == OMAP_GPIO_RISING_EDGE) l |= 1 << gpio; else l &= ~(1 << gpio); - __raw_writel(l, reg); + omap_writel(l, reg); break; default: BUG(); @@ -384,11 +385,11 @@ static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio) switch (bank->method) { case METHOD_MPUIO: - l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE); + l = omap_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE_REG); return (l & (1 << gpio)) ? OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; case METHOD_GPIO_1510: - l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL); + l = omap_readl(reg + OMAP1510_GPIO_INT_CONTROL); return (l & (1 << gpio)) ? OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; case METHOD_GPIO_1610: @@ -396,9 +397,9 @@ static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio) reg += OMAP1610_GPIO_EDGE_CTRL2; else reg += OMAP1610_GPIO_EDGE_CTRL1; - return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03; + return (omap_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03; case METHOD_GPIO_730: - l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL); + l = omap_readl(reg + OMAP730_GPIO_INT_CONTROL); return (l & (1 << gpio)) ? OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; default: @@ -429,7 +430,7 @@ static void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) BUG(); return; } - __raw_writel(1 << get_gpio_index(gpio), reg); + omap_writel(1 << get_gpio_index(gpio), reg); } static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -440,7 +441,7 @@ static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) switch (bank->method) { case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; - l = __raw_readl(reg); + l = omap_readl(reg); if (enable) l &= ~(1 << gpio); else @@ -448,7 +449,7 @@ static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) break; case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; - l = __raw_readl(reg); + l = omap_readl(reg); if (enable) l &= ~(1 << gpio); else @@ -464,7 +465,7 @@ static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; - l = __raw_readl(reg); + l = omap_readl(reg); if (enable) l &= ~(1 << gpio); else @@ -474,7 +475,7 @@ static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) BUG(); return; } - __raw_writel(l, reg); + omap_writel(l, reg); } int omap_request_gpio(int gpio) @@ -499,7 +500,7 @@ int omap_request_gpio(int gpio) /* Claim the pin for the ARM */ reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; - __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); + omap_writel(omap_readl(reg) | (1 << get_gpio_index(gpio)), reg); } #endif spin_unlock(&bank->lock); @@ -563,7 +564,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; #endif for (;;) { - u32 isr = __raw_readl(isr_reg); + u32 isr = omap_readl(isr_reg); unsigned int gpio_irq; if (!isr) @@ -586,15 +587,15 @@ static void gpio_ack_irq(unsigned int irq) #ifdef CONFIG_ARCH_OMAP1510 if (bank->method == METHOD_GPIO_1510) - __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS); + omap_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS); #endif #if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) - __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1); + omap_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1); #endif #ifdef CONFIG_ARCH_OMAP730 if (bank->method == METHOD_GPIO_730) - __raw_writel(1 << (gpio & 0x1f), bank->base + OMAP730_GPIO_INT_STATUS); + omap_writel(1 << (gpio & 0x1f), bank->base + OMAP730_GPIO_INT_STATUS); #endif } @@ -691,27 +692,26 @@ static int __init _omap_gpio_init(void) bank = &gpio_bank[i]; bank->reserved_map = 0; - bank->base = IO_ADDRESS(bank->base); spin_lock_init(&bank->lock); if (bank->method == METHOD_MPUIO) { omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); } #ifdef CONFIG_ARCH_OMAP1510 if (bank->method == METHOD_GPIO_1510) { - __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); - __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); + omap_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); + omap_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); } #endif #if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) if (bank->method == METHOD_GPIO_1610) { - __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); - __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); + omap_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); + omap_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); } #endif #ifdef CONFIG_ARCH_OMAP730 if (bank->method == METHOD_GPIO_730) { - __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK); - __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS); + omap_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK); + omap_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS); gpio_count = 32; /* 730 has 32-bit GPIOs */ } @@ -730,9 +730,9 @@ static int __init _omap_gpio_init(void) } /* Enable system clock for GPIO module. - * The CAM_CLK_CTRL *is* really the right place. */ + * The CAM_CLK_CTRL_REG *is* really the right place. */ if (cpu_is_omap1610()) - omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); + omap_writel(omap_readl(ULPD_CAM_CLK_CTRL_REG) | 0x04, ULPD_CAM_CLK_CTRL_REG); return 0; } @@ -748,11 +748,8 @@ int omap_gpio_init(void) return 0; } +EXPORT_SYMBOL(omap_gpio_init); EXPORT_SYMBOL(omap_request_gpio); EXPORT_SYMBOL(omap_free_gpio); -EXPORT_SYMBOL(omap_set_gpio_direction); -EXPORT_SYMBOL(omap_set_gpio_dataout); -EXPORT_SYMBOL(omap_get_gpio_datain); -EXPORT_SYMBOL(omap_set_gpio_edge_ctrl); arch_initcall(omap_gpio_init); diff --git a/arch/arm/mach-omap/innovator1510.c b/arch/arm/mach-omap/innovator1510.c deleted file mode 100644 index 1309f9664..000000000 --- a/arch/arm/mach-omap/innovator1510.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * linux/arch/arm/mach-omap/innovator1510.c - * - * Board specific inits for OMAP-1510 Innovator - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 - * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "common.h" - -extern int omap_gpio_init(void); - -void innovator_init_irq(void) -{ - omap_init_irq(); - omap_gpio_init(); - fpga_init_irq(); -} - -static struct resource smc91x_resources[] = { - [0] = { - .start = OMAP1510P1_FPGA_ETHR_START, /* Physical */ - .end = OMAP1510P1_FPGA_ETHR_START + 16, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = INT_ETHER, - .end = INT_ETHER, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct platform_device *devices[] __initdata = { - &smc91x_device, -}; - -static void __init innovator_init(void) -{ - if (!machine_is_innovator()) - return; - - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); -} - -/* Only FPGA needs to be mapped here. All others are done with ioremap */ -static struct map_desc innovator_io_desc[] __initdata = { -{ OMAP1510P1_FPGA_BASE, OMAP1510P1_FPGA_START, OMAP1510P1_FPGA_SIZE, - MT_DEVICE }, -}; - -static void __init innovator_map_io(void) -{ - omap_map_io(); - iotable_init(innovator_io_desc, ARRAY_SIZE(innovator_io_desc)); - - /* Dump the Innovator FPGA rev early - useful info for support. */ - printk("Innovator FPGA Rev %d.%d Board Rev %d\n", - fpga_read(OMAP1510P1_FPGA_REV_HIGH), - fpga_read(OMAP1510P1_FPGA_REV_LOW), - fpga_read(OMAP1510P1_FPGA_BOARD_REV)); -} - -MACHINE_START(INNOVATOR, "TI-Innovator/OMAP1510") - MAINTAINER("MontaVista Software, Inc.") - BOOT_MEM(0x10000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x10000100) - MAPIO(innovator_map_io) - INITIRQ(innovator_init_irq) - INIT_MACHINE(innovator_init) -MACHINE_END diff --git a/arch/arm/mach-omap/innovator1610.c b/arch/arm/mach-omap/innovator1610.c deleted file mode 100644 index 4081735b0..000000000 --- a/arch/arm/mach-omap/innovator1610.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * linux/arch/arm/mach-omap/innovator1610.c - * - * This file contains Innovator-specific code. - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "common.h" - -void -innovator_init_irq(void) -{ - omap_init_irq(); -} - -static struct resource smc91x_resources[] = { - [0] = { - .start = OMAP1610_ETHR_START, /* Physical */ - .end = OMAP1610_ETHR_START + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0, /* Really GPIO 0 */ - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct platform_device *devices[] __initdata = { - &smc91x_device, -}; - -static void __init innovator_init(void) -{ - if (!machine_is_innovator()) - return; - - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); -} - -static struct map_desc innovator_io_desc[] __initdata = { -{ OMAP1610_ETHR_BASE, OMAP1610_ETHR_START, OMAP1610_ETHR_SIZE,MT_DEVICE }, -{ OMAP1610_NOR_FLASH_BASE, OMAP1610_NOR_FLASH_START, OMAP1610_NOR_FLASH_SIZE, - MT_DEVICE }, -}; - -static void __init innovator_map_io(void) -{ - omap_map_io(); - iotable_init(innovator_io_desc, ARRAY_SIZE(innovator_io_desc)); -} - -MACHINE_START(INNOVATOR, "TI-Innovator/OMAP1610") - MAINTAINER("MontaVista Software, Inc.") - BOOT_MEM(0x10000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x10000100) - MAPIO(innovator_map_io) - INITIRQ(innovator_init_irq) - INIT_MACHINE(innovator_init) -MACHINE_END - diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap/irq.c index 18da117f6..3c7cefcbd 100644 --- a/arch/arm/mach-omap/irq.c +++ b/arch/arm/mach-omap/irq.c @@ -74,9 +74,9 @@ static inline void irq_bank_writel(unsigned long value, int bank, int offset) static void omap_ack_irq(unsigned int irq) { if (irq > 31) - omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG_OFFSET); + omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG); - omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG_OFFSET); + omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG); } static void omap_mask_irq(unsigned int irq) @@ -84,9 +84,9 @@ static void omap_mask_irq(unsigned int irq) int bank = IRQ_BANK(irq); u32 l; - l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); + l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR); l |= 1 << IRQ_BIT(irq); - omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); + omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR); } static void omap_unmask_irq(unsigned int irq) @@ -94,9 +94,9 @@ static void omap_unmask_irq(unsigned int irq) int bank = IRQ_BANK(irq); u32 l; - l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); + l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR); l &= ~(1 << IRQ_BIT(irq)); - omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET); + omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR); } static void omap_mask_ack_irq(unsigned int irq) @@ -121,7 +121,7 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger) /* FIQ is only available on bank 0 interrupts */ fiq = bank ? 0 : (fiq & 0x1); val = fiq | ((priority & 0x1f) << 2) | ((trigger & 0x1) << 1); - offset = IRQ_ILR0_REG_OFFSET + IRQ_BIT(irq) * 0x4; + offset = IRQ_ILR0 + IRQ_BIT(irq) * 0x4; irq_bank_writel(val, bank, offset); } @@ -182,13 +182,13 @@ void __init omap_init_irq(void) /* Mask and clear all interrupts */ for (i = 0; i < irq_bank_count; i++) { - irq_bank_writel(~0x0, i, IRQ_MIR_REG_OFFSET); - irq_bank_writel(0x0, i, IRQ_ITR_REG_OFFSET); + irq_bank_writel(~0x0, i, IRQ_MIR); + irq_bank_writel(0x0, i, IRQ_ITR); } /* Clear any pending interrupts */ - irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET); - irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET); + irq_bank_writel(0x03, 0, IRQ_CONTROL_REG); + irq_bank_writel(0x03, 1, IRQ_CONTROL_REG); /* Install the interrupt handlers for each bank */ for (i = 0; i < irq_bank_count; i++) { diff --git a/arch/arm/mach-omap/irq.h b/arch/arm/mach-omap/irq.h deleted file mode 100644 index 8e1aa7810..000000000 --- a/arch/arm/mach-omap/irq.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * linux/arch/arm/mach-omap/irq.h - * - * OMAP specific interrupt bank definitions - * - * Copyright (C) 2004 Nokia Corporation - * Written by Tony Lindgren - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define OMAP_IRQ_TYPE710 1 -#define OMAP_IRQ_TYPE730 2 -#define OMAP_IRQ_TYPE1510 3 -#define OMAP_IRQ_TYPE1610 4 -#define OMAP_IRQ_TYPE1710 5 - -#define MAX_NR_IRQ_BANKS 4 - -#define BANK_NR_IRQS 32 - -struct omap_irq_desc { - unsigned int cpu_type; - unsigned int start_irq; - unsigned long level_map; - unsigned long base_reg; - unsigned long mask_reg; - unsigned long ack_reg; - struct irqchip *handler; -}; - -struct omap_irq_bank { - unsigned int start_irq; - unsigned long level_map; - unsigned long base_reg; - unsigned long mask_reg; - unsigned long ack_reg; - struct irqchip *handler; -}; - -static void omap_offset_ack_irq(unsigned int irq); -static void omap_offset_mask_irq(unsigned int irq); -static void omap_offset_unmask_irq(unsigned int irq); -static void omap_offset_mask_ack_irq(unsigned int irq); - -/* NOTE: These will not work if irq bank offset != 0x100 */ -#define IRQ_TO_BANK(irq) (irq >> 5) -#define IRQ_BIT(irq) (irq & 0x1f) -#define BANK_OFFSET(bank) ((bank - 1) * 0x100) - -static struct irqchip omap_offset_irq = { - .ack = omap_offset_mask_ack_irq, - .mask = omap_offset_mask_irq, - .unmask = omap_offset_unmask_irq, -}; - -/* - * OMAP-730 interrupt banks - */ -static struct omap_irq_desc omap730_bank0_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE730, - .start_irq = 0, - .level_map = 0xb3f8e22f, - .base_reg = OMAP_IH1_BASE, - .mask_reg = OMAP_IH1_BASE + IRQ_MIR, - .ack_reg = OMAP_IH1_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap730_bank1_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE730, - .start_irq = 32, - .level_map = 0xfdb9c1f2, - .base_reg = OMAP_IH2_BASE, - .mask_reg = OMAP_IH2_BASE + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap730_bank2_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE730, - .start_irq = 64, - .level_map = 0x800040f3, - .base_reg = OMAP_IH2_BASE + 0x100, - .mask_reg = OMAP_IH2_BASE + 0x100 + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, /* Not replicated */ - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -/* - * OMAP-1510 interrupt banks - */ -static struct omap_irq_desc omap1510_bank0_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1510, - .start_irq = 0, - .level_map = 0xb3febfff, - .base_reg = OMAP_IH1_BASE, - .mask_reg = OMAP_IH1_BASE + IRQ_MIR, - .ack_reg = OMAP_IH1_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap1510_bank1_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1510, - .start_irq = 32, - .level_map = 0xffbfffed, - .base_reg = OMAP_IH2_BASE, - .mask_reg = OMAP_IH2_BASE + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -/* - * OMAP-1610 interrupt banks - */ -static struct omap_irq_desc omap1610_bank0_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1610, - .start_irq = 0, - .level_map = 0xb3fefe8f, - .base_reg = OMAP_IH1_BASE, - .mask_reg = OMAP_IH1_BASE + IRQ_MIR, - .ack_reg = OMAP_IH1_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap1610_bank1_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1610, - .start_irq = 32, - .level_map = 0xfffff7ff, - .base_reg = OMAP_IH2_BASE, - .mask_reg = OMAP_IH2_BASE + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap1610_bank2_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1610, - .start_irq = 64, - .level_map = 0xffffffff, - .base_reg = OMAP_IH2_BASE + 0x100, - .mask_reg = OMAP_IH2_BASE + 0x100 + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, /* Not replicated */ - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; - -static struct omap_irq_desc omap1610_bank3_irqs __initdata = { - .cpu_type = OMAP_IRQ_TYPE1610, - .start_irq = 96, - .level_map = 0xffffffff, - .base_reg = OMAP_IH2_BASE + 0x200, - .mask_reg = OMAP_IH2_BASE + 0x200 + IRQ_MIR, - .ack_reg = OMAP_IH2_BASE + IRQ_CONTROL_REG, /* Not replicated */ - .handler = &omap_offset_irq, /* IH2 regs at 0x100 offsets */ -}; diff --git a/arch/arm/mach-omap/omap-generic.c b/arch/arm/mach-omap/omap-generic.c deleted file mode 100644 index 982830dcd..000000000 --- a/arch/arm/mach-omap/omap-generic.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * linux/arch/arm/mach-omap/generic.c - * - * Modified from innovator.c - * - * Code for generic OMAP board. Should work on many OMAP systems where - * the device drivers take care of all the necessary hardware initialization. - * Do not put any board specific code to this file; create a new machine - * type if you need custom low-level initializations. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "common.h" - -static void __init omap_generic_init_irq(void) -{ - omap_init_irq(); -} - -/* - * Muxes the serial ports on - */ -static void __init omap_early_serial_init(void) -{ - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); -} - -static void __init omap_generic_init(void) -{ - if (!machine_is_omap_generic()) - return; - - /* - * Make sure the serial ports are muxed on at this point. - * You have to mux them off in device drivers later on - * if not needed. - */ - if (cpu_is_omap1510()) { - omap_early_serial_init(); - } -} - -static void __init omap_generic_map_io(void) -{ - omap_map_io(); -} - -MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610") - MAINTAINER("Tony Lindgren ") - BOOT_MEM(0x10000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x10000100) - MAPIO(omap_generic_map_io) - INITIRQ(omap_generic_init_irq) - INIT_MACHINE(omap_generic_init) -MACHINE_END diff --git a/arch/arm/mach-omap/omap-perseus2.c b/arch/arm/mach-omap/omap-perseus2.c deleted file mode 100644 index ec05093c9..000000000 --- a/arch/arm/mach-omap/omap-perseus2.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * linux/arch/arm/mach-omap/omap-perseus2.c - * - * Modified from omap-generic.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include "common.h" - -void omap_perseus2_init_irq(void) -{ - omap_init_irq(); -} - -static struct resource smc91x_resources[] = { - [0] = { - .start = OMAP730_FPGA_ETHR_START, /* Physical */ - .end = OMAP730_FPGA_ETHR_START + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0, - .end = 0, - .flags = INT_ETHER, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct platform_device *devices[] __initdata = { - &smc91x_device, -}; - -static void __init omap_perseus2_init(void) -{ - if (!machine_is_omap_perseus2()) - return; - - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); -} - -/* Only FPGA needs to be mapped here. All others are done with ioremap */ -static struct map_desc omap_perseus2_io_desc[] __initdata = { - {OMAP730_FPGA_BASE, OMAP730_FPGA_START, OMAP730_FPGA_SIZE, - MT_DEVICE}, -}; - -static void __init omap_perseus2_map_io(void) -{ - omap_map_io(); - iotable_init(omap_perseus2_io_desc, - ARRAY_SIZE(omap_perseus2_io_desc)); - - /* Early, board-dependent init */ - - /* - * Hold GSM Reset until needed - */ - *DSP_M_CTL &= ~1; - - /* - * UARTs -> done automagically by 8250 driver - */ - - /* - * CSx timings, GPIO Mux ... setup - */ - - /* Flash: CS0 timings setup */ - *((volatile __u32 *) OMAP_FLASH_CFG_0) = 0x0000fff3; - *((volatile __u32 *) OMAP_FLASH_ACFG_0) = 0x00000088; - - /* - * Ethernet support trough the debug board - * CS1 timings setup - */ - *((volatile __u32 *) OMAP_FLASH_CFG_1) = 0x0000fff3; - *((volatile __u32 *) OMAP_FLASH_ACFG_1) = 0x00000000; - - /* - * Configure MPU_EXT_NIRQ IO in IO_CONF9 register, - * It is used as the Ethernet controller interrupt - */ - *((volatile __u32 *) PERSEUS2_IO_CONF_9) &= 0x1FFFFFFF; -} - -MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") - MAINTAINER("Kevin Hilman ") - BOOT_MEM(0x10000000, 0xe0000000, 0xe0000000) - BOOT_PARAMS(0x10000100) - MAPIO(omap_perseus2_map_io) - INITIRQ(omap_perseus2_init_irq) - INIT_MACHINE(omap_perseus2_init) -MACHINE_END diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index d394f6957..a9648c82f 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -1,9 +1,9 @@ -if ARCH_PXA menu "Intel PXA2xx Implementations" choice prompt "Select target board" + depends on ARCH_PXA config ARCH_LUBBOCK bool "Intel DBPXA250 Development Platform" @@ -32,4 +32,3 @@ config PXA27x help Select code specific to PXA27x variants -endif diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c index 0e083b34e..6d1de79ab 100644 --- a/arch/arm/mach-pxa/leds-lubbock.c +++ b/arch/arm/mach-pxa/leds-lubbock.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "leds.h" diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 023c5e9f3..da026d437 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 245e25b08..de6b7e257 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -19,7 +19,6 @@ #include #include #include -#include /* diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index b71f89e11..2eff1396a 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -1,9 +1,8 @@ -if ARCH_S3C2410 - menu "S3C2410 Implementations" config ARCH_BAST bool "Simtec Electronics BAST (EB2410ITX)" + depends on ARCH_S3C2410 help Say Y here if you are using the Simtec Electronics EB2410ITX development board (also known as BAST) @@ -12,21 +11,22 @@ config ARCH_BAST config ARCH_H1940 bool "IPAQ H1940" + depends on ARCH_S3C2410 help Say Y here if you are using the HP IPAQ H1940 . config ARCH_SMDK2410 bool "SMDK2410/A9M2410" + depends on ARCH_S3C2410 help Say Y here if you are using the SMDK2410 or the derived module A9M2410 config MACH_VR1000 bool "Simtec VR1000" + depends on ARCH_S3C2410 help Say Y here if you are using the Simtec VR1000 board. endmenu - -endif diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c index be5dd86f4..6648d462e 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/arch/arm/mach-sa1100/cpu-sa1100.c @@ -230,9 +230,8 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver sa1100_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = (CPUFREQ_PANIC_OUTOFSYNC | + CPUFREQ_PANIC_RESUME_OUTOFSYNC), .verify = sa11x0_verify_speed, .target = sa1100_target, .get = sa11x0_getspeed, diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c index 62a4dbcce..b17ca12a9 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/arch/arm/mach-sa1100/cpu-sa1110.c @@ -329,9 +329,8 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver sa1110_driver = { - .flags = CPUFREQ_STICKY | - CPUFREQ_PANIC_OUTOFSYNC | - CPUFREQ_PANIC_RESUME_OUTOFSYNC, + .flags = (CPUFREQ_PANIC_OUTOFSYNC | + CPUFREQ_PANIC_RESUME_OUTOFSYNC), .verify = sa11x0_verify_speed, .target = sa1110_target, .get = sa11x0_getspeed, diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c new file mode 100644 index 000000000..c1f91fad8 --- /dev/null +++ b/arch/arm/mach-versatile/clock.c @@ -0,0 +1,146 @@ +/* + * linux/arch/arm/mach-versatile/clock.c + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "clock.h" + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +int clk_use(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_use); + +void clk_unuse(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_unuse); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EIO; +#if 0 // Not yet + if (clk->setvco) { + struct icst525_vco vco; + + vco = icst525_khz_to_vco(clk->params, rate); + clk->rate = icst525_khz(clk->params, vco); + + printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", + clk->name, vco.s, vco.r, vco.v); + + clk->setvco(clk, vco); + ret = 0; + } +#endif + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +/* + * These are fixed clocks. + */ +static struct clk kmi_clk = { + .name = "KMIREFCLK", + .rate = 24000000, +}; + +static struct clk uart_clk = { + .name = "UARTCLK", + .rate = 24000000, +}; + +static struct clk mmci_clk = { + .name = "MCLK", + .rate = 33000000, +}; + +int clk_register(struct clk *clk) +{ + down(&clocks_sem); + list_add(&clk->node, &clocks); + up(&clocks_sem); + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + down(&clocks_sem); + list_del(&clk->node); + up(&clocks_sem); +} +EXPORT_SYMBOL(clk_unregister); + +static int __init clk_init(void) +{ + clk_register(&kmi_clk); + clk_register(&uart_clk); + clk_register(&mmci_clk); + return 0; +} +arch_initcall(clk_init); diff --git a/arch/arm/mach-versatile/clock.h b/arch/arm/mach-versatile/clock.h new file mode 100644 index 000000000..12e68ecde --- /dev/null +++ b/arch/arm/mach-versatile/clock.h @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-versatile/clock.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +struct module; +struct icst525_params; + +struct clk { + struct list_head node; + unsigned long rate; + struct module *owner; + const char *name; + const struct icst525_params *params; + void *data; + void (*setvco)(struct clk *, struct icst525_vco vco); +}; + +int clk_register(struct clk *clk); +void clk_unregister(struct clk *clk); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index d03940c1b..81485b5b4 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include #include #include @@ -76,7 +75,7 @@ no_pmd: return 0; } -static void __flush_dcache_page(struct page *page) +void __flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); struct mm_struct *mm = current->active_mm; @@ -112,17 +111,6 @@ static void __flush_dcache_page(struct page *page) flush_dcache_mmap_unlock(mapping); } -void flush_dcache_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); - else - __flush_dcache_page(page); -} -EXPORT_SYMBOL(flush_dcache_page); - static void make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) { diff --git a/arch/arm/vfp/Makefile b/arch/arm/vfp/Makefile new file mode 100644 index 000000000..afabac31d --- /dev/null +++ b/arch/arm/vfp/Makefile @@ -0,0 +1,12 @@ +# +# linux/arch/arm/vfp/Makefile +# +# Copyright (C) 2001 ARM Limited +# + +# EXTRA_CFLAGS := -DDEBUG +# EXTRA_AFLAGS := -DDEBUG + +obj-y += vfp.o + +vfp-$(CONFIG_VFP) += entry.o vfpmodule.o vfphw.o vfpsingle.o vfpdouble.o diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S new file mode 100644 index 000000000..e9e583b2b --- /dev/null +++ b/arch/arm/vfp/entry.S @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/vfp/entry.S + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Basic entry code, called from the kernel's undefined instruction trap. + * r0 = faulted instruction + * r5 = faulted PC+4 + * r9 = successful return + * r10 = thread_info structure + * lr = failure return + */ +#include +#include +#include +#include + + .globl do_vfp +do_vfp: + ldr r4, .LCvfp + add r10, r10, #TI_VFPSTATE @ r10 = workspace + ldr pc, [r4] @ call VFP entry point + +.LCvfp: + .word vfp_vector + +@ This code is called if the VFP does not exist. It needs to flag the +@ failure to the VFP initialisation code. + + __INIT + .globl vfp_testing_entry +vfp_testing_entry: + ldr r0, VFP_arch_address + str r5, [r0] @ known non-zero value + mov pc, r9 @ we have handled the fault + +VFP_arch_address: + .word VFP_arch + + __FINIT diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h new file mode 100644 index 000000000..98e0f526e --- /dev/null +++ b/arch/arm/vfp/vfp.h @@ -0,0 +1,333 @@ +/* + * linux/arch/arm/vfp/vfp.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) +{ + if (shift) { + if (shift < 32) + val = val >> shift | ((val << (32 - shift)) != 0); + else + val = val != 0; + } + return val; +} + +static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) +{ + if (shift) { + if (shift < 64) + val = val >> shift | ((val << (64 - shift)) != 0); + else + val = val != 0; + } + return val; +} + +static inline u32 vfp_hi64to32jamming(u64 val) +{ + u32 v; + + asm( + "cmp %Q1, #1 @ vfp_hi64to32jamming\n\t" + "movcc %0, %R1\n\t" + "orrcs %0, %R1, #1" + : "=r" (v) : "r" (val) : "cc"); + + return v; +} + +static inline void add128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml) +{ + asm( "adds %Q0, %Q2, %Q4\n\t" + "adcs %R0, %R2, %R4\n\t" + "adcs %Q1, %Q3, %Q5\n\t" + "adc %R1, %R3, %R5" + : "=r" (nl), "=r" (nh) + : "0" (nl), "1" (nh), "r" (ml), "r" (mh) + : "cc"); + *resh = nh; + *resl = nl; +} + +static inline void sub128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml) +{ + asm( "subs %Q0, %Q2, %Q4\n\t" + "sbcs %R0, %R2, %R4\n\t" + "sbcs %Q1, %Q3, %Q5\n\t" + "sbc %R1, %R3, %R5\n\t" + : "=r" (nl), "=r" (nh) + : "0" (nl), "1" (nh), "r" (ml), "r" (mh) + : "cc"); + *resh = nh; + *resl = nl; +} + +static inline void mul64to128(u64 *resh, u64 *resl, u64 n, u64 m) +{ + u32 nh, nl, mh, ml; + u64 rh, rma, rmb, rl; + + nl = n; + ml = m; + rl = (u64)nl * ml; + + nh = n >> 32; + rma = (u64)nh * ml; + + mh = m >> 32; + rmb = (u64)nl * mh; + rma += rmb; + + rh = (u64)nh * mh; + rh += ((u64)(rma < rmb) << 32) + (rma >> 32); + + rma <<= 32; + rl += rma; + rh += (rl < rma); + + *resl = rl; + *resh = rh; +} + +static inline void shift64left(u64 *resh, u64 *resl, u64 n) +{ + *resh = n >> 63; + *resl = n << 1; +} + +static inline u64 vfp_hi64multiply64(u64 n, u64 m) +{ + u64 rh, rl; + mul64to128(&rh, &rl, n, m); + return rh | (rl != 0); +} + +static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) +{ + u64 mh, ml, remh, reml, termh, terml, z; + + if (nh >= m) + return ~0ULL; + mh = m >> 32; + z = (mh << 32 <= nh) ? 0xffffffff00000000ULL : (nh / mh) << 32; + mul64to128(&termh, &terml, m, z); + sub128(&remh, &reml, nh, nl, termh, terml); + ml = m << 32; + while ((s64)remh < 0) { + z -= 0x100000000ULL; + add128(&remh, &reml, remh, reml, mh, ml); + } + remh = (remh << 32) | (reml >> 32); + z |= (mh << 32 <= remh) ? 0xffffffff : remh / mh; + return z; +} + +/* + * Operations on unpacked elements + */ +#define vfp_sign_negate(sign) (sign ^ 0x8000) + +/* + * Single-precision + */ +struct vfp_single { + s16 exponent; + u16 sign; + u32 significand; +}; + +extern s32 vfp_get_float(unsigned int reg); +extern void vfp_put_float(unsigned int reg, s32 val); + +/* + * VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa + * VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent + * VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand + * which are not propagated to the float upon packing. + */ +#define VFP_SINGLE_MANTISSA_BITS (23) +#define VFP_SINGLE_EXPONENT_BITS (8) +#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) +#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) + +/* + * The bit in an unpacked float which indicates that it is a quiet NaN + */ +#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS)) + +/* + * Operations on packed single-precision numbers + */ +#define vfp_single_packed_sign(v) ((v) & 0x80000000) +#define vfp_single_packed_negate(v) ((v) ^ 0x80000000) +#define vfp_single_packed_abs(v) ((v) & ~0x80000000) +#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) +#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) + +/* + * Unpack a single-precision float. Note that this returns the magnitude + * of the single-precision float mantissa with the 1. if necessary, + * aligned to bit 30. + */ +static inline void vfp_single_unpack(struct vfp_single *s, s32 val) +{ + u32 significand; + + s->sign = vfp_single_packed_sign(val) >> 16, + s->exponent = vfp_single_packed_exponent(val); + + significand = (u32) val; + significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; + if (s->exponent && s->exponent != 255) + significand |= 0x40000000; + s->significand = significand; +} + +/* + * Re-pack a single-precision float. This assumes that the float is + * already normalised such that the MSB is bit 30, _not_ bit 31. + */ +static inline s32 vfp_single_pack(struct vfp_single *s) +{ + u32 val; + val = (s->sign << 16) + + (s->exponent << VFP_SINGLE_MANTISSA_BITS) + + (s->significand >> VFP_SINGLE_LOW_BITS); + return (s32)val; +} + +#define VFP_NUMBER (1<<0) +#define VFP_ZERO (1<<1) +#define VFP_DENORMAL (1<<2) +#define VFP_INFINITY (1<<3) +#define VFP_NAN (1<<4) +#define VFP_NAN_SIGNAL (1<<5) + +#define VFP_QNAN (VFP_NAN) +#define VFP_SNAN (VFP_NAN|VFP_NAN_SIGNAL) + +static inline int vfp_single_type(struct vfp_single *s) +{ + int type = VFP_NUMBER; + if (s->exponent == 255) { + if (s->significand == 0) + type = VFP_INFINITY; + else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) + type = VFP_QNAN; + else + type = VFP_SNAN; + } else if (s->exponent == 0) { + if (s->significand == 0) + type |= VFP_ZERO; + else + type |= VFP_DENORMAL; + } + return type; +} + +#ifndef DEBUG +#define vfp_single_normaliseround(sd,vsd,fpscr,except,func) __vfp_single_normaliseround(sd,vsd,fpscr,except) +u32 __vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions); +#else +u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func); +#endif + +/* + * Double-precision + */ +struct vfp_double { + s16 exponent; + u16 sign; + u64 significand; +}; + +extern u64 vfp_get_double(unsigned int reg); +extern void vfp_put_double(unsigned int reg, u64 val); + +#define VFP_DOUBLE_MANTISSA_BITS (52) +#define VFP_DOUBLE_EXPONENT_BITS (11) +#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) +#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) + +/* + * The bit in an unpacked double which indicates that it is a quiet NaN + */ +#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) + +/* + * Operations on packed single-precision numbers + */ +#define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) +#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) +#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) +#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) +#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) + +/* + * Unpack a double-precision float. Note that this returns the magnitude + * of the double-precision float mantissa with the 1. if necessary, + * aligned to bit 62. + */ +static inline void vfp_double_unpack(struct vfp_double *s, s64 val) +{ + u64 significand; + + s->sign = vfp_double_packed_sign(val) >> 48; + s->exponent = vfp_double_packed_exponent(val); + + significand = (u64) val; + significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; + if (s->exponent && s->exponent != 2047) + significand |= (1ULL << 62); + s->significand = significand; +} + +/* + * Re-pack a double-precision float. This assumes that the float is + * already normalised such that the MSB is bit 30, _not_ bit 31. + */ +static inline s64 vfp_double_pack(struct vfp_double *s) +{ + u64 val; + val = ((u64)s->sign << 48) + + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + + (s->significand >> VFP_DOUBLE_LOW_BITS); + return (s64)val; +} + +static inline int vfp_double_type(struct vfp_double *s) +{ + int type = VFP_NUMBER; + if (s->exponent == 2047) { + if (s->significand == 0) + type = VFP_INFINITY; + else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) + type = VFP_QNAN; + else + type = VFP_SNAN; + } else if (s->exponent == 0) { + if (s->significand == 0) + type |= VFP_ZERO; + else + type |= VFP_DENORMAL; + } + return type; +} + +u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); + +/* + * System registers + */ +extern u32 vfp_get_sys(unsigned int reg); +extern void vfp_put_sys(unsigned int reg, u32 val); + +u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c new file mode 100644 index 000000000..54649c1ee --- /dev/null +++ b/arch/arm/vfp/vfpdouble.c @@ -0,0 +1,1186 @@ +/* + * linux/arch/arm/vfp/vfpdouble.c + * + * This code is derived in part from John R. Housers softfloat library, which + * carries the following notice: + * + * =========================================================================== + * This C source file is part of the SoftFloat IEC/IEEE Floating-point + * Arithmetic Package, Release 2. + * + * Written by John R. Hauser. This work was made possible in part by the + * International Computer Science Institute, located at Suite 600, 1947 Center + * Street, Berkeley, California 94704. Funding was partially provided by the + * National Science Foundation under grant MIP-9311980. The original version + * of this code was written as part of a project to build a fixed-point vector + * processor in collaboration with the University of California at Berkeley, + * overseen by Profs. Nelson Morgan and John Wawrzynek. More information + * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ + * arithmetic/softfloat.html'. + * + * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort + * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT + * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO + * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY + * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + * + * Derivative works are acceptable, even for commercial purposes, so long as + * (1) they include prominent notice that the work is derivative, and (2) they + * include prominent notice akin to these three paragraphs for those parts of + * this code that are retained. + * =========================================================================== + */ +#include +#include +#include +#include + +#include "vfpinstr.h" +#include "vfp.h" + +static struct vfp_double vfp_double_default_qnan = { + .exponent = 2047, + .sign = 0, + .significand = VFP_DOUBLE_SIGNIFICAND_QNAN, +}; + +static void vfp_double_dump(const char *str, struct vfp_double *d) +{ + pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", + str, d->sign != 0, d->exponent, d->significand); +} + +static void vfp_double_normalise_denormal(struct vfp_double *vd) +{ + int bits = 31 - fls(vd->significand >> 32); + if (bits == 31) + bits = 62 - fls(vd->significand); + + vfp_double_dump("normalise_denormal: in", vd); + + if (bits) { + vd->exponent -= bits - 1; + vd->significand <<= bits; + } + + vfp_double_dump("normalise_denormal: out", vd); +} + +u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) +{ + u64 significand, incr; + int exponent, shift, underflow; + u32 rmode; + + vfp_double_dump("pack: in", vd); + + /* + * Infinities and NaNs are a special case. + */ + if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vd->significand == 0) { + vd->exponent = 0; + goto pack; + } + + exponent = vd->exponent; + significand = vd->significand; + + shift = 32 - fls(significand >> 32); + if (shift == 32) + shift = 64 - fls(significand); + if (shift) { + exponent -= shift; + significand <<= shift; + } + +#ifdef DEBUG + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: normalised", vd); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright64jamming(significand, -exponent); + exponent = 0; +#ifdef DEBUG + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: tiny number", vd); +#endif + if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1ULL << VFP_DOUBLE_LOW_BITS; + if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) + incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08llx\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#ifdef DEBUG + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: overflow", vd); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 2046) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vd->exponent = 2045; + vd->significand = 0x7fffffffffffffffULL; + } else { + vd->exponent = 2047; /* infinity */ + vd->significand = 0; + } + } else { + if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x8000000000000000ULL) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vd->exponent = exponent; + vd->significand = significand >> 1; + } + + pack: + vfp_double_dump("pack: final", vd); + { + s64 d = vfp_double_pack(vd); + pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, + dd, d, exceptions); + vfp_put_double(dd, d); + } + return exceptions; +} + +/* + * Propagate the NaN, setting exceptions if it is signalling. + * 'n' is always a NaN. 'm' may be a number, NaN or infinity. + */ +static u32 +vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + struct vfp_double *nan; + int tn, tm = 0; + + tn = vfp_double_type(vdn); + + if (vdm) + tm = vfp_double_type(vdm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_double_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vdn; + else + nan = vdm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + } + + *vdd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : 0x100; +} + +/* + * Extended operations + */ +static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr) +{ + vfp_put_double(dd, vfp_double_packed_abs(vfp_get_double(dm))); + return 0; +} + +static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr) +{ + vfp_put_double(dd, vfp_get_double(dm)); + return 0; +} + +static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr) +{ + vfp_put_double(dd, vfp_double_packed_negate(vfp_get_double(dm))); + return 0; +} + +static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm, vdd; + int ret, tm; + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + tm = vfp_double_type(&vdm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + struct vfp_double *vdp = &vdd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); + else if (vdm.sign == 0) { + sqrt_copy: + vdp = &vdm; + ret = 0; + } else { + sqrt_invalid: + vdp = &vfp_double_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_double(dd, vfp_double_pack(vdp)); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * sqrt(<0) = invalid + */ + if (vdm.sign) + goto sqrt_invalid; + + vfp_double_dump("sqrt", &vdm); + + /* + * Estimate the square root. + */ + vdd.sign = 0; + vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; + vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; + + vfp_double_dump("sqrt estimate1", &vdd); + + vdm.significand >>= 1 + (vdm.exponent & 1); + vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); + + vfp_double_dump("sqrt estimate2", &vdd); + + /* + * And now adjust. + */ + if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { + if (vdd.significand < 2) { + vdd.significand = ~0ULL; + } else { + u64 termh, terml, remh, reml; + vdm.significand <<= 2; + mul64to128(&termh, &terml, vdd.significand, vdd.significand); + sub128(&remh, &reml, vdm.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + shift64left(&termh, &terml, vdd.significand); + terml |= 1; + add128(&remh, &reml, remh, reml, termh, terml); + } + vdd.significand |= (remh | reml) != 0; + } + } + vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); + + return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fsqrt"); +} + +/* + * Equal := ZC + * Less than := N + * Greater than := C + * Unordered := CV + */ +static u32 vfp_compare(int dd, int signal_on_qnan, int dm, u32 fpscr) +{ + s64 d, m; + u32 ret = 0; + + m = vfp_get_double(dm); + if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + d = vfp_get_double(dd); + if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + if (d == m || vfp_double_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + } else if (vfp_double_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_double_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + + return ret; +} + +static u32 vfp_double_fcmp(int dd, int unused, int dm, u32 fpscr) +{ + return vfp_compare(dd, 0, dm, fpscr); +} + +static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr) +{ + return vfp_compare(dd, 1, dm, fpscr); +} + +static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr) +{ + return vfp_compare(dd, 0, -1, fpscr); +} + +static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr) +{ + return vfp_compare(dd, 1, -1, fpscr); +} + +static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + struct vfp_single vsd; + int tm; + u32 exceptions = 0; + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + + tm = vfp_double_type(&vdm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + vsd.sign = vdm.sign; + vsd.significand = vfp_hi64to32jamming(vdm.significand); + + /* + * If we have an infinity or a NaN, the exponent must be 255 + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vsd.exponent = 255; + if (tm & VFP_NAN) + vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vsd.exponent = 0; + else + vsd.exponent = vdm.exponent - (1023 - 127); + + return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fcvts"); + + pack_nan: + vfp_put_float(sd, vfp_single_pack(&vsd)); + return exceptions; +} + +static u32 vfp_double_fuito(int dd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 m = vfp_get_float(dm); + + vdm.sign = 0; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = (u64)m; + + return vfp_double_normaliseround(dd, &vdm, fpscr, 0, "fuito"); +} + +static u32 vfp_double_fsito(int dd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 m = vfp_get_float(dm); + + vdm.sign = (m & 0x80000000) >> 16; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = vdm.sign ? -m : m; + + return vfp_double_normaliseround(dd, &vdm, fpscr, 0, "fsito"); +} + +static u32 vfp_double_ftoui(int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + + /* + * Do we have a denormalised number? + */ + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vdm.sign = 0; + + if (vdm.exponent >= 1023 + 32) { + d = vdm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; + u64 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (vdm.significand << 1) >> shift; + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(sd, d); + + return exceptions; +} + +static u32 vfp_double_ftouiz(int sd, int unused, int dm, u32 fpscr) +{ + return vfp_double_ftoui(sd, unused, dm, FPSCR_ROUND_TOZERO); +} + +static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + vfp_double_dump("VDM", &vdm); + + /* + * Do we have denormalised number? + */ + if (vfp_double_type(&vdm) & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (vdm.exponent >= 1023 + 32) { + d = 0x7fffffff; + if (vdm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; /* 58 */ + u64 rem, incr = 0; + + d = (vdm.significand << 1) >> shift; + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > 0x7fffffff + (vdm.sign != 0)) { + d = 0x7fffffff + (vdm.sign != 0); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vdm.sign) + d = -d; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(sd, (s32)d); + + return exceptions; +} + +static u32 vfp_double_ftosiz(int dd, int unused, int dm, u32 fpscr) +{ + return vfp_double_ftosi(dd, unused, dm, FPSCR_ROUND_TOZERO); +} + + +static u32 (* const fop_extfns[32])(int dd, int unused, int dm, u32 fpscr) = { + [FEXT_TO_IDX(FEXT_FCPY)] = vfp_double_fcpy, + [FEXT_TO_IDX(FEXT_FABS)] = vfp_double_fabs, + [FEXT_TO_IDX(FEXT_FNEG)] = vfp_double_fneg, + [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_double_fsqrt, + [FEXT_TO_IDX(FEXT_FCMP)] = vfp_double_fcmp, + [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_double_fcmpe, + [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_double_fcmpz, + [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_double_fcmpez, + [FEXT_TO_IDX(FEXT_FCVT)] = vfp_double_fcvts, + [FEXT_TO_IDX(FEXT_FUITO)] = vfp_double_fuito, + [FEXT_TO_IDX(FEXT_FSITO)] = vfp_double_fsito, + [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_double_ftoui, + [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_double_ftouiz, + [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_double_ftosi, + [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_double_ftosiz, +}; + + + + +static u32 +vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + struct vfp_double *vdp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_double_type(vdn); + tm = vfp_double_type(vdm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vdn->sign ^ vdm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vdp = &vfp_double_default_qnan; + } else { + /* + * same signs -> valid + */ + vdp = vdn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vdp = vdn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + } + *vdd = *vdp; + return exceptions; +} + +static u32 +vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + u32 exp_diff; + u64 m_sig; + + if (vdn->significand & (1ULL << 63) || + vdm->significand & (1ULL << 63)) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vdn->exponent == 2047) + return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); + + /* + * We have two proper numbers, where 'vdn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vdd = *vdn; + + /* + * Align 'm' with the result. + */ + exp_diff = vdn->exponent - vdm->exponent; + m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vdn->sign ^ vdm->sign) { + m_sig = vdn->significand - m_sig; + if ((s64)m_sig < 0) { + vdd->sign = vfp_sign_negate(vdd->sign); + m_sig = -m_sig; + } + } else { + m_sig += vdn->significand; + } + vdd->significand = m_sig; + + return 0; +} + +static u32 +vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vdd->sign = vdn->sign ^ vdm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vdn->exponent == 2047) { + if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + if ((vdm->exponent | vdm->significand) == 0) { + *vdd = vfp_double_default_qnan; + return FPSCR_IOC; + } + vdd->exponent = vdn->exponent; + vdd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vdm->exponent | vdm->significand) == 0) { + vdd->exponent = 0; + vdd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason + * as the addition case - though this time we have +1 from + * each input operand. + */ + vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; + vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); + + vfp_double_dump("VDD", vdd); + return 0; +} + +#define NEG_MULTIPLY (1 << 0) +#define NEG_SUBTRACT (1 << 1) + +static u32 +vfp_double_multiply_accumulate(int dd, int dn, int dm, u32 fpscr, u32 negate, char *func) +{ + struct vfp_double vdd, vdp, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); + if (negate & NEG_MULTIPLY) + vdp.sign = vfp_sign_negate(vdp.sign); + + vfp_double_unpack(&vdn, vfp_get_double(dd)); + if (negate & NEG_SUBTRACT) + vdn.sign = vfp_sign_negate(vdn.sign); + + exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); + + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, func); +} + +/* + * Standard operations + */ + +/* + * sd = sd + (sn * sm) + */ +static u32 vfp_double_fmac(int dd, int dn, int dm, u32 fpscr) +{ + return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, 0, "fmac"); +} + +/* + * sd = sd - (sn * sm) + */ +static u32 vfp_double_fnmac(int dd, int dn, int dm, u32 fpscr) +{ + return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); +} + +/* + * sd = -sd + (sn * sm) + */ +static u32 vfp_double_fmsc(int dd, int dn, int dm, u32 fpscr) +{ + return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); +} + +/* + * sd = -sd - (sn * sm) + */ +static u32 vfp_double_fnmsc(int dd, int dn, int dm, u32 fpscr) +{ + return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); +} + +/* + * sd = sn * sm + */ +static u32 vfp_double_fmul(int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fmul"); +} + +/* + * sd = -(sn * sm) + */ +static u32 vfp_double_fnmul(int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + vdd.sign = vfp_sign_negate(vdd.sign); + + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fnmul"); +} + +/* + * sd = sn + sm + */ +static u32 vfp_double_fadd(int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fadd"); +} + +/* + * sd = sn - sm + */ +static u32 vfp_double_fsub(int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + /* + * Subtraction is like addition, but with a negated operand. + */ + vdm.sign = vfp_sign_negate(vdm.sign); + + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fsub"); +} + +/* + * sd = sn / sm + */ +static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions = 0; + int tm, tn; + + vfp_double_unpack(&vdn, vfp_get_double(dn)); + vfp_double_unpack(&vdm, vfp_get_double(dm)); + + vdd.sign = vdn.sign ^ vdm.sign; + + tn = vfp_double_type(&vdn); + tm = vfp_double_type(&vdm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vdn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vdm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exceptions + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdn); + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; + vdm.significand <<= 1; + if (vdm.significand <= (2 * vdn.significand)) { + vdn.significand >>= 1; + vdd.exponent++; + } + vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); + if ((vdd.significand & 0x1ff) <= 2) { + u64 termh, terml, remh, reml; + mul64to128(&termh, &terml, vdm.significand, vdd.significand); + sub128(&remh, &reml, vdn.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + add128(&remh, &reml, remh, reml, 0, vdm.significand); + } + vdd.significand |= (reml != 0); + } + return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fdiv"); + + vdn_nan: + exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); + pack: + vfp_put_double(dd, vfp_double_pack(&vdd)); + return exceptions; + + vdm_nan: + exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); + goto pack; + + zero: + vdd.exponent = 0; + vdd.significand = 0; + goto pack; + + divzero: + exceptions = FPSCR_DZC; + infinity: + vdd.exponent = 2047; + vdd.significand = 0; + goto pack; + + invalid: + vfp_put_double(dd, vfp_double_pack(&vfp_double_default_qnan)); + return FPSCR_IOC; +} + +static u32 (* const fop_fns[16])(int dd, int dn, int dm, u32 fpscr) = { + [FOP_TO_IDX(FOP_FMAC)] = vfp_double_fmac, + [FOP_TO_IDX(FOP_FNMAC)] = vfp_double_fnmac, + [FOP_TO_IDX(FOP_FMSC)] = vfp_double_fmsc, + [FOP_TO_IDX(FOP_FNMSC)] = vfp_double_fnmsc, + [FOP_TO_IDX(FOP_FMUL)] = vfp_double_fmul, + [FOP_TO_IDX(FOP_FNMUL)] = vfp_double_fnmul, + [FOP_TO_IDX(FOP_FADD)] = vfp_double_fadd, + [FOP_TO_IDX(FOP_FSUB)] = vfp_double_fsub, + [FOP_TO_IDX(FOP_FDIV)] = vfp_double_fdiv, +}; + +#define FREG_BANK(x) ((x) & 0x0c) +#define FREG_IDX(x) ((x) & 3) + +u32 vfp_double_cpdo(u32 inst, u32 fpscr) +{ + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int dd = vfp_get_sd(inst); + unsigned int dn = vfp_get_sn(inst); + unsigned int dm = vfp_get_sm(inst); + unsigned int vecitr, veclen, vecstride; + u32 (*fop)(int, int, s32, u32); + + veclen = fpscr & FPSCR_LENGTH_MASK; + vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2; + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if (FREG_BANK(dd) == 0) + veclen = 0; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + fop = (op == FOP_EXT) ? fop_extfns[dn] : fop_fns[FOP_TO_IDX(op)]; + if (!fop) + goto invalid; + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + u32 except; + + if (op == FOP_EXT) + pr_debug("VFP: itr%d (d%u.%u) = op[%u] (d%u.%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + dd >> 1, dd & 1, dn, + dm >> 1, dm & 1); + else + pr_debug("VFP: itr%d (d%u.%u) = (d%u.%u) op[%u] (d%u.%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + dd >> 1, dd & 1, + dn >> 1, dn & 1, + FOP_TO_IDX(op), + dm >> 1, dm & 1); + + except = fop(dd, dn, dm, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * This ensures that comparisons only operate on scalars; + * comparisons always return with one FPSCR status bit set. + */ + if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) + break; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + + dd = FREG_BANK(dd) + ((FREG_IDX(dd) + vecstride) & 6); + dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6); + if (FREG_BANK(dm) != 0) + dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 6); + } + return exceptions; + + invalid: + return ~0; +} diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S new file mode 100644 index 000000000..ad3626103 --- /dev/null +++ b/arch/arm/vfp/vfphw.S @@ -0,0 +1,210 @@ +/* + * linux/arch/arm/vfp/vfphw.S + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This code is called from the kernel's undefined instruction trap. + * r9 holds the return address for successful handling. + * lr holds the return address for unrecognised instructions. + * r10 points at the start of the private FP workspace in the thread structure + * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h) + */ +#include +#include +#include "../kernel/entry-header.S" + + .macro DBGSTR, str +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + add r0, pc, #4 + bl printk + b 1f + .asciz "<7>VFP: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + + .macro DBGSTR1, str, arg +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + mov r1, \arg + add r0, pc, #4 + bl printk + b 1f + .asciz "<7>VFP: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + + .macro DBGSTR3, str, arg1, arg2, arg3 +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + mov r3, \arg3 + mov r2, \arg2 + mov r1, \arg1 + add r0, pc, #4 + bl printk + b 1f + .asciz "<7>VFP: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + + +@ VFP hardware support entry point. +@ +@ r0 = faulted instruction +@ r5 = faulted PC+4 +@ r9 = successful return +@ r10 = vfp_state union +@ lr = failure return + + .globl vfp_support_entry +vfp_support_entry: + DBGSTR3 "instr %08x pc %08x state %p", r0, r5, r10 + + VFPFMRX r1, FPEXC @ Is the VFP enabled? + DBGSTR1 "fpexc %08x", r1 + tst r1, #FPEXC_ENABLE + bne look_for_VFP_exceptions @ VFP is already enabled + + DBGSTR1 "enable %x", r10 + ldr r3, last_VFP_context_address + orr r1, r1, #FPEXC_ENABLE @ user FPEXC has the enable bit set + ldr r4, [r3] @ last_VFP_context pointer + bic r2, r1, #FPEXC_EXCEPTION @ make sure exceptions are disabled + cmp r4, r10 + beq check_for_exception @ we are returning to the same + @ process, so the registers are + @ still there. In this case, we do + @ not want to drop a pending exception. + + VFPFMXR FPEXC, r2 @ enable VFP, disable any pending + @ exceptions, so we can get at the + @ rest of it + + @ Save out the current registers to the old thread state + + DBGSTR1 "save old state %p", r4 + cmp r4, #0 + beq no_old_VFP_process + VFPFMRX r2, FPSCR @ current status + VFPFMRX r6, FPINST @ FPINST (always there, rev0 onwards) + tst r1, #FPEXC_FPV2 @ is there an FPINST2 to read? + VFPFMRX r8, FPINST2, NE @ FPINST2 if needed - avoids reading + @ nonexistant reg on rev0 + VFPFSTMIA r4 @ save the working registers + add r4, r4, #8*16+4 + stmia r4, {r1, r2, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 + @ and point r4 at the word at the + @ start of the register dump + +no_old_VFP_process: + DBGSTR1 "load state %p", r10 + str r10, [r3] @ update the last_VFP_context pointer + @ Load the saved state back into the VFP + add r4, r10, #8*16+4 + ldmia r4, {r1, r2, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2 + VFPFLDMIA r10 @ reload the working registers while + @ FPEXC is in a safe state + tst r1, #FPEXC_FPV2 @ is there an FPINST2 to write? + VFPFMXR FPINST2, r8, NE @ FPINST2 if needed - avoids writing + @ nonexistant reg on rev0 + VFPFMXR FPINST, r6 + VFPFMXR FPSCR, r2 @ restore status + +check_for_exception: + tst r1, #FPEXC_EXCEPTION + bne process_exception @ might as well handle the pending + @ exception before retrying branch + @ out before setting an FPEXC that + @ stops us reading stuff + VFPFMXR FPEXC, r1 @ restore FPEXC last + sub r5, r5, #4 + str r5, [sp, #S_PC] @ retry the instruction + mov pc, r9 @ we think we have handled things + + +look_for_VFP_exceptions: + tst r1, #FPEXC_EXCEPTION + bne process_exception + VFPFMRX r2, FPSCR + tst r2, #FPSCR_IXE @ IXE doesn't set FPEXC_EXCEPTION ! + bne process_exception + + @ Fall into hand on to next handler - appropriate coproc instr + @ not recognised by VFP + + DBGSTR "not VFP" + mov pc, lr + +process_exception: + DBGSTR "bounce" + sub r5, r5, #4 + str r5, [sp, #S_PC] @ retry the instruction on exit from + @ the imprecise exception handling in + @ the support code + mov r2, sp @ nothing stacked - regdump is at TOS + mov lr, r9 @ setup for a return to the user code. + + @ Now call the C code to package up the bounce to the support code + @ r0 holds the trigger instruction + @ r1 holds the FPEXC value + @ r2 pointer to register dump + b VFP9_bounce @ we have handled this - the support + @ code will raise an exception if + @ required. If not, the user code will + @ retry the faulted instruction + +last_VFP_context_address: + .word last_VFP_context + + .globl vfp_get_float +vfp_get_float: + add pc, pc, r0, lsl #3 + mov r0, r0 + .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0 + mov pc, lr + mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1 + mov pc, lr + .endr + + .globl vfp_put_float +vfp_put_float: + add pc, pc, r0, lsl #3 + mov r0, r0 + .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + mcr p10, 0, r1, c\dr, c0, 0 @ fmsr r0, s0 + mov pc, lr + mcr p10, 0, r1, c\dr, c0, 4 @ fmsr r0, s1 + mov pc, lr + .endr + + .globl vfp_get_double +vfp_get_double: + mov r0, r0, lsr #1 + add pc, pc, r0, lsl #3 + mov r0, r0 + .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + mrrc p10, 1, r0, r1, c\dr @ fmrrd r0, r1, d\dr + mov pc, lr + .endr + + .globl vfp_put_double +vfp_put_double: + mov r0, r0, lsr #1 + add pc, pc, r0, lsl #3 + mov r0, r0 + .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + mcrr p10, 1, r1, r2, c\dr @ fmrrd r1, r2, d\dr + mov pc, lr + .endr diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h new file mode 100644 index 000000000..6c819aeae --- /dev/null +++ b/arch/arm/vfp/vfpinstr.h @@ -0,0 +1,88 @@ +/* + * linux/arch/arm/vfp/vfpinstr.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * VFP instruction masks. + */ +#define INST_CPRTDO(inst) (((inst) & 0x0f000000) == 0x0e000000) +#define INST_CPRT(inst) ((inst) & (1 << 4)) +#define INST_CPRT_L(inst) ((inst) & (1 << 20)) +#define INST_CPRT_Rd(inst) (((inst) & (15 << 12)) >> 12) +#define INST_CPRT_OP(inst) (((inst) >> 21) & 7) +#define INST_CPNUM(inst) ((inst) & 0xf00) +#define CPNUM(cp) ((cp) << 8) + +#define FOP_MASK (0x00b00040) +#define FOP_FMAC (0x00000000) +#define FOP_FNMAC (0x00000040) +#define FOP_FMSC (0x00100000) +#define FOP_FNMSC (0x00100040) +#define FOP_FMUL (0x00200000) +#define FOP_FNMUL (0x00200040) +#define FOP_FADD (0x00300000) +#define FOP_FSUB (0x00300040) +#define FOP_FDIV (0x00800000) +#define FOP_EXT (0x00b00040) + +#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) + +#define FEXT_MASK (0x000f0080) +#define FEXT_FCPY (0x00000000) +#define FEXT_FABS (0x00000080) +#define FEXT_FNEG (0x00010000) +#define FEXT_FSQRT (0x00010080) +#define FEXT_FCMP (0x00040000) +#define FEXT_FCMPE (0x00040080) +#define FEXT_FCMPZ (0x00050000) +#define FEXT_FCMPEZ (0x00050080) +#define FEXT_FCVT (0x00070080) +#define FEXT_FUITO (0x00080000) +#define FEXT_FSITO (0x00080080) +#define FEXT_FTOUI (0x000c0000) +#define FEXT_FTOUIZ (0x000c0080) +#define FEXT_FTOSI (0x000d0000) +#define FEXT_FTOSIZ (0x000d0080) + +#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) + +#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) +#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12) +#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) +#define vfp_get_dm(inst) ((inst & 0x0000000f)) +#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) +#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16) + +#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) + +#define FPSCR_N (1 << 31) +#define FPSCR_Z (1 << 30) +#define FPSCR_C (1 << 29) +#define FPSCR_V (1 << 28) + +/* + * Since we aren't building with -mfpu=vfp, we need to code + * these instructions using their MRC/MCR equivalents. + */ +#define vfpreg(_vfp_) #_vfp_ + +#define fmrx(_vfp_) ({ \ + u32 __v; \ + asm("mrc%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \ + : "=r" (__v)); \ + __v; \ + }) + +#define fmxr(_vfp_,_var_) \ + asm("mcr%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \ + : : "r" (_var_)) + +u32 vfp_single_cpdo(u32 inst, u32 fpscr); +u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs); + +u32 vfp_double_cpdo(u32 inst, u32 fpscr); diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c new file mode 100644 index 000000000..3aeedd2af --- /dev/null +++ b/arch/arm/vfp/vfpmodule.c @@ -0,0 +1,288 @@ +/* + * linux/arch/arm/vfp/vfpmodule.c + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vfpinstr.h" +#include "vfp.h" + +/* + * Our undef handlers (in entry.S) + */ +void vfp_testing_entry(void); +void vfp_support_entry(void); + +void (*vfp_vector)(void) = vfp_testing_entry; +union vfp_state *last_VFP_context; + +/* + * Dual-use variable. + * Used in startup: set to non-zero if VFP checks fail + * After startup, holds VFP architecture + */ +unsigned int VFP_arch; + +/* + * Per-thread VFP initialisation. + */ +void vfp_flush_thread(union vfp_state *vfp) +{ + memset(vfp, 0, sizeof(union vfp_state)); + + vfp->hard.fpexc = FPEXC_ENABLE; + vfp->hard.fpscr = FPSCR_ROUND_NEAREST; + + /* + * Disable VFP to ensure we initialise it first. + */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE); + + /* + * Ensure we don't try to overwrite our newly initialised + * state information on the first fault. + */ + if (last_VFP_context == vfp) + last_VFP_context = NULL; +} + +/* + * Per-thread VFP cleanup. + */ +void vfp_release_thread(union vfp_state *vfp) +{ + if (last_VFP_context == vfp) + last_VFP_context = NULL; +} + +/* + * Raise a SIGFPE for the current process. + * sicode describes the signal being raised. + */ +void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) +{ + siginfo_t info; + + memset(&info, 0, sizeof(info)); + + info.si_signo = SIGFPE; + info.si_code = sicode; + info.si_addr = (void *)(instruction_pointer(regs) - 4); + + /* + * This is the same as NWFPE, because it's not clear what + * this is used for + */ + current->thread.error_code = 0; + current->thread.trap_no = 6; + + force_sig_info(SIGFPE, &info, current); +} + +static void vfp_panic(char *reason) +{ + int i; + + printk(KERN_ERR "VFP: Error: %s\n", reason); + printk(KERN_ERR "VFP: EXC 0x%08x SCR 0x%08x INST 0x%08x\n", + fmrx(FPEXC), fmrx(FPSCR), fmrx(FPINST)); + for (i = 0; i < 32; i += 2) + printk(KERN_ERR "VFP: s%2u: 0x%08x s%2u: 0x%08x\n", + i, vfp_get_float(i), i+1, vfp_get_float(i+1)); +} + +/* + * Process bitmask of exception conditions. + */ +static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs) +{ + int si_code = 0; + + pr_debug("VFP: raising exceptions %08x\n", exceptions); + + if (exceptions == (u32)-1) { + vfp_panic("unhandled bounce"); + vfp_raise_sigfpe(0, regs); + return; + } + + /* + * If any of the status flags are set, update the FPSCR. + * Comparison instructions always return at least one of + * these flags set. + */ + if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) + fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); + + fpscr |= exceptions; + + fmxr(FPSCR, fpscr); + +#define RAISE(stat,en,sig) \ + if (exceptions & stat && fpscr & en) \ + si_code = sig; + + /* + * These are arranged in priority order, least to highest. + */ + RAISE(FPSCR_IXC, FPSCR_IXE, FPE_FLTRES); + RAISE(FPSCR_UFC, FPSCR_UFE, FPE_FLTUND); + RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF); + RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV); + + if (si_code) + vfp_raise_sigfpe(si_code, regs); +} + +/* + * Emulate a VFP instruction. + */ +static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs) +{ + u32 exceptions = (u32)-1; + + pr_debug("VFP: emulate: INST=0x%08x SCR=0x%08x\n", inst, fpscr); + + if (INST_CPRTDO(inst)) { + if (!INST_CPRT(inst)) { + /* + * CPDO + */ + if (vfp_single(inst)) { + exceptions = vfp_single_cpdo(inst, fpscr); + } else { + exceptions = vfp_double_cpdo(inst, fpscr); + } + } else { + /* + * A CPRT instruction can not appear in FPINST2, nor + * can it cause an exception. Therefore, we do not + * have to emulate it. + */ + } + } else { + /* + * A CPDT instruction can not appear in FPINST2, nor can + * it cause an exception. Therefore, we do not have to + * emulate it. + */ + } + return exceptions; +} + +/* + * Package up a bounce condition. + */ +void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) +{ + u32 fpscr, orig_fpscr, exceptions, inst; + + pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); + + /* + * Enable access to the VFP so we can handle the bounce. + */ + fmxr(FPEXC, fpexc & ~(FPEXC_EXCEPTION|FPEXC_INV|FPEXC_UFC|FPEXC_IOC)); + + orig_fpscr = fpscr = fmrx(FPSCR); + + /* + * If we are running with inexact exceptions enabled, we need to + * emulate the trigger instruction. Note that as we're emulating + * the trigger instruction, we need to increment PC. + */ + if (fpscr & FPSCR_IXE) { + regs->ARM_pc += 4; + goto emulate; + } + + barrier(); + + /* + * Modify fpscr to indicate the number of iterations remaining + */ + if (fpexc & FPEXC_EXCEPTION) { + u32 len; + + len = fpexc + (1 << FPEXC_LENGTH_BIT); + + fpscr &= ~FPSCR_LENGTH_MASK; + fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); + } + + /* + * Handle the first FP instruction. We used to take note of the + * FPEXC bounce reason, but this appears to be unreliable. + * Emulate the bounced instruction instead. + */ + inst = fmrx(FPINST); + exceptions = vfp_emulate_instruction(inst, fpscr, regs); + if (exceptions) + vfp_raise_exceptions(exceptions, inst, orig_fpscr, regs); + + /* + * If there isn't a second FP instruction, exit now. + */ + if (!(fpexc & FPEXC_FPV2)) + return; + + /* + * The barrier() here prevents fpinst2 being read + * before the condition above. + */ + barrier(); + trigger = fmrx(FPINST2); + fpscr = fmrx(FPSCR); + + emulate: + exceptions = vfp_emulate_instruction(trigger, fpscr, regs); + if (exceptions) + vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); +} + +/* + * VFP support code initialisation. + */ +static int __init vfp_init(void) +{ + unsigned int vfpsid; + + /* + * First check that there is a VFP that we can use. + * The handler is already setup to just log calls, so + * we just need to read the VFPSID register. + */ + vfpsid = fmrx(FPSID); + + printk(KERN_INFO "VFP support v0.3: "); + if (VFP_arch) { + printk("not present\n"); + } else if (vfpsid & FPSID_NODOUBLE) { + printk("no double precision support\n"); + } else { + VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ + printk("implementor %02x architecture %d part %02x variant %x rev %x\n", + (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, + (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT, + (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT, + (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, + (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); + vfp_vector = vfp_support_entry; + } + return 0; +} + +late_initcall(vfp_init); diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c new file mode 100644 index 000000000..92aa84127 --- /dev/null +++ b/arch/arm/vfp/vfpsingle.c @@ -0,0 +1,1224 @@ +/* + * linux/arch/arm/vfp/vfpsingle.c + * + * This code is derived in part from John R. Housers softfloat library, which + * carries the following notice: + * + * =========================================================================== + * This C source file is part of the SoftFloat IEC/IEEE Floating-point + * Arithmetic Package, Release 2. + * + * Written by John R. Hauser. This work was made possible in part by the + * International Computer Science Institute, located at Suite 600, 1947 Center + * Street, Berkeley, California 94704. Funding was partially provided by the + * National Science Foundation under grant MIP-9311980. The original version + * of this code was written as part of a project to build a fixed-point vector + * processor in collaboration with the University of California at Berkeley, + * overseen by Profs. Nelson Morgan and John Wawrzynek. More information + * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ + * arithmetic/softfloat.html'. + * + * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort + * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT + * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO + * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY + * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + * + * Derivative works are acceptable, even for commercial purposes, so long as + * (1) they include prominent notice that the work is derivative, and (2) they + * include prominent notice akin to these three paragraphs for those parts of + * this code that are retained. + * =========================================================================== + */ +#include +#include +#include +#include + +#include "vfpinstr.h" +#include "vfp.h" + +static struct vfp_single vfp_single_default_qnan = { + .exponent = 255, + .sign = 0, + .significand = VFP_SINGLE_SIGNIFICAND_QNAN, +}; + +static void vfp_single_dump(const char *str, struct vfp_single *s) +{ + pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", + str, s->sign != 0, s->exponent, s->significand); +} + +static void vfp_single_normalise_denormal(struct vfp_single *vs) +{ + int bits = 31 - fls(vs->significand); + + vfp_single_dump("normalise_denormal: in", vs); + + if (bits) { + vs->exponent -= bits - 1; + vs->significand <<= bits; + } + + vfp_single_dump("normalise_denormal: out", vs); +} + +#ifndef DEBUG +#define vfp_single_normaliseround(sd,vsd,fpscr,except,func) __vfp_single_normaliseround(sd,vsd,fpscr,except) +u32 __vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions) +#else +u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) +#endif +{ + u32 significand, incr, rmode; + int exponent, shift, underflow; + + vfp_single_dump("pack: in", vs); + + /* + * Infinities and NaNs are a special case. + */ + if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vs->significand == 0) { + vs->exponent = 0; + goto pack; + } + + exponent = vs->exponent; + significand = vs->significand; + + /* + * Normalise first. Note that we shift the significand up to + * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least + * significant bit. + */ + shift = 32 - fls(significand); + if (shift < 32 && shift) { + exponent -= shift; + significand <<= shift; + } + +#ifdef DEBUG + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: normalised", vs); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright32jamming(significand, -exponent); + exponent = 0; +#ifdef DEBUG + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: tiny number", vs); +#endif + if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1 << VFP_SINGLE_LOW_BITS; + if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) + incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08x\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#ifdef DEBUG + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: overflow", vs); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 254) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vs->exponent = 253; + vs->significand = 0x7fffffff; + } else { + vs->exponent = 255; /* infinity */ + vs->significand = 0; + } + } else { + if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x80000000) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vs->exponent = exponent; + vs->significand = significand >> 1; + } + + pack: + vfp_single_dump("pack: final", vs); + { + s32 d = vfp_single_pack(vs); + pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, + sd, d, exceptions); + vfp_put_float(sd, d); + } + + return exceptions; +} + +/* + * Propagate the NaN, setting exceptions if it is signalling. + * 'n' is always a NaN. 'm' may be a number, NaN or infinity. + */ +static u32 +vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + struct vfp_single *nan; + int tn, tm = 0; + + tn = vfp_single_type(vsn); + + if (vsm) + tm = vfp_single_type(vsm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_single_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vsn; + else + nan = vsm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + } + + *vsd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : 0x100; +} + + +/* + * Extended operations + */ +static u32 vfp_single_fabs(int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(sd, vfp_single_packed_abs(m)); + return 0; +} + +static u32 vfp_single_fcpy(int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(sd, m); + return 0; +} + +static u32 vfp_single_fneg(int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(sd, vfp_single_packed_negate(m)); + return 0; +} + +static const u16 sqrt_oddadjust[] = { + 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, + 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 +}; + +static const u16 sqrt_evenadjust[] = { + 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, + 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 +}; + +u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) +{ + int index; + u32 z, a; + + if ((significand & 0xc0000000) != 0x40000000) { + printk(KERN_WARNING "VFP: estimate_sqrt: invalid significand\n"); + } + + a = significand << 1; + index = (a >> 27) & 15; + if (exponent & 1) { + z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; + z = ((a / z) << 14) + (z << 15); + a >>= 1; + } else { + z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; + z = a / z + z; + z = (z >= 0x20000) ? 0xffff8000 : (z << 15); + if (z <= a) + return (s32)a >> 1; + } + return (u32)(((u64)a << 31) / z) + (z >> 1); +} + +static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm, vsd; + int ret, tm; + + vfp_single_unpack(&vsm, m); + tm = vfp_single_type(&vsm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + struct vfp_single *vsp = &vsd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); + else if (vsm.sign == 0) { + sqrt_copy: + vsp = &vsm; + ret = 0; + } else { + sqrt_invalid: + vsp = &vfp_single_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_float(sd, vfp_single_pack(vsp)); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * sqrt(<0) = invalid + */ + if (vsm.sign) + goto sqrt_invalid; + + vfp_single_dump("sqrt", &vsm); + + /* + * Estimate the square root. + */ + vsd.sign = 0; + vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; + vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; + + vfp_single_dump("sqrt estimate", &vsd); + + /* + * And now adjust. + */ + if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { + if (vsd.significand < 2) { + vsd.significand = 0xffffffff; + } else { + u64 term; + s64 rem; + vsm.significand <<= !(vsm.exponent & 1); + term = (u64)vsd.significand * vsd.significand; + rem = ((u64)vsm.significand << 32) - term; + + pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); + + while (rem < 0) { + vsd.significand -= 1; + rem += ((u64)vsd.significand << 1) | 1; + } + vsd.significand |= rem != 0; + } + } + vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); + + return vfp_single_normaliseround(sd, &vsd, fpscr, 0, "fsqrt"); +} + +/* + * Equal := ZC + * Less than := N + * Greater than := C + * Unordered := CV + */ +static u32 vfp_compare(int sd, int signal_on_qnan, s32 m, u32 fpscr) +{ + s32 d; + u32 ret = 0; + + d = vfp_get_float(sd); + if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + if (d == m || vfp_single_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + } else if (vfp_single_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_single_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + return ret; +} + +static u32 vfp_single_fcmp(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(sd, 0, m, fpscr); +} + +static u32 vfp_single_fcmpe(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(sd, 1, m, fpscr); +} + +static u32 vfp_single_fcmpz(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(sd, 0, 0, fpscr); +} + +static u32 vfp_single_fcmpez(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(sd, 1, 0, fpscr); +} + +static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + struct vfp_double vdd; + int tm; + u32 exceptions = 0; + + vfp_single_unpack(&vsm, m); + + tm = vfp_single_type(&vsm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + vdd.sign = vsm.sign; + vdd.significand = (u64)vsm.significand << 32; + + /* + * If we have an infinity or NaN, the exponent must be 2047. + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vdd.exponent = 2047; + if (tm & VFP_NAN) + vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vdd.exponent = 0; + else + vdd.exponent = vsm.exponent + (1023 - 127); + + /* + * Technically, if bit 0 of dd is set, this is an invalid + * instruction. However, we ignore this for efficiency. + */ + return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd"); + + pack_nan: + vfp_put_double(dd, vfp_double_pack(&vdd)); + return exceptions; +} + +static u32 vfp_single_fuito(int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vs; + + vs.sign = 0; + vs.exponent = 127 + 31 - 1; + vs.significand = (u32)m; + + return vfp_single_normaliseround(sd, &vs, fpscr, 0, "fuito"); +} + +static u32 vfp_single_fsito(int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vs; + + vs.sign = (m & 0x80000000) >> 16; + vs.exponent = 127 + 31 - 1; + vs.significand = vs.sign ? -m : m; + + return vfp_single_normaliseround(sd, &vs, fpscr, 0, "fsito"); +} + +static u32 vfp_single_ftoui(int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + tm = vfp_single_type(&vsm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vsm.sign = 0; + + if (vsm.exponent >= 127 + 32) { + d = vsm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(sd, d); + + return exceptions; +} + +static u32 vfp_single_ftouiz(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_single_ftoui(sd, unused, m, FPSCR_ROUND_TOZERO); +} + +static u32 vfp_single_ftosi(int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + if (vfp_single_type(&vsm) & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (vsm.exponent >= 127 + 32) { + /* + * m >= 2^31-2^7: invalid + */ + d = 0x7fffffff; + if (vsm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* 2^0 <= m <= 2^31-2^7 */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > 0x7fffffff + (vsm.sign != 0)) { + d = 0x7fffffff + (vsm.sign != 0); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vsm.sign) + d = -d; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(sd, (s32)d); + + return exceptions; +} + +static u32 vfp_single_ftosiz(int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO); +} + +static u32 (* const fop_extfns[32])(int sd, int unused, s32 m, u32 fpscr) = { + [FEXT_TO_IDX(FEXT_FCPY)] = vfp_single_fcpy, + [FEXT_TO_IDX(FEXT_FABS)] = vfp_single_fabs, + [FEXT_TO_IDX(FEXT_FNEG)] = vfp_single_fneg, + [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_single_fsqrt, + [FEXT_TO_IDX(FEXT_FCMP)] = vfp_single_fcmp, + [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_single_fcmpe, + [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_single_fcmpz, + [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_single_fcmpez, + [FEXT_TO_IDX(FEXT_FCVT)] = vfp_single_fcvtd, + [FEXT_TO_IDX(FEXT_FUITO)] = vfp_single_fuito, + [FEXT_TO_IDX(FEXT_FSITO)] = vfp_single_fsito, + [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_single_ftoui, + [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_single_ftouiz, + [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_single_ftosi, + [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_single_ftosiz, +}; + + + + + +static u32 +vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + struct vfp_single *vsp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_single_type(vsn); + tm = vfp_single_type(vsm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vsn->sign ^ vsm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vsp = &vfp_single_default_qnan; + } else { + /* + * same signs -> valid + */ + vsp = vsn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vsp = vsn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + } + *vsd = *vsp; + return exceptions; +} + +static u32 +vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + u32 exp_diff, m_sig; + + if (vsn->significand & 0x80000000 || + vsm->significand & 0x80000000) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vsn->exponent == 255) + return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); + + /* + * We have two proper numbers, where 'vsn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vsd = *vsn; + + /* + * Align both numbers. + */ + exp_diff = vsn->exponent - vsm->exponent; + m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vsn->sign ^ vsm->sign) { + m_sig = vsn->significand - m_sig; + if ((s32)m_sig < 0) { + vsd->sign = vfp_sign_negate(vsd->sign); + m_sig = -m_sig; + } else if (m_sig == 0) { + vsd->sign = (fpscr & FPSCR_RMODE_MASK) == + FPSCR_ROUND_MINUSINF ? 0x8000 : 0; + } + } else { + m_sig = vsn->significand + m_sig; + } + vsd->significand = m_sig; + + return 0; +} + +static u32 +vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) +{ + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vsd->sign = vsn->sign ^ vsm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vsn->exponent == 255) { + if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + if ((vsm->exponent | vsm->significand) == 0) { + *vsd = vfp_single_default_qnan; + return FPSCR_IOC; + } + vsd->exponent = vsn->exponent; + vsd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vsm->exponent | vsm->significand) == 0) { + vsd->exponent = 0; + vsd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason as + * the addition case - though this time we have +1 from each + * input operand. + */ + vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; + vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); + + vfp_single_dump("VSD", vsd); + return 0; +} + +#define NEG_MULTIPLY (1 << 0) +#define NEG_SUBTRACT (1 << 1) + +static u32 +vfp_single_multiply_accumulate(int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func) +{ + struct vfp_single vsd, vsp, vsn, vsm; + u32 exceptions; + s32 v; + + v = vfp_get_float(sn); + pr_debug("VFP: s%u = %08x\n", sn, v); + vfp_single_unpack(&vsn, v); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); + if (negate & NEG_MULTIPLY) + vsp.sign = vfp_sign_negate(vsp.sign); + + v = vfp_get_float(sd); + pr_debug("VFP: s%u = %08x\n", sd, v); + vfp_single_unpack(&vsn, v); + if (negate & NEG_SUBTRACT) + vsn.sign = vfp_sign_negate(vsn.sign); + + exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); + + return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, func); +} + +/* + * Standard operations + */ + +/* + * sd = sd + (sn * sm) + */ +static u32 vfp_single_fmac(int sd, int sn, s32 m, u32 fpscr) +{ + return vfp_single_multiply_accumulate(sd, sn, m, fpscr, 0, "fmac"); +} + +/* + * sd = sd - (sn * sm) + */ +static u32 vfp_single_fnmac(int sd, int sn, s32 m, u32 fpscr) +{ + return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); +} + +/* + * sd = -sd + (sn * sm) + */ +static u32 vfp_single_fmsc(int sd, int sn, s32 m, u32 fpscr) +{ + return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); +} + +/* + * sd = -sd - (sn * sm) + */ +static u32 vfp_single_fnmsc(int sd, int sn, s32 m, u32 fpscr) +{ + return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); +} + +/* + * sd = sn * sm + */ +static u32 vfp_single_fmul(int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(sn); + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fmul"); +} + +/* + * sd = -(sn * sm) + */ +static u32 vfp_single_fnmul(int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(sn); + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + vsd.sign = vfp_sign_negate(vsd.sign); + return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fnmul"); +} + +/* + * sd = sn + sm + */ +static u32 vfp_single_fadd(int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(sn); + + pr_debug("VFP: s%u = %08x\n", sn, n); + + /* + * Unpack and normalise denormals. + */ + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); + + return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fadd"); +} + +/* + * sd = sn - sm + */ +static u32 vfp_single_fsub(int sd, int sn, s32 m, u32 fpscr) +{ + /* + * Subtraction is addition with one sign inverted. + */ + return vfp_single_fadd(sd, sn, vfp_single_packed_negate(m), fpscr); +} + +/* + * sd = sn / sm + */ +static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions = 0; + s32 n = vfp_get_float(sn); + int tm, tn; + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + vfp_single_unpack(&vsm, m); + + vsd.sign = vsn.sign ^ vsm.sign; + + tn = vfp_single_type(&vsn); + tm = vfp_single_type(&vsm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vsn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vsm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exception + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsn); + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; + vsm.significand <<= 1; + if (vsm.significand <= (2 * vsn.significand)) { + vsn.significand >>= 1; + vsd.exponent++; + } + vsd.significand = ((u64)vsn.significand << 32) / vsm.significand; + if ((vsd.significand & 0x3f) == 0) + vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); + + return vfp_single_normaliseround(sd, &vsd, fpscr, 0, "fdiv"); + + vsn_nan: + exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); + pack: + vfp_put_float(sd, vfp_single_pack(&vsd)); + return exceptions; + + vsm_nan: + exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); + goto pack; + + zero: + vsd.exponent = 0; + vsd.significand = 0; + goto pack; + + divzero: + exceptions = FPSCR_DZC; + infinity: + vsd.exponent = 255; + vsd.significand = 0; + goto pack; + + invalid: + vfp_put_float(sd, vfp_single_pack(&vfp_single_default_qnan)); + return FPSCR_IOC; +} + +static u32 (* const fop_fns[16])(int sd, int sn, s32 m, u32 fpscr) = { + [FOP_TO_IDX(FOP_FMAC)] = vfp_single_fmac, + [FOP_TO_IDX(FOP_FNMAC)] = vfp_single_fnmac, + [FOP_TO_IDX(FOP_FMSC)] = vfp_single_fmsc, + [FOP_TO_IDX(FOP_FNMSC)] = vfp_single_fnmsc, + [FOP_TO_IDX(FOP_FMUL)] = vfp_single_fmul, + [FOP_TO_IDX(FOP_FNMUL)] = vfp_single_fnmul, + [FOP_TO_IDX(FOP_FADD)] = vfp_single_fadd, + [FOP_TO_IDX(FOP_FSUB)] = vfp_single_fsub, + [FOP_TO_IDX(FOP_FDIV)] = vfp_single_fdiv, +}; + +#define FREG_BANK(x) ((x) & 0x18) +#define FREG_IDX(x) ((x) & 7) + +u32 vfp_single_cpdo(u32 inst, u32 fpscr) +{ + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int sd = vfp_get_sd(inst); + unsigned int sn = vfp_get_sn(inst); + unsigned int sm = vfp_get_sm(inst); + unsigned int vecitr, veclen, vecstride; + u32 (*fop)(int, int, s32, u32); + + veclen = fpscr & FPSCR_LENGTH_MASK; + vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if (FREG_BANK(sd) == 0) + veclen = 0; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + fop = (op == FOP_EXT) ? fop_extfns[sn] : fop_fns[FOP_TO_IDX(op)]; + if (!fop) + goto invalid; + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + s32 m = vfp_get_float(sm); + u32 except; + + if (op == FOP_EXT) + pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, sd, sn, sm, m); + else + pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, sd, sn, + FOP_TO_IDX(op), sm, m); + + except = fop(sd, sn, m, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * This ensures that comparisons only operate on scalars; + * comparisons always return with one FPSCR status bit set. + */ + if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) + break; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + + sd = FREG_BANK(sd) + ((FREG_IDX(sd) + vecstride) & 7); + sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); + if (FREG_BANK(sm) != 0) + sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); + } + return exceptions; + + invalid: + return (u32)-1; +} diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index ce96fd34b..b40758b9f 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -327,6 +327,8 @@ config DEBUG_LL endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c index 57b9fb1e2..78cd8931d 100644 --- a/arch/arm26/kernel/ptrace.c +++ b/arch/arm26/kernel/ptrace.c @@ -691,6 +691,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 481edcadc..93d52b712 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -210,6 +210,8 @@ config FRAME_POINTER endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/cris/arch-v10/drivers/ethernet.c b/arch/cris/arch-v10/drivers/ethernet.c index f258c0008..e13b754a2 100644 --- a/arch/cris/arch-v10/drivers/ethernet.c +++ b/arch/cris/arch-v10/drivers/ethernet.c @@ -1396,8 +1396,8 @@ e100_close(struct net_device *dev) static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mii_ioctl_data *data = if_mii(ifr); - struct net_local *np = netdev_priv(dev); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct net_local *np = (struct net_local *)dev->priv; spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { diff --git a/arch/cris/kernel/hexify.c b/arch/cris/kernel/hexify.c deleted file mode 100644 index daa331fec..000000000 --- a/arch/cris/kernel/hexify.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - - -void main() -{ - int c; - int comma=0; - int count=0; - while((c=getchar())!=EOF) - { - unsigned char x=c; - if(comma) - printf(","); - else - comma=1; - if(count==8) - { - count=0; - printf("\n"); - } - if(count==0) - printf("\t"); - printf("0x%02X",c); - count++; - } - if(count) - printf("\n"); - exit(0); -} - - diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c deleted file mode 100644 index 1161a2525..000000000 --- a/arch/cris/kernel/ksyms.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void dump_thread(struct pt_regs *, struct user *); -extern unsigned long get_cmos_time(void); -extern void __Udiv(void); -extern void __Umod(void); -extern void __Div(void); -extern void __Mod(void); -extern void __ashrdi3(void); -extern void iounmap(void *addr); - -/* Platform dependent support */ -EXPORT_SYMBOL(dump_thread); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(get_cmos_time); -EXPORT_SYMBOL(loops_per_usec); - -/* String functions */ -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(strncpy); - -/* Math functions */ -EXPORT_SYMBOL(__Udiv); -EXPORT_SYMBOL(__Umod); -EXPORT_SYMBOL(__Div); -EXPORT_SYMBOL(__Mod); -EXPORT_SYMBOL(__ashrdi3); - -/* Memory functions */ -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); - -/* Semaphore functions */ -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__down_trylock); - -/* Export shadow registers for the CPU I/O pins */ -EXPORT_SYMBOL(genconfig_shadow); -EXPORT_SYMBOL(port_pa_data_shadow); -EXPORT_SYMBOL(port_pa_dir_shadow); -EXPORT_SYMBOL(port_pb_data_shadow); -EXPORT_SYMBOL(port_pb_dir_shadow); -EXPORT_SYMBOL(port_pb_config_shadow); -EXPORT_SYMBOL(port_g_data_shadow); - -/* Userspace access functions */ -EXPORT_SYMBOL(__copy_user_zeroing); -EXPORT_SYMBOL(__copy_user); - -/* Cache flush functions */ -EXPORT_SYMBOL(flush_etrax_cache); -EXPORT_SYMBOL(prepare_rx_descriptor); - -#undef memcpy -#undef memset -extern void * memset(void *, int, __kernel_size_t); -extern void * memcpy(void *, const void *, __kernel_size_t); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); - - diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 072192a4f..093f3e64c 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -253,6 +253,8 @@ config CONFIG_BLKDEV_RESERVE_ADDRESS BLKDEV start address. endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c index 0843013d1..cdbfe9e5c 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -80,6 +80,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index e057b4f6c..75ee13720 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -65,8 +65,6 @@ config X86_VOYAGER config X86_NUMAQ bool "NUMAQ (IBM/Sequent)" - select DISCONTIGMEM - select NUMA help This option is used for getting Linux to run on a (IBM/Sequent) NUMA multiquad box. This changes the way that processors are bootstrapped, @@ -424,6 +422,54 @@ config X86_OOSTORE depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR default y +config X86_4G + bool "4 GB kernel-space and 4 GB user-space virtual memory support" + help + This option is only useful for systems that have more than 1 GB + of RAM. + + The default kernel VM layout leaves 1 GB of virtual memory for + kernel-space mappings, and 3 GB of VM for user-space applications. + This option ups both the kernel-space VM and the user-space VM to + 4 GB. + + The cost of this option is additional TLB flushes done at + system-entry points that transition from user-mode into kernel-mode. + I.e. system calls and page faults, and IRQs that interrupt user-mode + code. There's also additional overhead to kernel operations that copy + memory to/from user-space. The overhead from this is hard to tell and + depends on the workload - it can be anything from no visible overhead + to 20-30% overhead. A good rule of thumb is to count with a runtime + overhead of 20%. + + The upside is the much increased kernel-space VM, which more than + quadruples the maximum amount of RAM supported. Kernels compiled with + this option boot on 64GB of RAM and still have more than 3.1 GB of + 'lowmem' left. Another bonus is that highmem IO bouncing decreases, + if used with drivers that still use bounce-buffers. + + There's also a 33% increase in user-space VM size - database + applications might see a boost from this. + + But the cost of the TLB flushes and the runtime overhead has to be + weighed against the bonuses offered by the larger VM spaces. The + dividing line depends on the actual workload - there might be 4 GB + systems that benefit from this option. Systems with less than 4 GB + of RAM will rarely see a benefit from this option - but it's not + out of question, the exact circumstances have to be considered. + +config X86_SWITCH_PAGETABLES + def_bool X86_4G + +config X86_4G_VM_LAYOUT + def_bool X86_4G + +config X86_UACCESS_INDIRECT + def_bool X86_4G + +config X86_HIGH_ENTRY + def_bool X86_4G + config HPET_TIMER bool "HPET Timer Support" help @@ -550,7 +596,6 @@ config X86_TSC config X86_MCE bool "Machine Check Exception" - depends on !X86_VOYAGER ---help--- Machine Check Exception support allows the processor to notify the kernel if it detects a problem (e.g. overheating, component failure). @@ -826,7 +871,7 @@ config EFI This option is only useful on systems that have EFI firmware and will result in a kernel image that is ~8k larger. In addition, you must use the latest ELILO loader available at - in order to take advantage of + in order to take advantage of kernel initialization using EFI information (neither GRUB nor LILO know anything about EFI). However, even with this option, the resultant kernel should continue to boot on existing non-EFI platforms. @@ -1288,15 +1333,6 @@ config FRAME_POINTER If you don't debug the kernel, you can say N, but we may not be able to solve problems without frame pointers. -config 4KSTACKS - bool "Use 4Kb for kernel stacks instead of 8Kb" - help - If you say Y here the kernel will use a 4Kb stacksize for the - kernel stack attached to each process/thread. This facilitates - running more threads on a system and also reduces the pressure - on the VM subsystem for higher order allocations. This option - will also use IRQ stacks to compensate for the reduced stackspace. - config X86_FIND_SMP_CONFIG bool depends on X86_LOCAL_APIC || X86_VOYAGER @@ -1309,6 +1345,8 @@ config X86_MPPARSE endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 299b5f2bb..1874ddff3 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -20,7 +20,7 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := CHECK := $(CHECK) -D__i386__=1 -CFLAGS += -pipe -msoft-float +CFLAGS += -pipe -msoft-float -m32 -fno-builtin-sprintf -fno-builtin-log2 -fno-builtin-puts # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,) @@ -112,7 +112,7 @@ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ drivers-$(CONFIG_PM) += arch/i386/power/ CFLAGS += $(mflags-y) -AFLAGS += $(mflags-y) +AFLAGS += $(mflags-y) -m32 boot := arch/i386/boot diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index d606d0687..5dfd82f17 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -156,7 +156,7 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long (MAXMEM-1) & 0x7fffffff +ramdisk_max: .long (__MAXMEM-1) & 0x7fffffff # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 7e2c665e6..f81130fae 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -126,8 +126,12 @@ video: pushw %ds # We use different segments call mode_set # Set the mode jc vid1 +#if 0 leaw badmdt, %si # Invalid mode ID call prtstr +#else + jmp vid1 +#endif /* CONFIG_VIDEO_IGNORE_BAD_MODE */ vid2: call mode_menu vid1: #ifdef CONFIG_VIDEO_RETAIN diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 70b4604da..577be173b 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds.s obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o entry_trampoline.o obj-y += cpu/ obj-y += timers/ @@ -33,7 +33,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_X86_STD_RESOURCES) += std_resources.o -EXTRA_AFLAGS := -traditional +EXTRA_AFLAGS := -traditional -m32 obj-$(CONFIG_SCx200) += scx200.o @@ -48,7 +48,7 @@ quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ -vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 +vsyscall-flags = -m32 -shared -s -Wl,-soname=linux-gate.so.1 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) @@ -63,6 +63,6 @@ extra-y += vsyscall-syms.o $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o -SYSCFLAGS_vsyscall-syms.o = -r +SYSCFLAGS_vsyscall-syms.o = -m32 -r $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE $(call if_changed,syscall) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 2c53ca535..fdb9b6c88 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -450,7 +450,7 @@ acpi_scan_rsdp ( * RSDP signature. */ for (offset = 0; offset < length; offset += 16) { - if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) + if (strncmp((char *) __va(start + offset), "RSD PTR ", sig_len)) continue; return (start + offset); } diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c index 92fd1760a..629f7b852 100644 --- a/arch/i386/kernel/acpi/sleep.c +++ b/arch/i386/kernel/acpi/sleep.c @@ -19,13 +19,29 @@ extern void zap_low_mappings(void); extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); -static void init_low_mapping(pgd_t *pgd, int pgd_limit) +static void map_low(pgd_t *pgd_base, unsigned long start, unsigned long end) { - int pgd_ofs = 0; + unsigned long vaddr; + pmd_t *pmd; + pgd_t *pgd; + int i, j; - while ((pgd_ofs < pgd_limit) && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) { - set_pgd(pgd, *(pgd+USER_PTRS_PER_PGD)); - pgd_ofs++, pgd++; + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + set_pmd(pmd, __pmd(_KERNPG_TABLE + _PAGE_PSE + + vaddr - start)); + } } } @@ -39,7 +55,9 @@ int acpi_save_state_mem (void) { if (!acpi_wakeup_address) return 1; - init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD); + if (!cpu_has_pse) + return 1; + map_low(swapper_pg_dir, 0, LOW_MAPPINGS_SIZE); memcpy((void *) acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); acpi_copy_wakeup_routine(acpi_wakeup_address); diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S index 2c5de1d7f..c43349a31 100644 --- a/arch/i386/kernel/acpi/wakeup.S +++ b/arch/i386/kernel/acpi/wakeup.S @@ -67,6 +67,13 @@ wakeup_code: movw $0x0e00 + 'i', %fs:(0x12) # need a gdt + #use the gdt copied in this low mem + lea temp_gdt_table - wakeup_code, %eax + xor %ebx, %ebx + movw %ds, %bx + shll $4, %ebx + addl %ebx, %eax + movl %eax, real_save_gdt + 2 - wakeup_code lgdt real_save_gdt - wakeup_code movl real_save_cr0 - wakeup_code, %eax @@ -89,6 +96,7 @@ real_save_cr4: .long 0 real_magic: .long 0 video_mode: .long 0 video_flags: .long 0 +temp_gdt_table: .fill GDT_ENTRIES, 8, 0 bogus_real_magic: movw $0x0e00 + 'B', %fs:(0x12) @@ -231,6 +239,13 @@ ENTRY(acpi_copy_wakeup_routine) movl %edx, real_save_cr0 - wakeup_start (%eax) sgdt real_save_gdt - wakeup_start (%eax) + # gdt wont be addressable from real mode in 4g4g split + # copying it to the lower mem + xor %ecx, %ecx + movw saved_gdt, %cx + movl saved_gdt + 2, %esi + lea temp_gdt_table - wakeup_start (%eax), %edi + rep movsb movl saved_videomode, %edx movl %edx, video_mode - wakeup_start (%eax) movl acpi_video_flags, %edx diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c index 6248bf257..43943f871 100644 --- a/arch/i386/kernel/asm-offsets.c +++ b/arch/i386/kernel/asm-offsets.c @@ -52,6 +52,7 @@ void foo(void) OFFSET(TI_preempt_count, thread_info, preempt_count); OFFSET(TI_addr_limit, thread_info, addr_limit); OFFSET(TI_restart_block, thread_info, restart_block); + OFFSET(TI_sysenter_return, thread_info, sysenter_return); BLANK(); OFFSET(EXEC_DOMAIN_handler, exec_domain, handler); @@ -61,5 +62,21 @@ void foo(void) DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) - sizeof(struct tss_struct)); + DEFINE(TI_task, offsetof (struct thread_info, task)); + DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain)); + DEFINE(TI_flags, offsetof (struct thread_info, flags)); + DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count)); + DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit)); + DEFINE(TI_sysenter_return, + offsetof (struct thread_info, sysenter_return)); + DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack)); + DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack)); + DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd)); + + DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, + __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0)); + DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL)); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(task_thread_db7, + offsetof (struct task_struct, thread.debugreg[7])); } diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index fbb6a591c..c21c8e529 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -379,6 +379,9 @@ void __init identify_cpu(struct cpuinfo_x86 *c) if (disable_pse) clear_bit(X86_FEATURE_PSE, c->x86_capability); + /* hack: disable SEP unconditionally. */ + clear_bit(X86_FEATURE_SEP, c->x86_capability); + /* If the model name is still unset, do table lookup. */ if ( !c->x86_model_id[0] ) { char *p; @@ -554,12 +557,16 @@ void __init cpu_init (void) set_tss_desc(cpu,t); cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); - load_LDT(&init_mm.context); + if (cpu) + load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + if (cpu) + trap_init_virtual_GDT(); + /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); diff --git a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c index 3f7caa4ae..0b0237e8a 100644 --- a/arch/i386/kernel/cpu/cpufreq/elanfreq.c +++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c @@ -254,7 +254,6 @@ static int elanfreq_cpu_exit(struct cpufreq_policy *policy) static int __init elanfreq_setup(char *str) { max_freq = simple_strtoul(str, &str, 0); - printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); return 1; } __setup("elanfreq=", elanfreq_setup); @@ -301,7 +300,7 @@ static void __exit elanfreq_exit(void) } -module_param (max_freq, int, 0444); +MODULE_PARM (max_freq, "i"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Schwebel , Sven Geggus "); diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index fefaf45a0..000aac11e 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -124,7 +124,7 @@ static int stock_freq; /* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ static int pci_busclk = 0; -module_param (pci_busclk, int, 0444); +MODULE_PARM(pci_busclk, "i"); /* maximum duration for which the cpu may be suspended * (32us * MAX_DURATION). If no parameter is given, this defaults @@ -133,7 +133,7 @@ module_param (pci_busclk, int, 0444); * is suspended -- processing power is just 0.39% of what it used to be, * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ static int max_duration = 255; -module_param (max_duration, int, 0444); +MODULE_PARM(max_duration, "i"); /* For the default policy, we want at least some processing power * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 57c0377b4..53145bbfe 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -36,26 +36,18 @@ static unsigned int numscales=16, numvscales; static unsigned int fsb; static int minvid, maxvid; -static unsigned int minmult, maxmult; static int can_scale_voltage; static int vrmrev; /* Module parameters */ static int dont_scale_voltage; static int debug; +static int debug; -static void dprintk(const char *fmt, ...) +static void dprintk(const char *msg, ...) { - char s[256]; - va_list args; - - if (debug == 0) - return; - - va_start(args, fmt); - vsprintf(s, fmt, args); - printk(s); - va_end(args); + if (debug == 1) + printk(msg); } @@ -70,7 +62,7 @@ static int longhaul_version; static struct cpufreq_frequency_table *longhaul_table; -static unsigned int calc_speed(int mult, int fsb) +static unsigned int calc_speed (int mult, int fsb) { int khz; khz = (mult/10)*fsb; @@ -81,13 +73,17 @@ static unsigned int calc_speed(int mult, int fsb) } -static int longhaul_get_cpu_mult(void) +static int longhaul_get_cpu_mult (void) { unsigned long invalue=0,lo, hi; rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; - if (longhaul_version==2 || longhaul_version==3) { + if (longhaul_version==2) { + if (lo & (1<<27)) + invalue+=16; + } + if (longhaul_version==4) { if (lo & (1<<27)) invalue+=16; } @@ -102,7 +98,7 @@ static int longhaul_get_cpu_mult(void) * Sets a new clock ratio, and -if applicable- a new Front Side Bus */ -static void longhaul_setstate(unsigned int clock_ratio_index) +static void longhaul_setstate (unsigned int clock_ratio_index) { int speed, mult; struct cpufreq_freqs freqs; @@ -166,7 +162,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) longhaul.bits.RevisionKey = 3; wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); break; - case 3: + case 4: rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; @@ -198,7 +194,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) #define ROUNDING 0xf -static int _guess(int guess) +static int _guess (int guess, int maxmult) { int target; @@ -211,7 +207,7 @@ static int _guess(int guess) } -static int guess_fsb(void) +static int guess_fsb(int maxmult) { int speed = (cpu_khz/1000); int i; @@ -221,25 +217,25 @@ static int guess_fsb(void) speed &= ~ROUNDING; for (i=0; i<3; i++) { - if (_guess(speeds[i]) == speed) + if (_guess(speeds[i],maxmult) == speed) return speeds[i]; } return 0; } -static int __init longhaul_get_ranges(void) +static int __init longhaul_get_ranges (void) { struct cpuinfo_x86 *c = cpu_data; - unsigned long invalue; + unsigned long invalue,invalue2; + unsigned int minmult=0, maxmult=0; unsigned int multipliers[32]= { 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; unsigned int j, k = 0; union msr_longhaul longhaul; unsigned long lo, hi; - unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 }; - unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 }; + unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 }; switch (longhaul_version) { case 1: @@ -250,9 +246,9 @@ static int __init longhaul_get_ranges(void) rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<18|1<<19)) >>18; if (c->x86_model==6) - fsb = eblcr_fsb_table_v1[invalue]; + fsb = eblcr_fsb_table[invalue]; else - fsb = guess_fsb(); + fsb = guess_fsb(maxmult); break; case 2: @@ -269,38 +265,53 @@ static int __init longhaul_get_ranges(void) else minmult = multipliers[invalue]; - fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; + switch (longhaul.bits.MaxMHzFSB) { + case 0x0: fsb=133; + break; + case 0x1: fsb=100; + break; + case 0x2: printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); + return -EINVAL; + case 0x3: fsb=66; + break; + } break; - case 3: + case 4: rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - /* - * TODO: This code works, but raises a lot of questions. - * - Some Nehemiah's seem to have broken Min/MaxMHzBR's. - * We get around this by using a hardcoded multiplier of 5.0x - * for the minimimum speed, and the speed we booted up at for the max. - * This is done in longhaul_get_cpu_mult() by reading the EBLCR register. - * - According to some VIA documentation EBLCR is only - * in pre-Nehemiah C3s. How this still works is a mystery. - * We're possibly using something undocumented and unsupported, - * But it works, so we don't grumble. - */ - minmult=50; + //TODO: Nehemiah may have borken MaxMHzBR. + // need to extrapolate from FSB. + + invalue2 = longhaul.bits.MinMHzBR; + invalue = longhaul.bits.MaxMHzBR; + if (longhaul.bits.MaxMHzBR4) + invalue += 16; + maxmult=multipliers[invalue]; + maxmult=longhaul_get_cpu_mult(); - fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; + printk(KERN_INFO PFX " invalue: %ld maxmult: %d \n", invalue, maxmult); + printk(KERN_INFO PFX " invalue2: %ld \n", invalue2); + + minmult=50; + + switch (longhaul.bits.MaxMHzFSB) { + case 0x0: fsb=133; + break; + case 0x1: fsb=100; + break; + case 0x2: printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); + return -EINVAL; + case 0x3: fsb=66; + break; + } + break; } dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n", minmult/10, minmult%10, maxmult/10, maxmult%10); - - if (fsb == -1) { - printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); - return -EINVAL; - } - highest_speed = calc_speed (maxmult, fsb); lowest_speed = calc_speed (minmult,fsb); dprintk (KERN_INFO PFX "FSB: %dMHz Lowestspeed=%dMHz Highestspeed=%dMHz\n", @@ -402,7 +413,7 @@ static int longhaul_verify(struct cpufreq_policy *policy) } -static int longhaul_target(struct cpufreq_policy *policy, +static int longhaul_target (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { @@ -426,7 +437,7 @@ static unsigned int longhaul_get(unsigned int cpu) return (calc_speed (longhaul_get_cpu_mult(), fsb)); } -static int __init longhaul_cpu_init(struct cpufreq_policy *policy) +static int __init longhaul_cpu_init (struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = cpu_data; char *cpuname=NULL; @@ -469,7 +480,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) break; case 9: - longhaul_version=3; + longhaul_version=4; numscales=32; switch (c->x86_mask) { case 0 ... 1: @@ -540,7 +551,7 @@ static struct cpufreq_driver longhaul_driver = { .attr = longhaul_attr, }; -static int __init longhaul_init(void) +static int __init longhaul_init (void) { struct cpuinfo_x86 *c = cpu_data; @@ -557,17 +568,8 @@ static int __init longhaul_init(void) return -ENODEV; } -static void __exit longhaul_exit(void) +static void __exit longhaul_exit (void) { - int i=0; - unsigned int new_clock_ratio; - - while (clock_ratio[i] != maxmult) - i++; - - new_clock_ratio = longhaul_table[i].index & 0xFF; - longhaul_setstate(new_clock_ratio); - cpufreq_unregister_driver(&longhaul_driver); kfree(longhaul_table); } diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index fa01a95bb..b5daeccfa 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -133,28 +132,34 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, #endif /* notifiers */ - for_each_cpu_mask(i, affected_cpu_map) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + for_each_cpu(i) { + if (cpu_isset(i, affected_cpu_map)) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } } /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ - for_each_cpu_mask(i, affected_cpu_map) { - cpumask_t this_cpu = cpumask_of_cpu(i); + for_each_cpu(i) { + if (cpu_isset(i, affected_cpu_map)) { + cpumask_t this_cpu = cpumask_of_cpu(i); - set_cpus_allowed(current, this_cpu); - BUG_ON(smp_processor_id() != i); + set_cpus_allowed(current, this_cpu); + BUG_ON(smp_processor_id() != i); - cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); + cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); + } } set_cpus_allowed(current, cpus_allowed); /* notifiers */ - for_each_cpu_mask(i, affected_cpu_map) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + for_each_cpu(i) { + if (cpu_isset(i, affected_cpu_map)) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } } return 0; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 7aefc6764..cf008b4af 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -28,7 +28,7 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_ACPI_PROCESSOR #include #include #endif @@ -63,7 +63,7 @@ struct pst_s { u8 numpstates; }; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_ACPI_PROCESSOR union powernow_acpi_control_t { struct { unsigned long fid:5, @@ -293,7 +293,7 @@ static void change_speed (unsigned int index) } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_ACPI_PROCESSOR struct acpi_processor_performance *acpi_processor_perf; @@ -642,7 +642,7 @@ static int __init powernow_init (void) static void __exit powernow_exit (void) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_ACPI_PROCESSOR if (acpi_processor_perf) { acpi_processor_unregister_performance(acpi_processor_perf, 0); kfree(acpi_processor_perf); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 05ed9025e..63737e8cb 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -733,22 +733,10 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) continue; } - if (fid < HI_FID_TABLE_BOTTOM) { - if (cntlofreq) { - /* if both entries are the same, ignore this - * one... - */ - if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || - (powernow_table[i].index != powernow_table[cntlofreq].index)) { - printk(KERN_ERR PFX "Too many lo freq table entries\n"); - goto err_out_mem; - } - - dprintk(KERN_INFO PFX "double low frequency table entry, ignoring it.\n"); - powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; - continue; - } else - cntlofreq = i; + /* verify only 1 entry from the lo frequency table */ + if ((fid < HI_FID_TABLE_BOTTOM) && (cntlofreq++)) { + printk(KERN_ERR PFX "Too many lo freq table entries\n"); + goto err_out_mem; } if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) { @@ -869,9 +857,12 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi if (smp_processor_id() != pol->cpu) { printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu); - goto err_out; + goto sched_out; } + /* from this point, do not exit without restoring preempt and cpu */ + preempt_disable(); + if (pending_bit_stuck()) { printk(KERN_ERR PFX "failing targ, change pending bit set\n"); goto err_out; @@ -909,6 +900,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ret = 0; err_out: + preempt_enable_no_resched(); +sched_out: set_cpus_allowed(current, oldmask); schedule(); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c index 93b70f0dc..466fc6578 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c @@ -67,19 +67,28 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { /** * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * @notify: whether to call cpufreq_notify_transition for CPU speed changes * * Tries to change the SpeedStep state. */ -static void speedstep_set_state (unsigned int state) +static void speedstep_set_state (unsigned int state, unsigned int notify) { u32 pmbase; u8 pm2_blk; u8 value; unsigned long flags; + struct cpufreq_freqs freqs; if (!speedstep_chipset_dev || (state > 0x1)) return; + freqs.old = speedstep_get_processor_frequency(speedstep_processor); + freqs.new = speedstep_freqs[state].frequency; + freqs.cpu = 0; /* speedstep.c is UP only driver */ + + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + /* get PMBASE */ pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); if (!(pmbase & 0x01)) @@ -134,6 +143,9 @@ static void speedstep_set_state (unsigned int state) printk (KERN_ERR "cpufreq: change failed - I/O error\n"); } + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return; } @@ -240,47 +252,11 @@ static int speedstep_target (struct cpufreq_policy *policy, unsigned int relation) { unsigned int newstate = 0; - struct cpufreq_freqs freqs; - cpumask_t cpus_allowed, affected_cpu_map; - int i; if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) return -EINVAL; - /* no transition necessary */ - if (freqs.old == freqs.new) - return 0; - - freqs.old = speedstep_get_processor_frequency(speedstep_processor); - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = policy->cpu; - - cpus_allowed = current->cpus_allowed; - - /* only run on CPU to be set, or on its sibling */ -#ifdef CONFIG_SMP - affected_cpu_map = cpu_sibling_map[policy->cpu]; -#else - affected_cpu_map = cpumask_of_cpu(policy->cpu); -#endif - - for_each_cpu_mask(i, affected_cpu_map) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - /* switch to physical CPU where state is to be changed */ - set_cpus_allowed(current, affected_cpu_map); - - speedstep_set_state(newstate); - - /* allow to be run on all CPUs */ - set_cpus_allowed(current, cpus_allowed); - - for_each_cpu_mask(i, affected_cpu_map) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } + speedstep_set_state(newstate, 1); return 0; } @@ -303,35 +279,21 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) { int result = 0; unsigned int speed; - cpumask_t cpus_allowed,affected_cpu_map; - /* capability check */ - if (policy->cpu != 0) /* FIXME: better support for SMT in cpufreq core. Up until then, it's better to register only one CPU */ + if (policy->cpu != 0) return -ENODEV; - /* only run on CPU to be set, or on its sibling */ - cpus_allowed = current->cpus_allowed; -#ifdef CONFIG_SMP - affected_cpu_map = cpu_sibling_map[policy->cpu]; -#else - affected_cpu_map = cpumask_of_cpu(policy->cpu); -#endif - set_cpus_allowed(current, affected_cpu_map); - /* detect low and high frequency */ result = speedstep_get_freqs(speedstep_processor, &speedstep_freqs[SPEEDSTEP_LOW].frequency, &speedstep_freqs[SPEEDSTEP_HIGH].frequency, &speedstep_set_state); - if (result) { - set_cpus_allowed(current, cpus_allowed); + if (result) return result; - } /* get current speed setting */ speed = speedstep_get_processor_frequency(speedstep_processor); - set_cpus_allowed(current, cpus_allowed); if (!speed) return -EIO; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index 6aa31cd5a..2b1f2fbee 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -139,24 +139,37 @@ static int speedstep_get_state (void) : "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0) ); - return (state & 1); + return state; } /** * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * @notify: whether to call cpufreq_notify_transition * */ -static void speedstep_set_state (unsigned int state) +static void speedstep_set_state (unsigned int state, unsigned int notify) { - unsigned int result = 0, command, new_state; + unsigned int old_state, result = 0, command, new_state; unsigned long flags; + struct cpufreq_freqs freqs; unsigned int function=SET_SPEEDSTEP_STATE; unsigned int retry = 0; if (state > 0x1) return; + old_state = speedstep_get_state(); + freqs.old = speedstep_freqs[old_state].frequency; + freqs.new = speedstep_freqs[state].frequency; + freqs.cpu = 0; /* speedstep.c is UP only driver */ + + if (old_state == state) + return; + + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + /* Disable IRQs */ local_irq_save(flags); @@ -185,6 +198,9 @@ static void speedstep_set_state (unsigned int state) printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result); } + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return; } @@ -201,21 +217,11 @@ static int speedstep_target (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { unsigned int newstate = 0; - struct cpufreq_freqs freqs; if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) return -EINVAL; - freqs.old = speedstep_freqs[speedstep_get_state()].frequency; - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = 0; /* speedstep.c is UP only driver */ - - if (freqs.old == freqs.new) - return 0; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - speedstep_set_state(newstate); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + speedstep_set_state(newstate, 1); return 0; } diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index 09acdd76b..f78243fea 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "cpu.h" @@ -19,8 +20,6 @@ #include #endif -extern int trap_init_f00f_bug(void); - #ifdef CONFIG_X86_INTEL_USERCOPY /* * Alignment at which movsl is preferred for bulk memory copies. @@ -147,7 +146,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); + trap_init_virtual_IDT(); printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 99b8d1116..423429491 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -27,7 +27,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL, + NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", /* Transmeta-defined */ diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c index 6b4a8f3cc..3304416c6 100644 --- a/arch/i386/kernel/doublefault.c +++ b/arch/i386/kernel/doublefault.c @@ -8,12 +8,13 @@ #include #include #include +#include #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) -#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000) +#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START)) static void doublefault_fn(void) { @@ -39,8 +40,8 @@ static void doublefault_fn(void) printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", t->eax, t->ebx, t->ecx, t->edx); - printk("esi = %08lx, edi = %08lx\n", - t->esi, t->edi); + printk("esi = %08lx, edi = %08lx, ebp = %08lx\n", + t->esi, t->edi, t->ebp); } } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 7b6856363..bb91de327 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -43,8 +43,10 @@ #include #include #include +#include #include #include +#include #include #include #include "irq_vectors.h" @@ -81,7 +83,102 @@ VM_MASK = 0x00020000 #define resume_kernel restore_all #endif -#define SAVE_ALL \ +#ifdef CONFIG_X86_HIGH_ENTRY + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +/* + * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu, + * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is + * left stale, so we must check whether to repeat the real stack calculation. + */ +#define repeat_if_esp_changed \ + xorl %esp, %ebp; \ + testl $-THREAD_SIZE, %ebp; \ + jnz 0b +#else +#define repeat_if_esp_changed +#endif + +/* clobbers ebx, edx and ebp */ + +#define __SWITCH_KERNELSPACE \ + cmpl $0xff000000, %esp; \ + jb 1f; \ + \ + /* \ + * switch pagetables and load the real stack, \ + * keep the stack offset: \ + */ \ + \ + movl $swapper_pg_dir-__PAGE_OFFSET, %edx; \ + \ + /* GET_THREAD_INFO(%ebp) intermixed */ \ +0: \ + movl %esp, %ebp; \ + movl %esp, %ebx; \ + andl $(-THREAD_SIZE), %ebp; \ + andl $(THREAD_SIZE-1), %ebx; \ + orl TI_real_stack(%ebp), %ebx; \ + repeat_if_esp_changed; \ + \ + movl %edx, %cr3; \ + movl %ebx, %esp; \ +1: + +#endif + + +#define __SWITCH_USERSPACE \ + /* interrupted any of the user return paths? */ \ + \ + movl EIP(%esp), %eax; \ + \ + cmpl $int80_ret_start_marker, %eax; \ + jb 33f; /* nope - continue with sysexit check */\ + cmpl $int80_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ +33: \ + cmpl $sysexit_ret_start_marker, %eax; \ + jb 44f; /* nope - continue with user check */ \ + cmpl $sysexit_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ + /* return to userspace? */ \ +44: \ + movl EFLAGS(%esp),%ecx; \ + movb CS(%esp),%cl; \ + testl $(VM_MASK | 3),%ecx; \ + jz 2f; \ +22: \ + /* \ + * switch to the virtual stack, then switch to \ + * the userspace pagetables. \ + */ \ + \ + GET_THREAD_INFO(%ebp); \ + movl TI_virtual_stack(%ebp), %edx; \ + movl TI_user_pgd(%ebp), %ecx; \ + \ + movl %esp, %ebx; \ + andl $(THREAD_SIZE-1), %ebx; \ + orl %ebx, %edx; \ +int80_ret_start_marker: \ + movl %edx, %esp; \ + movl %ecx, %cr3; \ + \ + __RESTORE_ALL; \ +int80_ret_end_marker: \ +2: + +#else /* !CONFIG_X86_HIGH_ENTRY */ + +#define __SWITCH_KERNELSPACE +#define __SWITCH_USERSPACE + +#endif + +#define __SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ @@ -96,7 +193,7 @@ VM_MASK = 0x00020000 movl %edx, %ds; \ movl %edx, %es; -#define RESTORE_INT_REGS \ +#define __RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -105,29 +202,28 @@ VM_MASK = 0x00020000 popl %ebp; \ popl %eax -#define RESTORE_REGS \ - RESTORE_INT_REGS; \ -1: popl %ds; \ -2: popl %es; \ +#define __RESTORE_REGS \ + __RESTORE_INT_REGS; \ +111: popl %ds; \ +222: popl %es; \ .section .fixup,"ax"; \ -3: movl $0,(%esp); \ - jmp 1b; \ -4: movl $0,(%esp); \ - jmp 2b; \ +444: movl $0,(%esp); \ + jmp 111b; \ +555: movl $0,(%esp); \ + jmp 222b; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,3b; \ - .long 2b,4b; \ + .long 111b,444b;\ + .long 222b,555b;\ .previous - -#define RESTORE_ALL \ - RESTORE_REGS \ +#define __RESTORE_ALL \ + __RESTORE_REGS \ addl $4, %esp; \ -1: iret; \ +333: iret; \ .section .fixup,"ax"; \ -2: sti; \ +666: sti; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ @@ -136,10 +232,18 @@ VM_MASK = 0x00020000 .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,2b; \ + .long 333b,666b;\ .previous +#define SAVE_ALL \ + __SAVE_ALL; \ + __SWITCH_KERNELSPACE; + +#define RESTORE_ALL \ + __SWITCH_USERSPACE; \ + __RESTORE_ALL; +.section .entry.text,"ax" ENTRY(lcall7) pushfl # We get a different stack layout with call @@ -238,20 +342,15 @@ sysenter_past_esp: pushl %ebp pushfl pushl $(__USER_CS) - pushl $SYSENTER_RETURN - -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_fault -1: movl (%ebp),%ebp -.section __ex_table,"a" - .align 4 - .long 1b,syscall_fault -.previous - + /* + * Push current_thread_info()->sysenter_return to the stack. + * A tiny bit of offset fixup is necessary - 4*4 means the 4 words + * pushed above, and the word being pushed now: + */ + pushl (TI_sysenter_return-THREAD_SIZE+4*4)(%esp) + /* + * No six-argument syscall is ever used with sysenter. + */ pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) @@ -266,12 +365,34 @@ sysenter_past_esp: movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + + GET_THREAD_INFO(%ebp) + movl TI_virtual_stack(%ebp), %edx + movl TI_user_pgd(%ebp), %ecx + movl %esp, %ebx + andl $(THREAD_SIZE-1), %ebx + orl %ebx, %edx +sysexit_ret_start_marker: + movl %edx, %esp + movl %ecx, %cr3 + /* + * only ebx is not restored by the userspace sysenter vsyscall + * code, it assumes it to be callee-saved. + */ + movl EBX(%esp), %ebx +#endif + /* if something modifies registers it must also disable sysexit */ movl EIP(%esp), %edx movl OLDESP(%esp), %ecx sti sysexit - +#ifdef CONFIG_X86_SWITCH_PAGETABLES +sysexit_ret_end_marker: + nop +#endif # system call handler stub ENTRY(system_call) @@ -321,6 +442,22 @@ work_notifysig: # deal with pending signals and # vm86-space xorl %edx, %edx call do_notify_resume + +#if CONFIG_X86_HIGH_ENTRY + /* + * Reload db7 if necessary: + */ + movl TI_flags(%ebp), %ecx + testb $_TIF_DB7, %cl + jnz work_db7 + + jmp restore_all + +work_db7: + movl TI_task(%ebp), %edx; + movl task_thread_db7(%edx), %edx; + movl %edx, %db7; +#endif jmp restore_all ALIGN @@ -357,14 +494,6 @@ syscall_exit_work: call do_syscall_trace jmp resume_userspace - ALIGN -syscall_fault: - pushl %eax # save orig_eax - SAVE_ALL - GET_THREAD_INFO(%ebp) - movl $-EFAULT,EAX(%esp) - jmp resume_userspace - ALIGN syscall_badsys: movl $-ENOSYS,EAX(%esp) @@ -376,7 +505,7 @@ syscall_badsys: */ .data ENTRY(interrupt) -.text +.previous vector=0 ENTRY(irq_entries_start) @@ -386,7 +515,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .data .long 1b -.text +.previous vector=vector+1 .endr @@ -427,12 +556,17 @@ error_code: movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl %esp, %edx pushl %esi # push the error code - pushl %edx # push the pt_regs pointer movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es + +/* clobbers edx, ebx and ebp */ + __SWITCH_KERNELSPACE + + leal 4(%esp), %edx # prepare pt_regs + pushl %edx # push pt_regs + call *%edi addl $8, %esp jmp ret_from_exception @@ -523,7 +657,7 @@ nmi_stack_correct: pushl %edx call do_nmi addl $8, %esp - RESTORE_ALL + jmp restore_all nmi_stack_fixup: FIX_STACK(12,nmi_stack_correct, 1) @@ -600,6 +734,8 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code +.previous + .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ @@ -824,7 +960,15 @@ ENTRY(sys_call_table) .long sys_madvise .long sys_getdents64 /* 220 */ .long sys_fcntl64 - .long sys_ni_syscall /* reserved for TUX */ +#ifdef CONFIG_TUX + .long __sys_tux +#else +# ifdef CONFIG_TUX_MODULE + .long sys_tux +# else + .long sys_ni_syscall +# endif +#endif .long sys_ni_syscall .long sys_gettid .long sys_readahead /* 225 */ @@ -875,7 +1019,7 @@ ENTRY(sys_call_table) .long sys_tgkill /* 270 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ + .long sys_vserver .long sys_mbind .long sys_get_mempolicy .long sys_set_mempolicy diff --git a/arch/i386/kernel/entry_trampoline.c b/arch/i386/kernel/entry_trampoline.c new file mode 100644 index 000000000..db6f6eaa8 --- /dev/null +++ b/arch/i386/kernel/entry_trampoline.c @@ -0,0 +1,75 @@ +/* + * linux/arch/i386/kernel/entry_trampoline.c + * + * (C) Copyright 2003 Ingo Molnar + * + * This file contains the needed support code for 4GB userspace + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text; + +void __init init_entry_mappings(void) +{ +#ifdef CONFIG_X86_HIGH_ENTRY + + void *tramp; + int p; + + /* + * We need a high IDT and GDT for the 4G/4G split: + */ + trap_init_virtual_IDT(); + + __set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL_EXEC); + __set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL_EXEC); + tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0); + + printk("mapped 4G/4G trampoline to %p.\n", tramp); + BUG_ON((void *)&__start___entry_text != tramp); + /* + * Virtual kernel stack: + */ + BUG_ON(__kmap_atomic_vaddr(KM_VSTACK_TOP) & (THREAD_SIZE-1)); + BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE); + BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE); + + /* + * set up the initial thread's virtual stack related + * fields: + */ + for (p = 0; p < ARRAY_SIZE(current->thread.stack_page); p++) + current->thread.stack_page[p] = virt_to_page((char *)current->thread_info + (p*PAGE_SIZE)); + + current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK_TOP); + + for (p = 0; p < ARRAY_SIZE(current->thread.stack_page); p++) { + __kunmap_atomic_type(KM_VSTACK_TOP-p); + __kmap_atomic(current->thread.stack_page[p], KM_VSTACK_TOP-p); + } +#endif + current->thread_info->real_stack = (void *)current->thread_info; + current->thread_info->user_pgd = NULL; + current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE; +} + + + +void __init entry_trampoline_setup(void) +{ + /* + * old IRQ entries set up by the boot code will still hang + * around - they are a sign of hw trouble anyway, now they'll + * produce a double fault message. + */ + trap_init_virtual_GDT(); +} diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 3f868ea50..69bad9bd0 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -153,6 +153,32 @@ ENTRY(startup_32_smp) orl %edx,%eax movl %eax,%cr4 + btl $5, %eax # check if PAE is enabled + jnc 6f + + /* Check if extended functions are implemented */ + movl $0x80000000, %eax + cpuid + cmpl $0x80000000, %eax + jbe 6f + mov $0x80000001, %eax + cpuid + /* Execute Disable bit supported? */ + btl $20, %edx + jnc 6f + + /* Setup EFER (Extended Feature Enable Register) */ + movl $0xc0000080, %ecx + rdmsr + + btsl $11, %eax + /* Make changes effective */ + wrmsr + +6: + /* cpuid clobbered ebx, set it up again: */ + xorl %ebx,%ebx + incl %ebx 3: #endif /* CONFIG_SMP */ diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 582f093ad..2df68a3bb 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -93,7 +93,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__udelay); @@ -107,13 +106,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +#if !defined(CONFIG_X86_UACCESS_INDIRECT) EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__direct_strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__copy_from_user_ll); EXPORT_SYMBOL(__copy_to_user_ll); EXPORT_SYMBOL(strnlen_user); +#else /* CONFIG_X86_UACCESS_INDIRECT */ +EXPORT_SYMBOL(direct_csum_partial_copy_generic); +#endif EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_free_coherent); diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c index 3da92c23d..cc5628f08 100644 --- a/arch/i386/kernel/i387.c +++ b/arch/i386/kernel/i387.c @@ -227,6 +227,7 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd ) static int convert_fxsr_to_user( struct _fpstate __user *buf, struct i387_fxsave_struct *fxsave ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpreg __user *to; struct _fpxreg *from; @@ -243,23 +244,25 @@ static int convert_fxsr_to_user( struct _fpstate __user *buf, if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; - to = &buf->_st[0]; + to = tmp; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long __user *t = (unsigned long __user *)to; unsigned long *f = (unsigned long *)from; - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f+1); + to->exponent = from->exponent; } + if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8]))) + return 1; return 0; } static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpxreg *to; struct _fpreg __user *from; @@ -267,6 +270,8 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; + if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8]))) + return 1; fxsave->cwd = (unsigned short)(env[0] & 0xffff); fxsave->swd = (unsigned short)(env[1] & 0xffff); @@ -278,15 +283,14 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; + from = tmp; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long __user *f = (unsigned long __user *)from; - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f + 1); + to->exponent = from->exponent; } return 0; } diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index 976e6bc16..dfe1a1e3a 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm); */ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; + { INIT_THREAD_INFO(init_task, init_thread_union) }; /* * Initial task structure. @@ -44,5 +44,5 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 579b3282e..d57a137e3 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -77,10 +77,8 @@ static void register_irq_proc (unsigned int irq); /* * per-CPU IRQ handling stacks */ -#ifdef CONFIG_4KSTACKS union irq_ctx *hardirq_ctx[NR_CPUS]; union irq_ctx *softirq_ctx[NR_CPUS]; -#endif /* * Special irq handlers. @@ -223,9 +221,6 @@ asmlinkage int handle_IRQ_event(unsigned int irq, int status = 1; /* Force the "do bottom halves" bit */ int retval = 0; - if (!(action->flags & SA_INTERRUPT)) - local_irq_enable(); - do { status |= action->flags; retval |= action->handler(irq, action->dev_id, regs); @@ -245,7 +240,7 @@ static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) printk(KERN_ERR "irq event %d: bogus return value %x\n", irq, action_ret); } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); + printk(KERN_ERR "irq %d: nobody cared! (screaming interrupt?)\n", irq); } dump_stack(); printk(KERN_ERR "handlers:\n"); @@ -488,7 +483,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) * useful for irq hardware that does not mask cleanly in an * SMP environment. */ -#ifdef CONFIG_4KSTACKS for (;;) { irqreturn_t action_ret; @@ -514,6 +508,8 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) /* build the stack frame on the IRQ stack */ isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); irqctx->tinfo.task = curctx->tinfo.task; + irqctx->tinfo.real_stack = curctx->tinfo.real_stack; + irqctx->tinfo.virtual_stack = curctx->tinfo.virtual_stack; irqctx->tinfo.previous_esp = current_stack_pointer(); *--isp = (u32) action; @@ -541,23 +537,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) desc->status &= ~IRQ_PENDING; } -#else - - for (;;) { - irqreturn_t action_ret; - - spin_unlock(&desc->lock); - - action_ret = handle_IRQ_event(irq, ®s, action); - - spin_lock(&desc->lock); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret); - if (likely(!(desc->status & IRQ_PENDING))) - break; - desc->status &= ~IRQ_PENDING; - } -#endif desc->status &= ~IRQ_INPROGRESS; out: @@ -1116,7 +1095,6 @@ void init_irq_proc (void) } -#ifdef CONFIG_4KSTACKS static char softirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned"))); static char hardirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned"))); @@ -1170,6 +1148,8 @@ asmlinkage void do_softirq(void) curctx = current_thread_info(); irqctx = softirq_ctx[smp_processor_id()]; irqctx->tinfo.task = curctx->task; + irqctx->tinfo.real_stack = curctx->real_stack; + irqctx->tinfo.virtual_stack = curctx->virtual_stack; irqctx->tinfo.previous_esp = current_stack_pointer(); /* build the stack frame on the softirq stack */ @@ -1190,4 +1170,3 @@ asmlinkage void do_softirq(void) } EXPORT_SYMBOL(do_softirq); -#endif diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index c07c21df7..d32b479ba 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -2,7 +2,7 @@ * linux/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds - * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 1999, 2003 Ingo Molnar */ #include @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -29,34 +31,31 @@ static void flush_ldt(void *null) static int alloc_ldt(mm_context_t *pc, int mincount, int reload) { - void *oldldt; - void *newldt; - int oldsize; + int oldsize, newsize, i; if (mincount <= pc->size) return 0; + /* + * LDT got larger - reallocate if necessary. + */ oldsize = pc->size; mincount = (mincount+511)&(~511); - if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) - newldt = vmalloc(mincount*LDT_ENTRY_SIZE); - else - newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); - - if (!newldt) - return -ENOMEM; - - if (oldsize) - memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); - oldldt = pc->ldt; - memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - pc->ldt = newldt; - wmb(); + newsize = mincount*LDT_ENTRY_SIZE; + for (i = 0; i < newsize; i += PAGE_SIZE) { + int nr = i/PAGE_SIZE; + BUG_ON(i >= 64*1024); + if (!pc->ldt_pages[nr]) { + pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER); + if (!pc->ldt_pages[nr]) + return -ENOMEM; + clear_highpage(pc->ldt_pages[nr]); + } + } pc->size = mincount; - wmb(); - if (reload) { #ifdef CONFIG_SMP cpumask_t mask; + preempt_disable(); load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); @@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) load_LDT(pc); #endif } - if (oldsize) { - if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(oldldt); - else - kfree(oldldt); - } return 0; } static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { - int err = alloc_ldt(new, old->size, 0); - if (err < 0) + int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE; + + err = alloc_ldt(new, size, 0); + if (err < 0) { + new->size = 0; return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + } + for (i = 0; i < nr_pages; i++) + copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0); return 0; } @@ -96,6 +94,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) init_MUTEX(&mm->context.sem); mm->context.size = 0; + memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES); old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); @@ -107,23 +106,21 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) /* * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ void destroy_context(struct mm_struct *mm) { - if (mm->context.size) { - if (mm == current->active_mm) - clear_LDT(); - if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(mm->context.ldt); - else - kfree(mm->context.ldt); - mm->context.size = 0; - } + int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) + __free_page(mm->context.ldt_pages[i]); + mm->context.size = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) { - int err; + int err, i; unsigned long size; struct mm_struct * mm = current->mm; @@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) size = bytecount; err = 0; - if (copy_to_user(ptr, mm->context.ldt, size)) - err = -EFAULT; + /* + * This is necessary just in case we got here straight from a + * context-switch where the ptes were set but no tlb flush + * was done yet. We rather avoid doing a TLB flush in the + * context-switch path and do it here instead. + */ + __flush_tlb_global(); + + for (i = 0; i < size; i += PAGE_SIZE) { + int nr = i / PAGE_SIZE, bytes; + char *kaddr = kmap(mm->context.ldt_pages[nr]); + + bytes = size - i; + if (bytes > PAGE_SIZE) + bytes = PAGE_SIZE; + if (copy_to_user(ptr + i, kaddr, size - i)) + err = -EFAULT; + kunmap(mm->context.ldt_pages[nr]); + } up(&mm->context.sem); if (err < 0) return err; @@ -158,7 +172,7 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount) err = 0; address = &default_ldt[0]; - size = 5*sizeof(struct desc_struct); + size = 5*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; @@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); + /* + * No rescheduling allowed from this point to the install. + * + * We do a TLB flush for the same reason as in the read_ldt() path. + */ + preempt_disable(); + __flush_tlb_global(); + lp = (__u32 *) ((ldt_info.entry_number << 3) + + (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0)); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -221,6 +243,7 @@ install: *lp = entry_1; *(lp+1) = entry_2; error = 0; + preempt_enable(); out_unlock: up(&mm->context.sem); @@ -248,3 +271,26 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecoun } return ret; } + +/* + * load one particular LDT into the current CPU + */ +void load_LDT_nolock(mm_context_t *pc, int cpu) +{ + struct page **pages = pc->ldt_pages; + int count = pc->size; + int nr_pages, i; + + if (likely(!count)) { + pages = &default_ldt_page; + count = 5; + } + nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + __kunmap_atomic_type(KM_LDT_PAGE0 - i); + __kmap_atomic(pages[i], KM_LDT_PAGE0 - i); + } + set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count); + load_LDT_desc(); +} diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 198b17c7e..07ddfdf0c 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -363,7 +363,7 @@ static void do_update_one (void * unused) struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (uci->mc == NULL) { - printk(KERN_INFO "microcode: No suitable data for cpu %d\n", cpu_num); + printk(KERN_INFO "microcode: No new microdata for cpu %d\n", cpu_num); return; } diff --git a/arch/i386/kernel/module.c b/arch/i386/kernel/module.c index e8258ad35..5149c8a62 100644 --- a/arch/i386/kernel/module.c +++ b/arch/i386/kernel/module.c @@ -32,7 +32,7 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return vmalloc(size); + return vmalloc_exec(size); } diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index e8ed286c8..55e4c29a3 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -675,7 +675,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 16d91e3e1..eea3c579c 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -477,7 +477,7 @@ void nmi_watchdog_tick (struct pt_regs * regs) * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; - if (alert_counter[cpu] == 5*nmi_hz) { + if (alert_counter[cpu] == 60*nmi_hz) { spin_lock(&nmi_print_lock); /* * We are in trouble anyway, lets at least try diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index de22204a7..ade806654 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -46,6 +48,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -202,7 +205,7 @@ static int __init idle_setup (char *str) if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); pm_idle = poll_idle; -#ifdef CONFIG_X86_SMP +#ifdef CONFIG_SMP if (smp_num_siblings > 1) printk("WARNING: polling idle and HT enabled, performance may degrade.\n"); #endif @@ -311,6 +314,9 @@ void flush_thread(void) struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); +#ifdef CONFIG_X86_HIGH_ENTRY + clear_thread_flag(TIF_DB7); +#endif memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. @@ -324,9 +330,8 @@ void release_thread(struct task_struct *dead_task) if (dead_task->mm) { // temporary debugging check if (dead_task->mm->context.size) { - printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + printk("WARNING: dead process %8s still has LDT? <%d>\n", dead_task->comm, - dead_task->mm->context.ldt, dead_task->mm->context.size); BUG(); } @@ -350,7 +355,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, { struct pt_regs * childregs; struct task_struct *tsk; - int err; + int err, i; childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; struct_cpy(childregs, regs); @@ -361,7 +366,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, p->thread.esp = (unsigned long) childregs; p->thread.esp0 = (unsigned long) (childregs+1); + /* + * get the two stack pages, for the virtual stack. + * + * IMPORTANT: this code relies on the fact that the task + * structure is an THREAD_SIZE aligned piece of physical memory. + */ + for (i = 0; i < ARRAY_SIZE(p->thread.stack_page); i++) + p->thread.stack_page[i] = + virt_to_page((unsigned long)p->thread_info + (i*PAGE_SIZE)); + p->thread.eip = (unsigned long) ret_from_fork; + p->thread_info->real_stack = p->thread_info; savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); @@ -512,11 +528,45 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ __unlazy_fpu(prev_p); + if (next_p->mm) + load_user_cs_desc(cpu, next_p->mm); +#ifdef CONFIG_X86_HIGH_ENTRY +{ + int i; + /* + * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is + * needed because otherwise NMIs could interrupt the + * user-return code with a virtual stack and stale TLBs.) + */ + for (i = 0; i < ARRAY_SIZE(next->stack_page); i++) { + __kunmap_atomic_type(KM_VSTACK_TOP-i); + __kmap_atomic(next->stack_page[i], KM_VSTACK_TOP-i); + } + /* + * NOTE: here we rely on the task being the stack as well + */ + next_p->thread_info->virtual_stack = + (void *)__kmap_atomic_vaddr(KM_VSTACK_TOP); +} +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + /* + * If next was preempted on entry from userspace to kernel, + * and now it's on a different cpu, we need to adjust %esp. + * This assumes that entry.S does not copy %esp while on the + * virtual stack (with interrupts enabled): which is so, + * except within __SWITCH_KERNELSPACE itself. + */ + if (unlikely(next->esp >= TASK_SIZE)) { + next->esp &= THREAD_SIZE - 1; + next->esp |= (unsigned long) next_p->thread_info->virtual_stack; + } +#endif +#endif /* * Reload esp0, LDT and the page table pointer: */ - load_esp0(tss, next); + load_virtual_esp0(tss, next_p); /* * Load the per-thread Thread-Local Storage descriptor. @@ -776,3 +826,303 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) return 0; } +/* + * Get a random word: + */ +static inline unsigned int get_random_int(void) +{ + unsigned int val = 0; + + if (!exec_shield_randomize) + return 0; + +#ifdef CONFIG_X86_HAS_TSC + rdtscl(val); +#endif + val += current->pid + jiffies + (int)&val; + + /* + * Use IP's RNG. It suits our purpose perfectly: it re-keys itself + * every second, from the entropy pool (and thus creates a limited + * drain on it), and uses halfMD4Transform within the second. We + * also spice it with the TSC (if available), jiffies, PID and the + * stack address: + */ + return secure_ip_id(val); +} + +unsigned long arch_align_stack(unsigned long sp) +{ + if (current->flags & PF_RELOCEXEC) + sp -= ((get_random_int() % 65536) << 4); + return sp & ~0xf; +} + +#if SHLIB_BASE >= 0x01000000 +# error SHLIB_BASE must be under 16MB! +#endif + +static unsigned long +arch_get_unmapped_nonexecutable_area(struct mm_struct *mm, unsigned long addr, unsigned long len) +{ + struct vm_area_struct *vma, *prev_vma; + unsigned long stack_limit; + int first_time = 1; + + if (!mm->mmap_top) { + printk("hm, %s:%d, !mmap_top.\n", current->comm, current->pid); + mm->mmap_top = mmap_top(); + } + stack_limit = mm->mmap_top; + + /* requested length too big for entire address space */ + if (len > TASK_SIZE) + return -ENOMEM; + + /* dont allow allocations above current stack limit */ + if (mm->non_executable_cache > stack_limit) + mm->non_executable_cache = stack_limit; + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + /* make sure it can fit in the remaining address space */ + if (mm->non_executable_cache < len) + return -ENOMEM; + + /* either no address requested or cant fit in requested address hole */ +try_again: + addr = (mm->non_executable_cache - len)&PAGE_MASK; + do { + if (!(vma = find_vma_prev(mm, addr, &prev_vma))) + return -ENOMEM; + + /* new region fits between prev_vma->vm_end and vma->vm_start, use it */ + if (addr+len <= vma->vm_start && (!prev_vma || (addr >= prev_vma->vm_end))) { + /* remember the address as a hint for next time */ + mm->non_executable_cache = addr; + return addr; + + /* pull non_executable_cache down to the first hole */ + } else if (mm->non_executable_cache == vma->vm_end) + mm->non_executable_cache = vma->vm_start; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + } while (len <= vma->vm_start); + /* if hint left us with no space for the requested mapping try again */ + if (first_time) { + first_time = 0; + mm->non_executable_cache = stack_limit; + goto try_again; + } + return -ENOMEM; +} + +static unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len) +{ + unsigned long range = end - len - start; + if (end <= start + len) + return 0; + return PAGE_ALIGN(get_random_int() % range + start); +} + +static inline unsigned long +stock_arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start_addr; + + if (len > TASK_SIZE) + return -ENOMEM; + + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + start_addr = addr = mm->free_area_cache; + +full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) { + /* + * Start a new search - just in case we missed + * some holes. + */ + if (start_addr != TASK_UNMAPPED_BASE) { + start_addr = addr = TASK_UNMAPPED_BASE; + goto full_search; + } + return -ENOMEM; + } + if (!vma || addr + len <= vma->vm_start) { + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } + addr = vma->vm_end; + } +} + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0, + unsigned long len0, unsigned long pgoff, unsigned long flags, + unsigned long prot) +{ + unsigned long addr = addr0, len = len0; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int ascii_shield = 0; + unsigned long tmp; + + /* + * Fall back to the old layout: + */ + if (!(current->flags & PF_RELOCEXEC)) + return stock_arch_get_unmapped_area(filp, addr0, len0, pgoff, flags); + if (len > TASK_SIZE) + return -ENOMEM; + + if (!addr && (prot & PROT_EXEC) && !(flags & MAP_FIXED)) + addr = randomize_range(SHLIB_BASE, 0x01000000, len); + + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) { + return addr; + } + } + + if (prot & PROT_EXEC) { + ascii_shield = 1; + addr = SHLIB_BASE; + } else { + /* this can fail if the stack was unlimited */ + if ((tmp = arch_get_unmapped_nonexecutable_area(mm, addr, len)) != -ENOMEM) + return tmp; +search_upper: + addr = PAGE_ALIGN(arch_align_stack(TASK_UNMAPPED_BASE)); + } + + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) { + return -ENOMEM; + } + if (!vma || addr + len <= vma->vm_start) { + /* + * Must not let a PROT_EXEC mapping get into the + * brk area: + */ + if (ascii_shield && (addr + len > mm->brk)) { + ascii_shield = 0; + goto search_upper; + } + /* + * Up until the brk area we randomize addresses + * as much as possible: + */ + if (ascii_shield && (addr >= 0x01000000)) { + tmp = randomize_range(0x01000000, mm->brk, len); + vma = find_vma(mm, tmp); + if (TASK_SIZE - len >= tmp && + (!vma || tmp + len <= vma->vm_start)) + return tmp; + } + /* + * Ok, randomization didnt work out - return + * the result of the linear search: + */ + return addr; + } + addr = vma->vm_end; + } +} + +void arch_add_exec_range(struct mm_struct *mm, unsigned long limit) +{ + if (limit > mm->context.exec_limit) { + mm->context.exec_limit = limit; + set_user_cs(&mm->context.user_cs, limit); + if (mm == current->mm) + load_user_cs_desc(smp_processor_id(), mm); + } +} + +void arch_remove_exec_range(struct mm_struct *mm, unsigned long old_end) +{ + struct vm_area_struct *vma; + unsigned long limit = 0; + + if (old_end == mm->context.exec_limit) { + for (vma = mm->mmap; vma; vma = vma->vm_next) + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; + + mm->context.exec_limit = limit; + set_user_cs(&mm->context.user_cs, limit); + if (mm == current->mm) + load_user_cs_desc(smp_processor_id(), mm); + } +} + +void arch_flush_exec_range(struct mm_struct *mm) +{ + mm->context.exec_limit = 0; + set_user_cs(&mm->context.user_cs, 0); +} + +/* + * Generate random brk address between 128MB and 196MB. (if the layout + * allows it.) + */ +void randomize_brk(unsigned long old_brk) +{ + unsigned long new_brk, range_start, range_end; + + range_start = 0x08000000; + if (current->mm->brk >= range_start) + range_start = current->mm->brk; + range_end = range_start + 0x02000000; + new_brk = randomize_range(range_start, range_end, 0); + if (new_brk) + current->mm->brk = new_brk; +} + +/* + * Top of mmap area (just below the process stack). + * leave an at least ~128 MB hole. Randomize it. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +unsigned long mmap_top(void) +{ + unsigned long gap = 0; + + gap = current->rlim[RLIMIT_STACK].rlim_cur; + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + + gap = arch_align_stack(gap) & PAGE_MASK; + + return TASK_SIZE - gap; +} + diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 0cf2f1187..6f3a62694 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -259,6 +259,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index c8936c4e5..309efc17a 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -155,12 +155,11 @@ void machine_real_restart(unsigned char *code, int length) CMOS_WRITE(0x00, 0x8f); spin_unlock_irqrestore(&rtc_lock, flags); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + /* + * Remap the first 16 MB of RAM (which includes the kernel image) + * at virtual address zero: + */ + setup_identity_mappings(swapper_pg_dir, 0, LOW_MAPPINGS_SIZE); /* * Use `swapper_pg_dir' as our page directory. diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index c23188191..3c50ed275 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -129,28 +129,29 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) */ static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) +restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *__sc, int *peax) { - unsigned int err = 0; + struct sigcontext scratch; /* 88 bytes of scratch area */ /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; -#define COPY(x) err |= __get_user(regs->x, &sc->x) + if (copy_from_user(&scratch, __sc, sizeof(scratch))) + return -EFAULT; + +#define COPY(x) regs->x = scratch.x #define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ loadsegment(seg,tmp); } #define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | X86_EFLAGS_DF | \ @@ -173,27 +174,23 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax COPY_SEG_STRICT(ss); { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); + unsigned int tmpflags = scratch.eflags; regs->eflags = (regs->eflags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_eax = -1; /* disable syscall checks */ } { - struct _fpstate __user * buf; - err |= __get_user(buf, &sc->fpstate); + struct _fpstate * buf = scratch.fpstate; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + return -EFAULT; + if (restore_i387(buf)) + return -EFAULT; } } - err |= __get_user(*peax, &sc->eax); - return err; - -badframe: - return 1; + *peax = scratch.eax; + return 0; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -262,46 +259,47 @@ badframe: */ static int -setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, +setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + struct sigcontext sc; /* 88 bytes of scratch area */ + int tmp; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->gs); + *(unsigned int *)&sc.gs = tmp; __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->fs); - - err |= __put_user(regs->xes, (unsigned int __user *)&sc->es); - err |= __put_user(regs->xds, (unsigned int __user *)&sc->ds); - err |= __put_user(regs->edi, &sc->edi); - err |= __put_user(regs->esi, &sc->esi); - err |= __put_user(regs->ebp, &sc->ebp); - err |= __put_user(regs->esp, &sc->esp); - err |= __put_user(regs->ebx, &sc->ebx); - err |= __put_user(regs->edx, &sc->edx); - err |= __put_user(regs->ecx, &sc->ecx); - err |= __put_user(regs->eax, &sc->eax); - err |= __put_user(current->thread.trap_no, &sc->trapno); - err |= __put_user(current->thread.error_code, &sc->err); - err |= __put_user(regs->eip, &sc->eip); - err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); - err |= __put_user(regs->esp, &sc->esp_at_signal); - err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss); + *(unsigned int *)&sc.fs = tmp; + *(unsigned int *)&sc.es = regs->xes; + *(unsigned int *)&sc.ds = regs->xds; + sc.edi = regs->edi; + sc.esi = regs->esi; + sc.ebp = regs->ebp; + sc.esp = regs->esp; + sc.ebx = regs->ebx; + sc.edx = regs->edx; + sc.ecx = regs->ecx; + sc.eax = regs->eax; + sc.trapno = current->thread.trap_no; + sc.err = current->thread.error_code; + sc.eip = regs->eip; + *(unsigned int *)&sc.cs = regs->xcs; + sc.eflags = regs->eflags; + sc.esp_at_signal = regs->esp; + *(unsigned int *)&sc.ss = regs->xss; tmp = save_i387(fpstate); if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + return 1; + sc.fpstate = tmp ? fpstate : NULL; /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(current->thread.cr2, &sc->cr2); + sc.oldmask = mask; + sc.cr2 = current->thread.cr2; - return err; + if (copy_to_user(__sc, &sc, sizeof(sc))) + return 1; + return 0; } /* @@ -333,7 +331,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) /* These symbols are defined with the addresses in the vsyscall page. See vsyscall-sigreturn.S. */ -extern void __kernel_sigreturn, __kernel_rt_sigreturn; +extern char __kernel_sigreturn, __kernel_rt_sigreturn, SYSENTER_RETURN; static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) @@ -367,7 +365,7 @@ static void setup_frame(int sig, struct k_sigaction *ka, if (err) goto give_sigsegv; - restorer = &__kernel_sigreturn; + restorer = current->mm->context.vdso + (long)&__kernel_sigreturn; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -439,7 +437,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->esp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); @@ -450,9 +448,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, goto give_sigsegv; /* Set up to return from userspace. */ - restorer = &__kernel_rt_sigreturn; + restorer = current->mm->context.vdso + (long)&__kernel_rt_sigreturn; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; + err |= __put_user(restorer, &frame->pretcode); /* diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 7c64adbf1..afd92719d 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt (void) if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); +#endif } else leave_mm(cpu); } @@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, spin_unlock(&tlbstate_lock); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - cpumask_t cpu_mask; - - preempt_disable(); - cpu_mask = mm->cpu_vm_mask; - cpu_clear(smp_processor_id(), cpu_mask); - - local_flush_tlb(); - if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, FLUSH_ALL); - preempt_enable(); -} - void flush_tlb_mm (struct mm_struct * mm) { cpumask_t cpu_mask; @@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) if (current->active_mm == mm) { if(current->mm) - __flush_tlb_one(va); +#ifndef CONFIG_X86_SWITCH_PAGETABLES + __flush_tlb_one(va) +#endif + ; else leave_mm(smp_processor_id()); } diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index 0c36130af..4aadf9045 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c @@ -57,7 +57,7 @@ static inline long do_mmap2( } down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + error = do_mmap_pgoff(current->mm, file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); if (file) @@ -217,7 +217,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -225,6 +225,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name) asmlinkage int sys_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -233,15 +234,16 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error |= __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c index c9194e33f..8047133cd 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -13,18 +13,24 @@ #include #include #include +#include #include #include #include #include +#include extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); +#ifdef CONFIG_X86_HIGH_ENTRY + struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else struct tss_struct *tss = init_tss + cpu; +#endif tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; @@ -41,11 +47,14 @@ void enable_sep_cpu(void *info) extern const char vsyscall_int80_start, vsyscall_int80_end; extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; +struct page *sysenter_page; + static int __init sysenter_setup(void) { unsigned long page = get_zeroed_page(GFP_ATOMIC); - __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY); + __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_KERNEL_RO); + sysenter_page = virt_to_page(page); if (!boot_cpu_has(X86_FEATURE_SEP)) { memcpy((void *) page, @@ -59,7 +68,51 @@ static int __init sysenter_setup(void) &vsyscall_sysenter_end - &vsyscall_sysenter_start); on_each_cpu(enable_sep_cpu, NULL, 1, 1); + return 0; } __initcall(sysenter_setup); + +extern void SYSENTER_RETURN_OFFSET; + +unsigned int vdso_enabled = 1; + +void map_vsyscall(void) +{ + struct thread_info *ti = current_thread_info(); + struct vm_area_struct *vma; + unsigned long addr; + + if (unlikely(!vdso_enabled)) { + current->mm->context.vdso = NULL; + return; + } + + /* + * Map the vDSO (it will be randomized): + */ + down_write(¤t->mm->mmap_sem); + addr = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, 0); + current->mm->context.vdso = (void *)addr; + ti->sysenter_return = (void *)addr + (long)&SYSENTER_RETURN_OFFSET; + if (addr != -1) { + vma = find_vma(current->mm, addr); + if (vma) { + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; + get_page(sysenter_page); + install_page(current->mm, vma, addr, + sysenter_page, vma->vm_page_prot); + + } + } + up_write(¤t->mm->mmap_sem); +} + +static int __init vdso_setup(char *str) +{ + vdso_enabled = simple_strtoul(str, NULL, 0); + return 1; +} +__setup("vdso=", vdso_setup); + diff --git a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c index 0526fc198..b2f722efb 100644 --- a/arch/i386/kernel/timers/timer.c +++ b/arch/i386/kernel/timers/timer.c @@ -19,10 +19,10 @@ static struct timer_opts* timers[] = { #ifdef CONFIG_HPET_TIMER &timer_hpet, #endif + &timer_tsc, #ifdef CONFIG_X86_PM_TIMER &timer_pmtmr, #endif - &timer_tsc, &timer_pit, NULL, }; diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index f031de058..ae775d4cf 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -55,12 +55,8 @@ #include "mach_traps.h" -asmlinkage int system_call(void); -asmlinkage void lcall7(void); -asmlinkage void lcall27(void); - -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; +struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +struct page *default_ldt_page; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; @@ -245,8 +241,10 @@ void show_registers(struct pt_regs *regs) for(i=0;i<20;i++) { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { + unsigned char c = 0; + if ((user_mode(regs) && get_user(c, &((unsigned char*)regs->eip)[i])) || + (!user_mode(regs) && __direct_get_user(c, &((unsigned char*)regs->eip)[i]))) { + bad: printk(" Bad EIP value."); break; @@ -270,20 +268,18 @@ static void handle_BUG(struct pt_regs *regs) eip = regs->eip; - if (eip < PAGE_OFFSET) - goto no_bug; - if (__get_user(ud2, (unsigned short *)eip)) + if (__direct_get_user(ud2, (unsigned short *)eip)) goto no_bug; if (ud2 != 0x0b0f) goto no_bug; - if (__get_user(line, (unsigned short *)(eip + 2))) + if (__direct_get_user(line, (unsigned short *)(eip + 2))) goto bug; - if (__get_user(file, (char **)(eip + 4)) || - (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + if (__direct_get_user(file, (char **)(eip + 4)) || + __direct_get_user(c, file)) file = ""; printk("------------[ cut here ]------------\n"); - printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line); + printk("kernel BUG at %s:%d!\n", file, line); no_bug: return; @@ -304,7 +300,7 @@ void die(const char * str, struct pt_regs * regs, long err) spin_lock_irq(&die_lock); bust_spinlocks(1); handle_BUG(regs); - printk(KERN_ALERT "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT printk("PREEMPT "); nl = 1; @@ -430,6 +426,10 @@ DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) +/* + * the original non-exec stack patch was written by + * Solar Designer . Thanks! + */ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { if (regs->eflags & X86_EFLAGS_IF) @@ -441,6 +441,46 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) if (!(regs->xcs & 3)) goto gp_in_kernel; + /* + * lazy-check for CS validity on exec-shield binaries: + */ + if (current->mm) { + int cpu = smp_processor_id(); + struct desc_struct *desc1, *desc2; + struct vm_area_struct *vma; + unsigned long limit = 0; + + spin_lock(¤t->mm->page_table_lock); + for (vma = current->mm->mmap; vma; vma = vma->vm_next) + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; + spin_unlock(¤t->mm->page_table_lock); + + current->mm->context.exec_limit = limit; + set_user_cs(¤t->mm->context.user_cs, limit); + + desc1 = ¤t->mm->context.user_cs; + desc2 = cpu_gdt_table[cpu] + GDT_ENTRY_DEFAULT_USER_CS; + + /* + * The CS was not in sync - reload it and retry the + * instruction. If the instruction still faults then + * we wont hit this branch next time around. + */ + if (desc1->a != desc2->a || desc1->b != desc2->b) { + if (print_fatal_signals >= 2) { + printk("#GPF fixup (%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id()); + printk(" exec_limit: %08lx, user_cs: %08lx/%08lx, CPU_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, desc1->a, desc1->b, desc2->a, desc2->b); + } + load_user_cs_desc(cpu, current->mm); + return; + } + } + if (print_fatal_signals) { + printk("#GPF(%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id()); + printk(" exec_limit: %08lx, user_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, current->mm->context.user_cs.a, current->mm->context.user_cs.b); + } + current->thread.error_code = error_code; current->thread.trap_no = 13; force_sig(SIGSEGV, current); @@ -592,10 +632,18 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); - /* Mask out spurious debug traps due to lazy DR7 setting */ + /* + * Mask out spurious debug traps due to lazy DR7 setting or + * due to 4G/4G kernel mode: + */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) goto clear_dr7; + if (!user_mode(regs)) { + // restore upon return-to-userspace: + set_thread_flag(TIF_DB7); + goto clear_dr7; + } } if (regs->eflags & VM_MASK) @@ -837,19 +885,53 @@ asmlinkage void math_emulate(long arg) #endif /* CONFIG_MATH_EMULATION */ -#ifdef CONFIG_X86_F00F_BUG -void __init trap_init_f00f_bug(void) +void __init trap_init_virtual_IDT(void) { - __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); - /* - * Update the IDT descriptor and reload the IDT so that - * it uses the read-only mapped virtual address. + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + idt_descr.address = __fix_to_virt(FIX_IDT); + __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); } + +void __init trap_init_virtual_GDT(void) +{ + int cpu = smp_processor_id(); + struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu; + struct Xgt_desc_struct tmp_desc = {0, 0}; + struct tss_struct * t; + + __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory"); + +#ifdef CONFIG_X86_HIGH_ENTRY + if (!cpu) { + __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL); + __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL); + __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL); + } + + gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu; +#else + gdt_desc->address = (unsigned long)cpu_gdt_table[cpu]; +#endif + __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc)); + +#ifdef CONFIG_X86_HIGH_ENTRY + t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else + t = init_tss + cpu; #endif + set_tss_desc(cpu, t); + cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + load_TR_desc(); +} #define _set_gate(gate_addr,type,dpl,addr,seg) \ do { \ @@ -876,17 +958,17 @@ void set_intr_gate(unsigned int n, void *addr) _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } -static void __init set_trap_gate(unsigned int n, void *addr) +void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); } -static void __init set_system_gate(unsigned int n, void *addr) +void __init set_system_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); } -static void __init set_call_gate(void *a, void *addr) +void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr,__KERNEL_CS); } @@ -908,6 +990,7 @@ void __init trap_init(void) #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif + init_entry_mappings(); set_trap_gate(0,÷_error); set_intr_gate(1,&debug); @@ -938,9 +1021,10 @@ void __init trap_init(void) * default LDT is a single-entry callgate to lcall7 for iBCS * and a callgate to lcall27 for Solaris/x86 binaries */ +#if 0 set_call_gate(&default_ldt[0],lcall7); set_call_gate(&default_ldt[4],lcall27); - +#endif /* * Should be a barrier for any external CPU state. */ diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index a5af5ec33..e0e3bdfe2 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -125,7 +125,7 @@ struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; - load_esp0(tss, ¤t->thread); + load_virtual_esp0(tss, current); current->thread.saved_esp0 = 0; put_cpu(); @@ -305,7 +305,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; - load_esp0(tss, &tsk->thread); + load_virtual_esp0(tss, tsk); put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 829f1c91d..c83850859 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -5,13 +5,17 @@ #include #include +#include +#include +#include + OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { @@ -21,6 +25,19 @@ SECTIONS *(.gnu.warning) } = 0x9090 +#ifdef CONFIG_X86_4G + . = ALIGN(PAGE_SIZE_asm); + __entry_tramp_start = .; + . = FIX_ENTRY_TRAMPOLINE_0_addr; + __start___entry_text = .; + .entry.text : AT (__entry_tramp_start) { *(.entry.text) } + __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text); + . = __entry_tramp_end; + . = ALIGN(PAGE_SIZE_asm); +#else + .entry.text : { *(.entry.text) } +#endif + _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ @@ -36,15 +53,12 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_end = .; - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -54,7 +68,7 @@ SECTIONS .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE_asm); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -93,7 +107,7 @@ SECTIONS from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -101,10 +115,22 @@ SECTIONS __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __init_end = .; /* freed after init ends here */ - + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_tss : { *(.data.tss) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_default_ldt : { *(.data.default_ldt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_idt : { *(.data.idt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_gdt : { *(.data.gdt) } + __bss_start = .; /* BSS */ .bss : { *(.bss.page_aligned) @@ -132,4 +158,6 @@ SECTIONS .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } + + } diff --git a/arch/i386/kernel/vsyscall-sysenter.S b/arch/i386/kernel/vsyscall-sysenter.S index cb54c01bd..cb421be0f 100644 --- a/arch/i386/kernel/vsyscall-sysenter.S +++ b/arch/i386/kernel/vsyscall-sysenter.S @@ -12,6 +12,11 @@ .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: + cmpl $192, %eax + jne 1f + int $0x80 + ret +1: push %ecx .Lpush_ecx: push %edx @@ -24,11 +29,11 @@ __kernel_vsyscall: /* 7: align return point with nop's to make disassembly easier */ .space 7,0x90 - /* 14: System call restart point is here! (SYSENTER_RETURN - 2) */ + /* 14: System call restart point is here! (SYSENTER_RETURN_OFFSET-2) */ jmp .Lenter_kernel /* 16: System call normal return point is here! */ - .globl SYSENTER_RETURN /* Symbol used by entry.S. */ -SYSENTER_RETURN: + .globl SYSENTER_RETURN_OFFSET /* Symbol used by sysenter.c */ +SYSENTER_RETURN_OFFSET: pop %ebp .Lpop_ebp: pop %edx diff --git a/arch/i386/kernel/vsyscall.lds b/arch/i386/kernel/vsyscall.lds index 7ff7f8b9e..484e45148 100644 --- a/arch/i386/kernel/vsyscall.lds +++ b/arch/i386/kernel/vsyscall.lds @@ -1,15 +1,12 @@ /* * Linker script for vsyscall DSO. The vsyscall page is an ELF shared - * object prelinked to its virtual address, and with only one read-only - * segment (that fits in one page). This script controls its layout. + * object with only one read-only segment (that fits in one page). + * This script controls its layout. */ -/* This must match . */ -VSYSCALL_BASE = 0xffffe000; - SECTIONS { - . = VSYSCALL_BASE + SIZEOF_HEADERS; + . = SIZEOF_HEADERS; .hash : { *(.hash) } :text .dynsym : { *(.dynsym) } @@ -22,7 +19,7 @@ SECTIONS For the layouts to match, we need to skip more than enough space for the dynamic symbol table et al. If this amount is insufficient, ld -shared will barf. Just increase it here. */ - . = VSYSCALL_BASE + 0x400; + . = 0x400; .text : { *(.text) } :text =0x90909090 diff --git a/arch/i386/lib/bitops.c b/arch/i386/lib/bitops.c new file mode 100644 index 000000000..97db3853d --- /dev/null +++ b/arch/i386/lib/bitops.c @@ -0,0 +1,70 @@ +#include +#include + +/** + * find_next_bit - find the first set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +int find_next_bit(const unsigned long *addr, int size, int offset) +{ + const unsigned long *p = addr + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for nonzero in the first 32 bits: + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (*p >> bit)); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No set bit yet, search remaining full words for a bit + */ + res = find_first_bit (p, size - 32 * (p - addr)); + return (offset + set + res); +} +EXPORT_SYMBOL(find_next_bit); + +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +int find_next_zero_bit(const unsigned long *addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for zero in the first 32 bits. + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (~(*p >> bit))); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No zero yet, search remaining full bytes for a zero + */ + res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); + return (offset + set + res); +} +EXPORT_SYMBOL(find_next_zero_bit); diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S index 94c7867dd..638b3bfbe 100644 --- a/arch/i386/lib/checksum.S +++ b/arch/i386/lib/checksum.S @@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, .previous .align 4 -.globl csum_partial_copy_generic +.globl direct_csum_partial_copy_generic #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: subl $4,%esp pushl %edi pushl %esi @@ -422,7 +422,7 @@ DST( movb %cl, (%edi) ) #define ARGBASE 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: pushl %ebx pushl %edi pushl %esi diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser.S index 62d7f178a..1985ca1e0 100644 --- a/arch/i386/lib/getuser.S +++ b/arch/i386/lib/getuser.S @@ -9,6 +9,7 @@ * return value. */ #include +#include /* diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 416a4d10f..62e383663 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -77,7 +76,7 @@ do { \ * and returns @count. */ long -__strncpy_from_user(char *dst, const char __user *src, long count) +__direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -103,7 +102,7 @@ __strncpy_from_user(char *dst, const char __user *src, long count) * and returns @count. */ long -strncpy_from_user(char *dst, const char __user *src, long count) +direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -148,7 +147,7 @@ do { \ * On success, this will be zero. */ unsigned long -clear_user(void __user *to, unsigned long n) +direct_clear_user(void __user *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) @@ -168,7 +167,7 @@ clear_user(void __user *to, unsigned long n) * On success, this will be zero. */ unsigned long -__clear_user(void __user *to, unsigned long n) +__direct_clear_user(void __user *to, unsigned long n) { __do_clear_user(to, n); return n; @@ -185,7 +184,7 @@ __clear_user(void __user *to, unsigned long n) * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -long strnlen_user(const char __user *s, long n) +long direct_strnlen_user(const char __user *s, long n) { unsigned long mask = -__addr_ok(s); unsigned long res, tmp; @@ -568,8 +567,7 @@ survive: return n; } -unsigned long -__copy_from_user_ll(void *to, const void __user *from, unsigned long n) +unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n) { if (movsl_is_ok(to, from, n)) __copy_user_zeroing(to, (const void *) from, n); @@ -578,53 +576,3 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned long n) return n; } -/** - * copy_to_user: - Copy a block of data into user space. - * @to: Destination address, in user space. - * @from: Source address, in kernel space. - * @n: Number of bytes to copy. - * - * Context: User context only. This function may sleep. - * - * Copy data from kernel space to user space. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - */ -unsigned long -copy_to_user(void __user *to, const void *from, unsigned long n) -{ - might_sleep(); - if (access_ok(VERIFY_WRITE, to, n)) - n = __copy_to_user(to, from, n); - return n; -} -EXPORT_SYMBOL(copy_to_user); - -/** - * copy_from_user: - Copy a block of data from user space. - * @to: Destination address, in kernel space. - * @from: Source address, in user space. - * @n: Number of bytes to copy. - * - * Context: User context only. This function may sleep. - * - * Copy data from user space to kernel space. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - * - * If some data could not be copied, this function will pad the copied - * data to the requested size using zero bytes. - */ -unsigned long -copy_from_user(void *to, const void __user *from, unsigned long n) -{ - might_sleep(); - if (access_ok(VERIFY_READ, from, n)) - n = __copy_from_user(to, from, n); - else - memset(to, 0, n); - return n; -} -EXPORT_SYMBOL(copy_from_user); diff --git a/arch/i386/mach-es7000/es7000.c b/arch/i386/mach-es7000/es7000.c deleted file mode 100644 index defe41e6c..000000000 --- a/arch/i386/mach-es7000/es7000.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Written by: Garry Forsgren, Unisys Corporation - * Natalie Protasevich, Unisys Corporation - * This file contains the code to configure and interface - * with Unisys ES7000 series hardware system manager. - * - * Copyright (c) 2003 Unisys Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Unisys Corporation, Township Line & Union Meeting - * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or: - * - * http://www.unisys.com - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "es7000.h" - -/* - * ES7000 Globals - */ - -volatile unsigned long *psai = NULL; -struct mip_reg *mip_reg; -struct mip_reg *host_reg; -int mip_port; -unsigned long mip_addr, host_addr; - -/* - * Parse the OEM Table - */ - -void __init -parse_unisys_oem (char *oemptr, int oem_entries) -{ - int i; - int success = 0; - unsigned char type, size; - unsigned long val; - char *tp = NULL; - struct psai *psaip = NULL; - struct mip_reg_info *mi; - struct mip_reg *host, *mip; - - tp = oemptr; - - tp += 8; - - for (i=0; i <= oem_entries; i++) { - type = *tp++; - size = *tp++; - tp -= 2; - switch (type) { - case MIP_REG: - mi = (struct mip_reg_info *)tp; - val = MIP_RD_LO(mi->host_reg); - host_addr = val; - host = (struct mip_reg *)val; - host_reg = __va(host); - val = MIP_RD_LO(mi->mip_reg); - mip_addr = val; - mip = (struct mip_reg *)val; - mip_reg = __va(mip); - Dprintk("es7000_mipcfg: host_reg = 0x%lx \n", - (unsigned long)host_reg); - Dprintk("es7000_mipcfg: mip_reg = 0x%lx \n", - (unsigned long)mip_reg); - success++; - break; - case MIP_PSAI_REG: - psaip = (struct psai *)tp; - if (tp != NULL) { - if (psaip->addr) - psai = __va(psaip->addr); - else - psai = NULL; - success++; - } - break; - default: - break; - } - if (i == 6) break; - tp += size; - } - - if (success < 2) { - printk("\nNo ES7000 found.\n"); - es7000_plat = 0; - } else { - printk("\nEnabling ES7000 specific features...\n"); - es7000_plat = 1; - } - return; -} - -int __init -find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length) -{ - struct acpi_table_rsdp *rsdp = NULL; - unsigned long rsdp_phys = 0; - struct acpi_table_header *header = NULL; - int i; - struct acpi_table_sdt sdt; - - rsdp_phys = acpi_find_rsdp(); - rsdp = __va(rsdp_phys); - if (rsdp->rsdt_address) { - struct acpi_table_rsdt *mapped_rsdt = NULL; - sdt.pa = rsdp->rsdt_address; - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); - if (!header) - return -ENODEV; - - sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; - mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt.pa, header->length); - if (!mapped_rsdt) - return -ENODEV; - - header = &mapped_rsdt->header; - - for (i = 0; i < sdt.count; i++) - sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; - }; - for (i = 0; i < sdt.count; i++) { - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.entry[i].pa, - sizeof(struct acpi_table_header)); - if (!header) - continue; - if (!strncmp((char *) &header->signature, "OEM1", 4)) { - if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) { - void *addr; - struct oem_table *t; - acpi_table_print(header, sdt.entry[i].pa); - t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length); - addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize); - *length = header->length; - *oem_addr = (unsigned long) addr; - return 0; - } - } - } - printk("ES7000: did not find Unisys ACPI OEM table!\n"); - return -1; -} - -static void -es7000_spin(int n) -{ - int i = 0; - - while (i++ < n) - rep_nop(); -} - -static int __init -es7000_mip_write(struct mip_reg *mip_reg) -{ - int status = 0; - int spin; - - spin = MIP_SPIN; - while (((unsigned long long)host_reg->off_38 & - (unsigned long long)MIP_VALID) != 0) { - if (--spin <= 0) { - printk("es7000_mip_write: Timeout waiting for Host Valid Flag"); - return -1; - } - es7000_spin(MIP_SPIN); - } - - memcpy(host_reg, mip_reg, sizeof(struct mip_reg)); - outb(1, mip_port); - - spin = MIP_SPIN; - - while (((unsigned long long)mip_reg->off_38 & - (unsigned long long)MIP_VALID) == 0) { - if (--spin <= 0) { - printk("es7000_mip_write: Timeout waiting for MIP Valid Flag"); - return -1; - } - es7000_spin(MIP_SPIN); - } - - status = ((unsigned long long)mip_reg->off_0 & - (unsigned long long)0xffff0000000000) >> 48; - mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 & - (unsigned long long)~MIP_VALID); - return status; -} - -int -es7000_start_cpu(int cpu, unsigned long eip) -{ - unsigned long vect = 0, psaival = 0; - - if (psai == NULL) - return -1; - - vect = ((unsigned long)__pa(eip)/0x1000) << 16; - psaival = (0x1000000 | vect | cpu); - - while (*psai & 0x1000000) - ; - - *psai = psaival; - - return 0; - -} - -int -es7000_stop_cpu(int cpu) -{ - int startup; - - if (psai == NULL) - return -1; - - startup= (0x1000000 | cpu); - - while ((*psai & 0xff00ffff) != startup) - ; - - startup = (*psai & 0xff0000) >> 16; - *psai &= 0xffffff; - - return 0; - -} - -void __init -es7000_sw_apic() -{ - if (es7000_plat) { - int mip_status; - struct mip_reg es7000_mip_reg; - - printk("ES7000: Enabling APIC mode.\n"); - memset(&es7000_mip_reg, 0, sizeof(struct mip_reg)); - es7000_mip_reg.off_0 = MIP_SW_APIC; - es7000_mip_reg.off_38 = (MIP_VALID); - while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0) - printk("es7000_sw_apic: command failed, status = %x\n", - mip_status); - return; - } -} diff --git a/arch/i386/mach-es7000/setup.c b/arch/i386/mach-es7000/setup.c deleted file mode 100644 index 4caed0e43..000000000 --- a/arch/i386/mach-es7000/setup.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Machine specific setup for es7000 - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * pre_intr_init_hook - initialisation prior to setting up interrupt vectors - * - * Description: - * Perform any necessary interrupt initialisation prior to setting up - * the "ordinary" interrupt call gates. For legacy reasons, the ISA - * interrupts should be initialised here if the machine emulates a PC - * in any way. - **/void __init pre_intr_init_hook(void) -{ - init_ISA_irqs(); -} - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; - -/** - * intr_init_hook - post gate setup interrupt initialisation - * - * Description: - * Fill in any interrupts that may have been left out by the general - * init_IRQ() routine. interrupts having to do with the machine rather - * than the devices on the I/O bus (like APIC interrupts in intel MP - * systems) are started here. - **/ -void __init intr_init_hook(void) -{ -#ifdef CONFIG_X86_LOCAL_APIC - apic_intr_init(); -#endif - - if (!acpi_ioapic) - setup_irq(2, &irq2); -} - -/** - * pre_setup_arch_hook - hook called prior to any setup_arch() execution - * - * Description: - * generally used to activate any machine specific identification - * routines that may be needed before setup_arch() runs. On VISWS - * this is used to get the board revision and type. - **/ -void __init pre_setup_arch_hook(void) -{ -} - -/** - * trap_init_hook - initialise system specific traps - * - * Description: - * Called as the final act of trap_init(). Used in VISWS to initialise - * the various board specific APIC traps. - **/ -void __init trap_init_hook(void) -{ -} - -static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; - -/** - * time_init_hook - do any specific initialisations for the system timer. - * - * Description: - * Must plug the system timer interrupt source at HZ into the IRQ listed - * in irq_vectors.h:TIMER_IRQ - **/ -void __init time_init_hook(void) -{ - setup_irq(0, &irq0); -} - -#ifdef CONFIG_MCA -/** - * mca_nmi_hook - hook into MCA specific NMI chain - * - * Description: - * The MCA (Microchannel Arcitecture) has an NMI chain for NMI sources - * along the MCA bus. Use this to hook into that chain if you will need - * it. - **/ -void __init mca_nmi_hook(void) -{ - /* If I recall correctly, there's a whole bunch of other things that - * we can do to check for NMI problems, but that's all I know about - * at the moment. - */ - - printk("NMI generated from unknown source!\n"); -} - -#endif diff --git a/arch/i386/mach-es7000/topology.c b/arch/i386/mach-es7000/topology.c deleted file mode 100644 index e96d8910a..000000000 --- a/arch/i386/mach-es7000/topology.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * arch/i386/mach-generic/topology.c - Populate driverfs with topology information - * - * Written by: Matthew Dobson, IBM Corporation - * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ -#include -#include -#include - -struct i386_cpu cpu_devices[NR_CPUS]; - -#ifdef CONFIG_NUMA -#include -#include - -struct i386_node node_devices[MAX_NUMNODES]; - -static int __init topology_init(void) -{ - int i; - - for (i = 0; i < num_online_nodes(); i++) - arch_register_node(i); - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) arch_register_cpu(i); - return 0; -} - -#else /* !CONFIG_NUMA */ - -static int __init topology_init(void) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) arch_register_cpu(i); - return 0; -} - -#endif /* CONFIG_NUMA */ - -subsys_initcall(topology_init); diff --git a/arch/i386/math-emu/fpu_system.h b/arch/i386/math-emu/fpu_system.h index fd5fc6d78..78693a5c3 100644 --- a/arch/i386/math-emu/fpu_system.h +++ b/arch/i386/math-emu/fpu_system.h @@ -15,6 +15,7 @@ #include #include #include +#include /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ @@ -22,7 +23,7 @@ /* s is always from a cpu register, and the cpu does bounds checking * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 0c77e0b07..97d4af301 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -27,6 +27,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -104,8 +105,17 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, if (seg & (1<<2)) { /* Must lock the LDT while reading it. */ down(¤t->mm->context.sem); +#if 1 + /* horrible hack for 4/4 disabled kernels. + I'm not quite sure what the TLB flush is good for, + it's mindlessly copied from the read_ldt code */ + __flush_tlb_global(); + desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]); + desc = (void *)desc + ((seg & ~7) % PAGE_SIZE); +#else desc = current->mm->context.ldt; desc = (void *)desc + (seg & ~7); +#endif } else { /* Must disable preemption while reading the GDT. */ desc = (u32 *)&cpu_gdt_table[get_cpu()]; @@ -118,6 +128,9 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, (desc[1] & 0xff000000); if (seg & (1<<2)) { +#if 1 + kunmap((void *)((unsigned long)desc & PAGE_MASK)); +#endif up(¤t->mm->context.sem); } else put_cpu(); @@ -243,6 +256,17 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ +#ifdef CONFIG_X86_4G + /* + * On 4/4 all kernels faults are either bugs, vmalloc or prefetch + */ + /* If it's vm86 fall through */ + if (unlikely(!(regs->eflags & VM_MASK) && ((regs->xcs & 3) == 0))) { + if (error_code & 3) + goto bad_area_nosemaphore; + goto vmalloc_fault; + } +#else if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 5)) goto vmalloc_fault; @@ -252,6 +276,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) */ goto bad_area_nosemaphore; } +#endif mm = tsk->mm; @@ -406,12 +431,27 @@ no_context: bust_spinlocks(1); +#ifdef CONFIG_X86_PAE + { + pgd_t *pgd; + pmd_t *pmd; + + + + pgd = init_mm.pgd + pgd_index(address); + if (pgd_present(*pgd)) { + pmd = pmd_offset(pgd, address); + if (pmd_val(*pmd) & _PAGE_NX) + printk(KERN_CRIT "kernel tried to access NX-protected page - exploit attempt? (uid: %d)\n", current->uid); + } + } +#endif if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); - printk(KERN_ALERT " printing eip:\n"); + printk(" printing eip:\n"); printk("%08lx\n", regs->eip); asm("movl %%cr3,%0":"=r" (page)); page = ((unsigned long *) __va(page))[address >> 22]; diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c index 581753285..83972da8e 100644 --- a/arch/i386/mm/highmem.c +++ b/arch/i386/mm/highmem.c @@ -41,12 +41,47 @@ void *kmap_atomic(struct page *page, enum km_type type) if (!pte_none(*(kmap_pte-idx))) BUG(); #endif - set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + /* + * If the page is not a normal RAM page, then map it + * uncached to be on the safe side - it could be device + * memory that must not be prefetched: + */ + if (PageReserved(page)) + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot_nocache)); + else + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); __flush_tlb_one(vaddr); return (void*) vaddr; } +/* + * page frame number based kmaps - useful for PCI mappings. + * NOTE: we map the page with the dont-cache flag. + */ +void *kmap_atomic_nocache_pfn(unsigned long pfn, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + inc_preempt_count(); + if (pfn < highstart_pfn) + return pfn_to_kaddr(pfn); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#ifdef CONFIG_DEBUG_HIGHMEM + if (!pte_none(*(kmap_pte-idx))) + BUG(); +#endif + set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot_nocache)); + __flush_tlb_one(vaddr); + + return (void*) vaddr; +} + + void kunmap_atomic(void *kvaddr, enum km_type type) { #ifdef CONFIG_DEBUG_HIGHMEM diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 0397fe963..a8dbbc57b 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -43,7 +43,8 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struc { pte_t entry; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + // mm->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(mm, HPAGE_SIZE / PAGE_SIZE); if (write_access) { entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); @@ -83,7 +84,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, ptepage = pte_page(entry); get_page(ptepage); set_pte(dst_pte, entry); - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + // dst->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(dst, HPAGE_SIZE / PAGE_SIZE); addr += HPAGE_SIZE; } return 0; @@ -222,7 +224,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, page = pte_page(pte); put_page(page); } - mm->rss -= (end - start) >> PAGE_SHIFT; + // mm->rss -= (end - start) >> PAGE_SHIFT; + vx_rsspages_sub(mm, (end - start) >> PAGE_SHIFT); flush_tlb_range(vma, start, end); } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 19ba96e64..77179eb95 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -40,125 +40,13 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static int do_test_wp_bit(void); -/* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - if (pmd_table != pmd_offset(pgd, 0)) - BUG(); -#else - pmd_table = pmd_offset(pgd, 0); -#endif - - return pmd_table; -} - -/* - * Create a page table and place a pointer to it in a middle page - * directory entry. - */ -static pte_t * __init one_page_table_init(pmd_t *pmd) -{ - if (pmd_none(*pmd)) { - pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - if (page_table != pte_offset_kernel(pmd, 0)) - BUG(); - - return page_table; - } - - return pte_offset_kernel(pmd, 0); -} - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - int pgd_idx, pmd_idx; - unsigned long vaddr; - - vaddr = start; - pgd_idx = pgd_index(vaddr); - pmd_idx = pmd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); - - pmd = pmd_offset(pgd, vaddr); - for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - if (pmd_none(*pmd)) - one_page_table_init(pmd); - - vaddr += PMD_SIZE; - } - pmd_idx = 0; - } -} - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long pfn; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; - - pgd_idx = pgd_index(PAGE_OFFSET); - pgd = pgd_base + pgd_idx; - pfn = 0; - - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; - for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - /* Map with big pages if possible, otherwise create normal page tables. */ - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte = one_page_table_init(pmd); - - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - } - } - } -} - static inline int page_kills_ppro(unsigned long pagenr) { if (pagenr >= 0x70000 && pagenr <= 0x7003F) @@ -168,7 +56,7 @@ static inline int page_kills_ppro(unsigned long pagenr) extern int is_available_memory(efi_memory_desc_t *); -static inline int page_is_ram(unsigned long pagenr) +int page_is_ram(unsigned long pagenr) { int i; unsigned long addr, end; @@ -206,11 +94,8 @@ static inline int page_is_ram(unsigned long pagenr) return 0; } -#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; -pgprot_t kmap_prot; -EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #define kmap_get_fixmap_pte(vaddr) \ @@ -218,29 +103,7 @@ EXPORT_SYMBOL(kmap_pte); void __init kmap_init(void) { - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; -} - -void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; + kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); } void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) @@ -255,6 +118,10 @@ void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) SetPageReserved(page); } +EXPORT_SYMBOL_GPL(page_is_ram); + +#ifdef CONFIG_HIGHMEM + #ifndef CONFIG_DISCONTIGMEM void __init set_highmem_pages_init(int bad_ppro) { @@ -266,14 +133,12 @@ void __init set_highmem_pages_init(int bad_ppro) #else extern void set_highmem_pages_init(int); #endif /* !CONFIG_DISCONTIGMEM */ - #else -#define kmap_init() do { } while (0) -#define permanent_kmaps_init(pgd_base) do { } while (0) -#define set_highmem_pages_init(bad_ppro) do { } while (0) -#endif /* CONFIG_HIGHMEM */ +# define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif -unsigned long __PAGE_KERNEL = _PAGE_KERNEL; +unsigned long long __PAGE_KERNEL = _PAGE_KERNEL; +unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC; #ifndef CONFIG_DISCONTIGMEM #define remap_numa_kva() do {} while (0) @@ -281,30 +146,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERNEL; extern void __init remap_numa_kva(void); #endif -static void __init pagetable_init (void) +static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_base + pgd_index(address); + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); + } +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) +{ + unsigned long vaddr; + + for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE) + prepare_pagetables(pgd_base, vaddr); +} + +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { unsigned long vaddr; - pgd_t *pgd_base = swapper_pg_dir; + pgd_t *pgd; + int i, j, k; + pmd_t *pmd; + pte_t *pte, *pte_base; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start; + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) + __pe += _PAGE_GLOBAL; + __PAGE_KERNEL |= _PAGE_GLOBAL; +#endif + } + set_pmd(pmd, __pmd(__pe)); + continue; + } + if (!pmd_present(*pmd)) + pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + else + pte_base = pte_offset_kernel(pmd, 0); + pte = pte_base; + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL); + } + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); + } + } +} +static void __init pagetable_init (void) +{ + unsigned long vaddr, end; + pgd_t *pgd_base; #ifdef CONFIG_X86_PAE int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif - /* Enable PSE if available */ - if (cpu_has_pse) { - set_in_cr4(X86_CR4_PSE); - } + /* + * This can be zero as well - no problem, in that case we exit + * the loops anyway due to the PTRS_PER_* conditions. + */ + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - /* Enable PGE if available */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __PAGE_KERNEL |= _PAGE_GLOBAL; + pgd_base = swapper_pg_dir; +#ifdef CONFIG_X86_PAE + /* + * It causes too many problems if there's no proper pmd set up + * for all 4 entries of the PGD - so we allocate all of them. + * PAE systems will not miss this extra 4-8K anyway ... + */ + for (i = 0; i < PTRS_PER_PGD; i++) { + pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1)); } +#endif + /* + * Set up lowmem-sized identity mappings at PAGE_OFFSET: + */ + setup_identity_mappings(pgd_base, PAGE_OFFSET, end); - kernel_physical_mapping_init(pgd_base); + /* + * Add flat-mode identity-mappings - SMP needs it when + * starting up on an AP from real-mode. (In the non-PAE + * case we already have these mappings through head.S.) + * All user-space mappings are explicitly cleared after + * SMP startup. + */ +#if defined(CONFIG_SMP) && defined(CONFIG_X86_PAE) + setup_identity_mappings(pgd_base, 0, 16*1024*1024); +#endif remap_numa_kva(); /* @@ -312,59 +272,64 @@ static void __init pagetable_init (void) * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, pgd_base); + fixrange_init(vaddr, 0, pgd_base); - permanent_kmaps_init(pgd_base); +#ifdef CONFIG_HIGHMEM + { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + } #endif } -#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND) /* - * Swap suspend & friends need this for resume because things like the intel-agp - * driver might have split up a kernel 4MB mapping. + * Clear kernel pagetables in a PMD_SIZE-aligned range. */ -char __nosavedata swsusp_pg_dir[PAGE_SIZE] - __attribute__ ((aligned (PAGE_SIZE))); - -static inline void save_pg_dir(void) -{ - memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE); -} -#else -static inline void save_pg_dir(void) +static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; + int i, j; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + pmd_clear(pmd); + } + } + flush_tlb_all(); } -#endif -void zap_low_mappings (void) +void zap_low_mappings(void) { - int i; - - save_pg_dir(); - + printk("zapping low mappings.\n"); /* * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - flush_tlb_all(); + clear_mappings(swapper_pg_dir, 0, 16*1024*1024); } #ifndef CONFIG_DISCONTIGMEM @@ -392,6 +357,53 @@ void __init zone_sizes_init(void) extern void zone_sizes_init(void); #endif /* !CONFIG_DISCONTIGMEM */ +static int disable_nx __initdata = 0; +u64 __supported_pte_mask = ~_PAGE_NX; + +/* + * noexec = on|off + * + * Control non executable mappings. + * + * on Enable + * off Disable (disables exec-shield too) + */ +static int __init noexec_setup(char *str) +{ + if (!strncmp(str, "on",2) && cpu_has_nx) { + __supported_pte_mask |= _PAGE_NX; + disable_nx = 0; + } else if (!strncmp(str,"off",3)) { + disable_nx = 1; + __supported_pte_mask &= ~_PAGE_NX; + exec_shield = 0; + } + return 1; +} + +__setup("noexec=", noexec_setup); + +int use_nx = 0; +#ifdef CONFIG_X86_PAE + +static void __init set_nx(void) +{ + unsigned int v[4], l, h; + + if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { + cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); + if ((v[3] & (1 << 20)) && !disable_nx) { + rdmsr(MSR_EFER, l, h); + l |= EFER_NX; + wrmsr(MSR_EFER, l, h); + use_nx = 1; + __supported_pte_mask |= _PAGE_NX; + } + } +} + +#endif + /* * paging_init() sets up the page tables - note that the first 8MB are * already mapped by head.S. @@ -401,6 +413,17 @@ extern void zone_sizes_init(void); */ void __init paging_init(void) { +#ifdef CONFIG_X86_PAE + set_nx(); + if (use_nx) + printk("NX (Execute Disable) protection: active\n"); + else { + printk("NX (Execute Disable) protection: not present!\n"); + if (exec_shield) + printk("Using x86 segment limits to approximate NX protection\n"); + } +#endif + pagetable_init(); load_cr3(swapper_pg_dir); @@ -414,11 +437,18 @@ void __init paging_init(void) set_in_cr4(X86_CR4_PAE); #endif __flush_tlb_all(); - + /* + * Subtle. SMP is doing it's boot stuff late (because it has to + * fork idle threads) - but it also needs low mappings for the + * protected-mode entry to work. We zap these entries only after + * the WP-bit has been tested. + */ +#ifndef CONFIG_SMP + zap_low_mappings(); +#endif kmap_init(); zone_sizes_init(); } - /* * Test if the WP bit works in supervisor mode. It isn't supported on 386's * and also on some strange 486's (NexGen etc.). All 586+'s are OK. This @@ -533,22 +563,18 @@ void __init mem_init(void) if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); - /* - * Subtle. SMP is doing it's boot stuff late (because it has to - * fork idle threads) - but it also needs low mappings for the - * protected-mode entry to work. We zap these entries only after - * the WP-bit has been tested. - */ -#ifndef CONFIG_SMP - zap_low_mappings(); -#endif + entry_trampoline_setup(); + default_ldt_page = virt_to_page(default_ldt); + load_LDT(&init_mm.context); } -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; void __init pgtable_cache_init(void) { + void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*dtor)(void *, kmem_cache_t *, unsigned long); + if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -558,13 +584,36 @@ void __init pgtable_cache_init(void) NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); + + if (TASK_SIZE > PAGE_OFFSET) { + kpmd_cache = kmem_cache_create("kpmd", + PTRS_PER_PMD*sizeof(pmd_t), + PTRS_PER_PMD*sizeof(pmd_t), + 0, + kpmd_ctor, + NULL); + if (!kpmd_cache) + panic("pgtable_cache_init(): " + "cannot create kpmd cache"); + } } + + if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET) + ctor = pgd_ctor; + else + ctor = NULL; + + if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET) + dtor = pgd_dtor; + else + dtor = NULL; + pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), PTRS_PER_PGD*sizeof(pgd_t), 0, - pgd_ctor, - PTRS_PER_PMD == 1 ? pgd_dtor : NULL); + ctor, + dtor); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } @@ -573,7 +622,7 @@ void __init pgtable_cache_init(void) * This function cannot be __init, since exceptions don't work in that * section. Put this after the callers, so that it cannot be inlined. */ -static int do_test_wp_bit(void) +static int noinline do_test_wp_bit(void) { char tmp_reg; int flag; diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index af7c60285..cdef757b2 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c @@ -67,22 +67,21 @@ static void flush_kernel_map(void *dummy) static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) { - struct page *page; - unsigned long flags; - set_pte_atomic(kpte, pte); /* change init_mm */ - if (PTRS_PER_PMD > 1) - return; - - spin_lock_irqsave(&pgd_lock, flags); - for (page = pgd_list; page; page = (struct page *)page->index) { - pgd_t *pgd; - pmd_t *pmd; - pgd = (pgd_t *)page_address(page) + pgd_index(address); - pmd = pmd_offset(pgd, address); - set_pte_atomic((pte_t *)pmd, pte); +#ifndef CONFIG_X86_PAE + { + struct list_head *l; + if (TASK_SIZE > PAGE_OFFSET) + return; + spin_lock(&mmlist_lock); + list_for_each(l, &init_mm.mmlist) { + struct mm_struct *mm = list_entry(l, struct mm_struct, mmlist); + pmd_t *pmd = pmd_offset(pgd_offset(mm, address), address); + set_pte_atomic((pte_t *)pmd, pte); + } + spin_unlock(&mmlist_lock); } - spin_unlock_irqrestore(&pgd_lock, flags); +#endif } /* diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 49561339c..24adf6630 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -21,6 +21,7 @@ #include #include #include +#include void show_mem(void) { @@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags) memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } +void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags) +{ + pmd_t *kpmd, *pmd; + kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1], + (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE); + pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS); + + memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t)); + memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t)); +} + /* - * List of all pgd's needed for non-PAE so it can invalidate entries - * in both cached and uncached pgd's; not needed for PAE since the - * kernel pmd is shared. If PAE were not to share the pmd a similar - * tactic would be needed. This is essentially codepath-based locking + * List of all pgd's needed so it can invalidate entries in both cached + * and uncached pgd's. This is essentially codepath-based locking * against pageattr.c; it is the unique case in which a valid change * of kernel pagetables can't be lazily synchronized by vmalloc faults. * vmalloc faults work because attached pagetables are never freed. @@ -169,6 +179,12 @@ void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags) * checks at dup_mmap(), exec(), and other mmlist addition points * could be used. The locking scheme was chosen on the basis of * manfred's recommendations and having no core impact whatsoever. + * + * Lexicon for #ifdefless conditions to config options: + * (a) PTRS_PER_PMD == 1 means non-PAE. + * (b) PTRS_PER_PMD > 1 means PAE. + * (c) TASK_SIZE > PAGE_OFFSET means 4:4. + * (d) TASK_SIZE <= PAGE_OFFSET means non-4:4. * -- wli */ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED; @@ -194,26 +210,38 @@ static inline void pgd_list_del(pgd_t *pgd) next->private = (unsigned long)pprev; } -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused) { + pgd_t *pgd = __pgd; unsigned long flags; - if (PTRS_PER_PMD == 1) - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + if (TASK_SIZE <= PAGE_OFFSET) + spin_lock_irqsave(&pgd_lock, flags); + else + memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS], + &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS], + NR_SHARED_PMDS*sizeof(pgd_t)); + } - memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + if (TASK_SIZE <= PAGE_OFFSET) + memcpy(&pgd[USER_PTRS_PER_PGD], + &swapper_pg_dir[USER_PTRS_PER_PGD], + (PTRS_PER_PGD - USER_PTRS_PER_PGD)*sizeof(pgd_t)); if (PTRS_PER_PMD > 1) return; - pgd_list_add(pgd); - spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + if (TASK_SIZE > PAGE_OFFSET) + memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t)); + else { + pgd_list_add(pgd); + spin_unlock_irqrestore(&pgd_lock, flags); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + } } -/* never called when PTRS_PER_PMD > 1 */ +/* Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ @@ -231,15 +259,31 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (PTRS_PER_PMD == 1 || !pgd) return pgd; + /* + * In the 4G userspace case alias the top 16 MB virtual + * memory range into the user mappings as well (these + * include the trampoline and CPU data structures). + */ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { - pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + pmd_t *pmd; + + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + pmd = kmem_cache_alloc(kpmd_cache, GFP_KERNEL); + else + pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + if (!pmd) goto out_oom; set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd)))); } - return pgd; + return pgd; out_oom: + /* + * we don't have to handle the kpmd_cache here, since it's the + * last allocation, and has either nothing to free or when it + * succeeds the whole operation succeeds. + */ for (i--; i >= 0; i--) kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); kmem_cache_free(pgd_cache, pgd); @@ -250,10 +294,26 @@ void pgd_free(pgd_t *pgd) { int i; - /* in the PAE case user pgd entries are overwritten before usage */ - if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); /* in the non-PAE case, clear_page_tables() clears user pgd entries */ + if (PTRS_PER_PMD == 1) + goto out_free; + + /* in the PAE case user pgd entries are overwritten before usage */ + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + pmd_t *pmd = __va(pgd_val(pgd[i]) - 1); + + /* + * only userspace pmd's are cleared for us + * by mm/memory.c; it's a slab cache invariant + * that we must separate the kernel pmd slab + * all times, else we'll have bad pmd's. + */ + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + kmem_cache_free(kpmd_cache, pmd); + else + kmem_cache_free(pmd_cache, pmd); + } +out_free: kmem_cache_free(pgd_cache, pgd); } + diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index a8b1954ae..ac6acb3ce 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -226,12 +226,7 @@ static void __init pci_fixup_nforce2(struct pci_dev *dev) fixed_val = rev < 0xC1 ? 0x1F01FF01 : 0x9F01FF01; pci_read_config_dword(dev, 0x6c, &val); - - /* - * Apply fixup only if C1 Halt Disconnect is enabled - * (bit28) because it is not supported on some boards. - */ - if ((val & (1 << 28)) && val != fixed_val) { + if (val != fixed_val) { printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); pci_write_config_dword(dev, 0x6c, fixed_val); } diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 98bea6d85..a603f523a 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -115,9 +115,7 @@ void restore_processor_state(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; - set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); /* This does ltr */ diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 64e4ec65f..d51c192d0 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -44,10 +44,7 @@ choice config IA64_GENERIC bool "generic" - select NUMA - select ACPI_NUMA select VIRTUAL_MEM_MAP - select DISCONTIGMEM help This selects the system type of your hardware. A "generic" kernel will run on any supported IA-64 system. However, if you configure @@ -78,6 +75,15 @@ config IA64_HP_SIM endchoice +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + default n + ---help--- + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu/cpu#. + Say N if you want to disable cpu hotplug. + choice prompt "Processor type" default ITANIUM @@ -244,15 +250,6 @@ config NR_CPUS than 64 will cause the use of a CPU mask array, causing a small performance hit. -config HOTPLUG_CPU - bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" - depends on SMP && HOTPLUG && EXPERIMENTAL - default n - ---help--- - Say Y here to experiment with turning CPUs off and on. CPUs - can be controlled through /sys/devices/system/cpu/cpu#. - Say N if you want to disable CPU hotplug. - config PREEMPT bool "Preemptible Kernel" help @@ -500,6 +497,8 @@ config SYSVIPC_COMPAT default y endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 2675ab3fb..7fd4296c7 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -59,12 +59,16 @@ core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/ core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ -core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ - +ifeq ($(CONFIG_DISCONTIGMEM),y) + core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ +endif drivers-$(CONFIG_PCI) += arch/ia64/pci/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ -drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/ +drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ +ifeq ($(CONFIG_DISCONTIGMEM),y) +drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/sn/ +endif drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/ boot := arch/ia64/hp/sim/boot @@ -73,6 +77,10 @@ boot := arch/ia64/hp/sim/boot all: compressed unwcheck +bzImage: compressed + mkdir -p arch/ia64/boot + cp vmlinux.gz arch/ia64/boot/bzImage + compressed: vmlinux.gz vmlinux.gz: vmlinux diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index babf3d1fc..1613474b1 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -146,7 +146,7 @@ ia64_elf32_init (struct pt_regs *regs) int ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) { - unsigned long stack_base; + unsigned long stack_base, grow; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i; @@ -163,7 +163,10 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + grow = (IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p)) + >> PAGE_SHIFT; + if (security_vm_enough_memory(grow) || + !vx_vmpages_avail(mm, grow)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -184,7 +187,9 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)? PAGE_COPY_EXEC: PAGE_COPY; insert_vm_struct(current->mm, mpnt); - current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + // current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + vx_vmpages_sub(current->mm, current->mm->total_vm - + ((mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -211,23 +216,10 @@ elf32_set_personality (void) } static unsigned long -elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused) { unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type, eppnt->p_offset - pgoff); } - -#define cpu_uses_ia32el() (local_cpu_data->family > 0x1f) - -static int __init check_elf32_binfmt(void) -{ - if (cpu_uses_ia32el()) { - printk("Please use IA-32 EL for executing IA-32 binaries\n"); - return unregister_binfmt(&elf_format); - } - return 0; -} - -module_init(check_elf32_binfmt) diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 45a49b600..75a3aa62d 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -21,7 +21,7 @@ * Jonathan Nicklin * Patrick O'Rourke * 11/07/2000 - */ + / /* * Global (preserved) predicate usage on syscall entry/exit path: * @@ -1362,7 +1362,15 @@ sys_call_table: data8 sys_syslog data8 sys_setitimer data8 sys_getitimer +#ifdef CONFIG_TUX + data8 __sys_tux // 1120 /* was: ia64_oldstat */ +#else +# ifdef CONFIG_TUX_MODULE + data8 sys_tux // 1120 /* was: ia64_oldstat */ +# else data8 sys_ni_syscall // 1120 /* was: ia64_oldstat */ +# endif +#endif data8 sys_ni_syscall /* was: ia64_oldlstat */ data8 sys_ni_syscall /* was: ia64_oldfstat */ data8 sys_vhangup diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 874bb10b7..c6e88e482 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -502,7 +502,6 @@ ENTRY(fsys_fallback_syscall) adds r17=-1024,r15 movl r14=sys_call_table ;; - rsm psr.i shladd r18=r17,3,r14 ;; ld8 r18=[r18] // load normal (heavy-weight) syscall entry-point @@ -543,7 +542,7 @@ GLOBAL_ENTRY(fsys_bubble_down) * to synthesize. */ # define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \ - | IA64_PSR_BN | IA64_PSR_I) + | IA64_PSR_BN) invala movl r8=PSR_ONE_BITS diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 0a5eb48d5..6f74b9a12 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -815,42 +815,6 @@ GLOBAL_ENTRY(ia64_delay_loop) br.ret.sptk.many rp END(ia64_delay_loop) -/* - * Return a CPU-local timestamp in nano-seconds. This timestamp is - * NOT synchronized across CPUs its return value must never be - * compared against the values returned on another CPU. The usage in - * kernel/sched.c ensures that. - * - * The return-value of sched_clock() is NOT supposed to wrap-around. - * If it did, it would cause some scheduling hiccups (at the worst). - * Fortunately, with a 64-bit cycle-counter ticking at 100GHz, even - * that would happen only once every 5+ years. - * - * The code below basically calculates: - * - * (ia64_get_itc() * local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT - * - * except that the multiplication and the shift are done with 128-bit - * intermediate precision so that we can produce a full 64-bit result. - */ -GLOBAL_ENTRY(sched_clock) - addl r8=THIS_CPU(cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0 - mov.m r9=ar.itc // fetch cycle-counter (35 cyc) - ;; - ldf8 f8=[r8] - ;; - setf.sig f9=r9 // certain to stall, so issue it _after_ ldf8... - ;; - xmpy.lu f10=f9,f8 // calculate low 64 bits of 128-bit product (4 cyc) - xmpy.hu f11=f9,f8 // calculate high 64 bits of 128-bit product - ;; - getf.sig r8=f10 // (5 cyc) - getf.sig r9=f11 - ;; - shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT - br.ret.sptk.many rp -END(sched_clock) - GLOBAL_ENTRY(start_kernel_thread) .prologue .save rp, r0 // this is the end of the call-chain diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 605c4e92a..4fc74cc17 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -58,8 +58,11 @@ EXPORT_SYMBOL(__strlen_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strnlen_user); +#define __KERNEL_SYSCALLS__ #include EXPORT_SYMBOL(__ia64_syscall); +EXPORT_SYMBOL(execve); +EXPORT_SYMBOL(clone); /* from arch/ia64/lib */ extern void __divsi3(void); @@ -103,6 +106,9 @@ EXPORT_SYMBOL(ia64_save_scratch_fpregs); #include EXPORT_SYMBOL(unw_init_running); +#include +EXPORT_SYMBOL(efi_mem_type); + #ifdef ASM_SUPPORTED # ifdef CONFIG_SMP # if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 9ef5f3ef9..33044bcb1 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -100,7 +100,7 @@ #endif static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; -extern cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; +cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 42056fbaa..37c17881d 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -56,6 +56,7 @@ #include #include +extern cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; /* * Linux has a controller-independent x86 interrupt architecture. @@ -84,11 +85,6 @@ irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { } }; -/* - * This is updated when the user sets irq affinity via /proc - */ -cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; - #ifdef CONFIG_IA64_GENERIC irq_desc_t * __ia64_irq_desc (unsigned int irq) { diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 85371f48a..df9539ab8 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -599,7 +599,7 @@ pfm_do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct) static inline unsigned long pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) { - return get_unmapped_area(file, addr, len, pgoff, flags); + return get_unmapped_area(file, addr, len, pgoff, flags, 0); } @@ -2361,7 +2361,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon */ insert_vm_struct(mm, vma); - mm->total_vm += size >> PAGE_SHIFT; + // mm->total_vm += size >> PAGE_SHIFT; + vx_vmpages_add(mm, size >> PAGE_SHIFT); up_write(&task->mm->mmap_sem); diff --git a/arch/ia64/kernel/perfmon_hpsim.h b/arch/ia64/kernel/perfmon_hpsim.h deleted file mode 100644 index 9c6fe7fc1..000000000 --- a/arch/ia64/kernel/perfmon_hpsim.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file contains the HP SKI Simulator PMU register description tables - * and pmc checkers used by perfmon.c. - * - * Copyright (C) 2002-2003 Hewlett Packard Co - * Stephane Eranian - * - * File mostly contributed by Ian Wienand - * - * This file is included as a dummy template so the kernel does not - * try to initalize registers the simulator can't handle. - * - * Note the simulator does not (currently) implement these registers, i.e., - * they do not count anything. But you can read/write them. - */ - -#define RDEP(x) (1UL<<(x)) - -#ifndef CONFIG_IA64_HP_SIM -#error "This file should only be included for the HP Simulator" -#endif - -static pfm_reg_desc_t pfm_hpsim_pmc_desc[PMU_MAX_PMCS]={ -/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL, 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL, 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL, 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL, 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc8 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc9 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc10 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(10), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc11 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(11), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc12 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(12), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc13 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(13), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc14 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(14), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc15 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(15), 0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, - { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ -}; - -static pfm_reg_desc_t pfm_hpsim_pmd_desc[PMU_MAX_PMDS]={ -/* pmd0 */ { PFM_REG_BUFFER, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmd1 */ { PFM_REG_BUFFER, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmd2 */ { PFM_REG_BUFFER, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmd3 */ { PFM_REG_BUFFER, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, -/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, -/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, -/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, -/* pmd8 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(8),0UL, 0UL, 0UL}}, -/* pmd9 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(9),0UL, 0UL, 0UL}}, -/* pmd10 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, -/* pmd11 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, -/* pmd12 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, -/* pmd13 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(13),0UL, 0UL, 0UL}}, -/* pmd14 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(14),0UL, 0UL, 0UL}}, -/* pmd15 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(15),0UL, 0UL, 0UL}}, - { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ -}; - -/* - * impl_pmcs, impl_pmds are computed at runtime to minimize errors! - */ -static pmu_config_t pmu_conf={ - .pmu_name = "hpsim", - .pmu_family = 0x7, /* ski emulator reports as Itanium */ - .enabled = 0, - .ovfl_val = (1UL << 32) - 1, - .num_ibrs = 0, /* does not use */ - .num_dbrs = 0, /* does not use */ - .pmd_desc = pfm_hpsim_pmd_desc, - .pmc_desc = pfm_hpsim_pmc_desc -}; diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 0432abe56..eace1b77c 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1310,6 +1310,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; + ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out_tsk; diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index aa2cb4fc3..26eb18052 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -330,8 +330,18 @@ setup_arch (char **cmdline_p) setup_serial_hcdp(efi.hcdp); } #endif - if (!efi.hcdp) - setup_serial_legacy(); + /* + * Without HCDP, we won't discover any serial ports until the serial driver looks + * in the ACPI namespace. If ACPI claims there are some legacy devices, register + * the legacy COM ports so serial console works earlier. This is slightly dangerous + * because we don't *really* know whether there's anything there, but we hope that + * all new boxes will implement HCDP. + */ + { + extern unsigned char acpi_legacy_devices; + if (!efi.hcdp && acpi_legacy_devices) + setup_serial_legacy(); + } #endif #ifdef CONFIG_VT @@ -625,9 +635,6 @@ cpu_init (void) ia32_cpu_init(); #endif - /* Clear ITC to eliminiate sched_clock() overflows in human time. */ - ia64_set_itc(0); - /* disable all local interrupt sources: */ ia64_set_itv(1 << 16); ia64_set_lrr0(1 << 16); diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 8cef119ac..8058fb588 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -202,6 +202,7 @@ ia64_sync_itc (unsigned int master) { long i, delta, adj, adjust_latency = 0, done = 0; unsigned long flags, rt, master_time_stamp, bound; + extern void ia64_cpu_local_tick (void); #if DEBUG_ITC_SYNC struct { long rt; /* roundtrip time */ @@ -524,7 +525,7 @@ build_cpu_to_node_map (void) #else # error Fixme: Dunno how to build CPU-to-node map. #endif - cpu_to_node_map[cpu] = (node >= 0) ? node : 0; + cpu_to_node_map[cpu] = node; if (node >= 0) cpu_set(cpu, node_to_cpu_mask[node]); } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index e33bcb661..3ebc74a5d 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -45,6 +45,14 @@ EXPORT_SYMBOL(last_cli_ip); #endif +unsigned long long +sched_clock (void) +{ + unsigned long offset = ia64_get_itc(); + + return (offset * local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; +} + static void itc_reset (void) { diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index d823ff897..20d11f4d5 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -36,10 +36,14 @@ expand_backing_store (struct vm_area_struct *vma, unsigned long address) if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)) return -ENOMEM; + if (!vx_vmpages_avail(vma->vm_mm, grow) + return -ENOMEM; vma->vm_end += PAGE_SIZE; - vma->vm_mm->total_vm += grow; + // vma->vm_mm->total_vm += grow; + vx_vmpages_add(vma->vm_mm, grow); if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; + // vma->vm_mm->locked_vm += grow; + vx_vmlocked_add(vma->vm_mm, grow); return 0; } diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index 56e409ec6..c72435812 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -65,7 +65,8 @@ set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma, { pte_t entry; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + // mm->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(mm, HPAGE_SIZE / PAGE_SIZE); if (write_access) { entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); @@ -108,7 +109,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, ptepage = pte_page(entry); get_page(ptepage); set_pte(dst_pte, entry); - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + // dst->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(dst, HPAGE_SIZE / PAGE_SIZE); addr += HPAGE_SIZE; } return 0; @@ -251,7 +253,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsig put_page(page); pte_clear(pte); } - mm->rss -= (end - start) >> PAGE_SHIFT; + // mm->rss -= (end - start) >> PAGE_SHIFT; + vx_rsspages_sub(mm, (end - start) >> PAGE_SHIFT); flush_tlb_range(vma, start, end); } diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index c03b3980d..b0a67b60e 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -216,6 +216,13 @@ free_initrd_mem (unsigned long start, unsigned long end) } } +int page_is_ram(unsigned long pagenr) +{ + //FIXME: implement w/efi walk + printk("page is ram is called!!!!!\n"); + return 1; +} + /* * This installs a clean page in the kernel's page table. */ diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 1fa88d5f3..35ea6886f 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -690,6 +690,8 @@ config DEBUG_INFO endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index b03d03163..65b1b9c7e 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -635,7 +635,8 @@ static inline void unswap_pte(struct vm_area_struct * vma, unsigned long set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); swap_free(entry); get_page(page); - ++vma->vm_mm->rss; + // ++vma->vm_mm->rss; + vx_rsspages_inc(vma->vm_mm); } static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 12e4acdfd..0f0b28d34 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -140,6 +140,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index f11317725..b8f71e760 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -566,6 +566,8 @@ config BDM_DISABLE endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 4f3df6d67..0c57f873a 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -124,6 +124,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 920bec861..8d6d86c07 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1646,6 +1646,8 @@ config DEBUG_HIGHMEM endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index dc9f7924e..0bcfb5ab6 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -686,7 +686,8 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* Do this so that we can load the interpreter, if need be. We will * change some of these later. */ - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); setup_arg_pages(bprm, EXSTACK_DEFAULT); current->mm->start_stack = bprm->p; diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index bcb3e0c5a..836474423 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -1201,7 +1201,7 @@ asmlinkage long sys32_newuname(struct new_utsname * name) int ret = 0; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (copy_to_user(name, vx_new_utsname(), sizeof *name)) ret = -EFAULT; up_read(&uts_sem); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 6e8511390..db86febff 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -76,6 +76,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 7e1eca973..5785d06bc 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -209,7 +209,7 @@ out: */ asmlinkage int sys_uname(struct old_utsname * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, vx_new_utsname(), sizeof (*name))) return 0; return -EFAULT; } @@ -220,21 +220,23 @@ asmlinkage int sys_uname(struct old_utsname * name) asmlinkage int sys_olduname(struct oldold_utsname * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); error = error ? -EFAULT : 0; @@ -260,10 +262,10 @@ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) return -EFAULT; down_write(&uts_sem); - strncpy(system_utsname.nodename, nodename, len); + strncpy(vx_new_uts(nodename), nodename, len); nodename[__NEW_UTS_LEN] = '\0'; - strlcpy(system_utsname.nodename, nodename, - sizeof(system_utsname.nodename)); + strlcpy(vx_new_uts(nodename), nodename, + sizeof(vx_new_uts(nodename))); up_write(&uts_sem); return 0; } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 25d7e97ed..3e0cf6e41 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -577,7 +577,8 @@ asmlinkage int irix_brk(unsigned long brk) /* * Check if we have enough memory.. */ - if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) { + if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT) || + !vx_vmpages_avail(mm, (newbrk-oldbrk) >> PAGE_SHIFT)) { ret = -ENOMEM; goto out; } diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index ccd63a41f..4f195174a 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -223,6 +223,8 @@ config DEBUG_INFO endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 514e8b5f8..d45980cb5 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -110,6 +110,9 @@ long sys_ptrace(long request, pid_t pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; + ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out_tsk; diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 6b5649a69..cd320b20c 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -676,6 +676,7 @@ asmlinkage int sys32_sysinfo(struct sysinfo32 *info) do { seq = read_seqbegin(&xtime_lock); + /* requires vx virtualization */ val.uptime = jiffies / HZ; val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c index 23c0322d5..3e9f887ee 100644 --- a/arch/ppc/8260_io/uart.c +++ b/arch/ppc/8260_io/uart.c @@ -161,7 +161,7 @@ static struct serial_state rs_table[] = { #ifndef CONFIG_SCC1_ENET { 0, 0, PROFF_SCC1, SIU_INT_SCC1, 0, SCC_NUM_BASE}, /* SCC1 ttyS2 */ #endif -#if !defined(CONFIG_SBC82xx) && !defined(CONFIG_SCC2_ENET) +#ifndef CONFIG_SCC2_ENET { 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE + 1}, /* SCC2 ttyS3 */ #endif }; @@ -475,7 +475,7 @@ static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs) if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL); + handle_sysrq(ch, regs, NULL, NULL); break_pressed = 0; goto ignore_char; } else diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 0d4e6516a..d5b49d26b 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -542,15 +542,6 @@ config EST8260 , but the EST8260 cannot be found on it and has probably been discontinued or rebadged. -config SBC82xx - bool "SBC82xx" - ---help--- - SBC PowerQUICC II, single-board computer with MPC82xx CPU - Manufacturer: Wind River Systems, Inc. - Date of Release: May 2003 - End of Life: - - URL: - config SBS8260 bool "SBS8260" @@ -584,7 +575,7 @@ config EMBEDDEDBOOT config 8260 bool "MPC8260 CPM Support" if WILLOW depends on 6xx - default y if TQM8260 || RPXSUPER || EST8260 || SBS8260 || SBC82xx + default y if TQM8260 || RPXSUPER || EST8260 || SBS8260 help The MPC8260 CPM (Communications Processor Module) is a typical embedded CPU made by Motorola. Selecting this option means that @@ -1278,6 +1269,8 @@ config PPC_OCP endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 54e9a9e6d..36d94afe2 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -54,6 +54,7 @@ AFLAGS_vmlinux.lds.o := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage + cp vmlinux arch/ppc/boot/bzImage boot := arch/$(ARCH)/boot @@ -86,7 +87,7 @@ include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s ifdef CONFIG_6xx # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later -NEW_AS := $(shell echo dssall | $(AS) -many -o /dev/null >/dev/null 2>&1 ; echo $$?) +NEW_AS := $(shell echo dssall | $(AS) -o /dev/null >/dev/null 2>&1 ; echo $$?) GOODVER := 2.12.1 else NEW_AS := 0 @@ -94,7 +95,7 @@ endif ifneq ($(NEW_AS),0) checkbin: - @echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' + @echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build' @echo 'correctly with old versions of binutils.' @echo '*** Please upgrade your binutils to ${GOODVER} or newer' @false diff --git a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c index 4dc12e6ab..8f40dd1a1 100644 --- a/arch/ppc/boot/simple/embed_config.c +++ b/arch/ppc/boot/simple/embed_config.c @@ -10,7 +10,6 @@ #include #include #include -#include #ifdef CONFIG_8xx #include #endif @@ -403,18 +402,14 @@ embed_config(bd_t **bdp) #ifdef CONFIG_8260 /* Compute 8260 clock values if the rom doesn't provide them. + * We can't compute the internal core frequency (I don't know how to + * do that). */ -static unsigned char bus2core_8260[] = { -/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - 3, 2, 2, 2, 4, 4, 5, 9, 6, 11, 8, 10, 3, 12, 7, 2, - 6, 5, 13, 2, 14, 4, 15, 2, 3, 11, 8, 10, 16, 12, 7, 2, -}; - static void clk_8260(bd_t *bd) { uint scmr, vco_out, clkin; - uint plldf, pllmf, corecnf; + uint plldf, pllmf, busdf, brgdf, cpmdf; volatile immap_t *ip; ip = (immap_t *)IMAP_ADDR; @@ -428,7 +423,8 @@ clk_8260(bd_t *bd) */ plldf = (scmr >> 12) & 1; pllmf = scmr & 0xfff; - corecnf = (scmr >> 24) &0x1f; + cpmdf = (scmr >> 16) & 0x0f; + busdf = (scmr >> 20) & 0x0f; /* This is arithmetic from the 8260 manual. */ @@ -437,7 +433,6 @@ clk_8260(bd_t *bd) bd->bi_vco = vco_out; /* Save for later */ bd->bi_cpmfreq = vco_out / 2; /* CPM Freq, in MHz */ - bd->bi_intfreq = bd->bi_busfreq * bus2core_8260[corecnf] / 2; /* Set Baud rate divisor. The power up default is divide by 16, * but we set it again here in case it was changed. @@ -445,79 +440,8 @@ clk_8260(bd_t *bd) ip->im_clkrst.car_sccr = 1; /* DIV 16 BRG */ bd->bi_brgfreq = vco_out / 16; } - -static unsigned char bus2core_8280[] = { -/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - 3, 2, 2, 2, 4, 4, 5, 9, 6, 11, 8, 10, 3, 12, 7, 2, - 6, 5, 13, 2, 14, 2, 15, 2, 3, 2, 2, 2, 16, 2, 2, 2, -}; - -static void -clk_8280(bd_t *bd) -{ - uint scmr, main_clk, clkin; - uint pllmf, corecnf; - volatile immap_t *ip; - - ip = (immap_t *)IMAP_ADDR; - scmr = ip->im_clkrst.car_scmr; - - /* The clkin is always bus frequency. - */ - clkin = bd->bi_busfreq; - - /* Collect the bits from the scmr. - */ - pllmf = scmr & 0xf; - corecnf = (scmr >> 24) & 0x1f; - - /* This is arithmetic from the 8280 manual. - */ - main_clk = clkin * (pllmf + 1); - - bd->bi_cpmfreq = main_clk / 2; /* CPM Freq, in MHz */ - bd->bi_intfreq = bd->bi_busfreq * bus2core_8280[corecnf] / 2; - - /* Set Baud rate divisor. The power up default is divide by 16, - * but we set it again here in case it was changed. - */ - ip->im_clkrst.car_sccr = (ip->im_clkrst.car_sccr & 0x3) | 0x1; - bd->bi_brgfreq = main_clk / 16; -} #endif -#ifdef CONFIG_SBC82xx -void -embed_config(bd_t **bdp) -{ - u_char *cp; - int i; - bd_t *bd; - unsigned long pvr; - - bd = *bdp; - - bd = &bdinfo; - *bdp = bd; - bd->bi_baudrate = 9600; - bd->bi_memsize = 256 * 1024 * 1024; /* just a guess */ - - cp = (void*)SBC82xx_MACADDR_NVRAM_SCC1; - memcpy(bd->bi_enetaddr, cp, 6); - - /* can busfreq be calculated? */ - pvr = mfspr(PVR); - if ((pvr & 0xffff0000) == 0x80820000) { - bd->bi_busfreq = 100000000; - clk_8280(bd); - } else { - bd->bi_busfreq = 66000000; - clk_8260(bd); - } - -} -#endif /* SBC82xx */ - #if defined(CONFIG_EST8260) || defined(CONFIG_TQM8260) void embed_config(bd_t **bdp) diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index 78f85e675..45732ae13 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -350,14 +350,6 @@ struct cpu_spec cpu_specs[] = { 32, 32, __setup_cpu_603 }, - { /* 8280 is a G2_LE (603e core, plus some) */ - 0x7fff0000, 0x00820000, "8280", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, - COMMON_PPC, - 32, 32, - __setup_cpu_603 - }, { /* default match, we assume split I/D cache & TB (non-601)... */ 0x00000000, 0x00000000, "(generic PPC)", CPU_FTR_COMMON | diff --git a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S new file mode 100644 index 000000000..8f0c590f1 --- /dev/null +++ b/arch/ppc/kernel/head_e500.S @@ -0,0 +1,1329 @@ +/* + * arch/ppc/kernel/head_e500.S + * + * Kernel execution entry point code. + * + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * Copyright 2002-2004 MontaVista Software, Inc. + * PowerPC 44x support, Matt Porter + * Copyright 2004 Freescale Semiconductor, Inc + * PowerPC e500 modifications, Kumar Gala + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Macros + */ + +#define SET_IVOR(vector_number, vector_label) \ + li r26,vector_label@l; \ + mtspr SPRN_IVOR##vector_number,r26; \ + sync + +/* As with the other PowerPC ports, it is expected that when code + * execution begins here, the following registers contain valid, yet + * optional, information: + * + * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) + * r4 - Starting address of the init RAM disk + * r5 - Ending address of the init RAM disk + * r6 - Start of kernel command line string (e.g. "mem=128") + * r7 - End of kernel command line string + * + */ + .text +_GLOBAL(_stext) +_GLOBAL(_start) + /* + * Reserve a word at a fixed location to store the address + * of abatron_pteptrs + */ + nop +/* + * Save parameters we are passed + */ + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* CPU number */ + +/* We try to not make any assumptions about how the boot loader + * setup or used the TLBs. We invalidate all mappings from the + * boot loader and load a single entry in TLB1[0] to map the + * first 16M of kernel memory. Any boot info passed from the + * bootloader needs to live in this first 16M. + * + * Requirement on bootloader: + * - The page we're executing in needs to reside in TLB1 and + * have IPROT=1. If not an invalidate broadcast could + * evict the entry we're currently executing in. + * + * r3 = Index of TLB1 were executing in + * r4 = Current MSR[IS] + * r5 = Index of TLB1 temp mapping + * + * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0] + * if needed + */ + +/* 1. Find the index of the entry we're executing in */ + bl invstr /* Find our address */ +invstr: mflr r6 /* Make it accessible */ + mfmsr r7 + rlwinm r4,r7,27,31,31 /* extract MSR[IS] */ + mfspr r7, SPRN_PID0 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + mfspr r7,SPRN_PID1 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */ + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + mfspr r7, SPRN_PID2 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* Fall through, we had to match */ +match_TLB: + mfspr r7,SPRN_MAS0 + rlwinm r3,r7,16,28,31 /* Extract MAS0(Entry) */ + + mfspr r7,SPRN_MAS1 /* Insure IPROT set */ + oris r7,r7,MAS1_IPROT@h + mtspr SPRN_MAS1,r7 + tlbwe + +/* 2. Invalidate all entries except the entry we're executing in */ + mfspr r9,SPRN_TLB1CFG + andi. r9,r9,0xfff + li r6,0 /* Set Entry counter to 0 */ +1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r6,16,12,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */ + mtspr SPRN_MAS0,r7 + tlbre + mfspr r7,SPRN_MAS1 + rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */ + cmpw r3,r6 + beq skpinv /* Dont update the current execution TLB */ + mtspr SPRN_MAS1,r7 + tlbwe + isync +skpinv: addi r6,r6,1 /* Increment */ + cmpw r6,r9 /* Are we done? */ + bne 1b /* If not, repeat */ + + /* Invalidate TLB0 */ + li r6,0x04 + tlbivax 0,r6 +#ifdef CONFIG_SMP + tlbsync +#endif + /* Invalidate TLB1 */ + li r6,0x0c + tlbivax 0,r6 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + +/* 3. Setup a temp mapping and jump to it */ + andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */ + addi r5, r5, 0x1 + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,12,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + + /* Just modify the entry ID and EPN for the temp mapping */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,12,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + xori r6,r4,1 /* Setup TMP mapping in the other Address space */ + slwi r6,r6,12 + oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l + mtspr SPRN_MAS1,r6 + mfspr r6,SPRN_MAS2 + li r7,0 /* temp EPN = 0 */ + rlwimi r7,r6,0,20,31 + mtspr SPRN_MAS2,r7 + tlbwe + + xori r6,r4,1 + slwi r6,r6,5 /* setup new context with other address space */ + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r7,r9,0,20,31 + addi r7,r7,24 + mtspr SRR0,r7 + mtspr SRR1,r6 + rfi + +/* 4. Clear out PIDs & Search info */ + li r6,0 + mtspr SPRN_PID0,r6 + mtspr SPRN_PID1,r6 + mtspr SPRN_PID2,r6 + mtspr SPRN_MAS6,r6 + +/* 5. Invalidate mapping we started in */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,12,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + li r6,0 + mtspr SPRN_MAS1,r6 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + +/* 6. Setup KERNELBASE mapping in TLB1[0] */ + lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ + mtspr SPRN_MAS0,r6 + lis r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l + mtspr SPRN_MAS1,r6 + li r7,0 + lis r6,KERNELBASE@h + ori r6,r6,KERNELBASE@l + rlwimi r6,r7,0,20,31 + mtspr SPRN_MAS2,r6 + li r7,(MAS3_SX|MAS3_SW|MAS3_SR) + mtspr SPRN_MAS3,r7 + tlbwe + +/* 7. Jump to KERNELBASE mapping */ + li r7,0 + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r6,r9,0,20,31 + addi r6,r6,24 + mtspr SRR0,r6 + mtspr SRR1,r7 + rfi /* start execution out of TLB1[0] entry */ + +/* 8. Clear out the temp mapping */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,12,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + tlbre + mtspr SPRN_MAS1,r8 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 +#ifdef CONFIG_SMP + tlbsync +#endif + msync + + /* Establish the interrupt vector offsets */ + SET_IVOR(0, CriticalInput); + SET_IVOR(1, MachineCheck); + SET_IVOR(2, DataStorage); + SET_IVOR(3, InstructionStorage); + SET_IVOR(4, ExternalInput); + SET_IVOR(5, Alignment); + SET_IVOR(6, Program); + SET_IVOR(7, FloatingPointUnavailable); + SET_IVOR(8, SystemCall); + SET_IVOR(9, AuxillaryProcessorUnavailable); + SET_IVOR(10, Decrementer); + SET_IVOR(11, FixedIntervalTimer); + SET_IVOR(12, WatchdogTimer); + SET_IVOR(13, DataTLBError); + SET_IVOR(14, InstructionTLBError); + SET_IVOR(15, Debug); + SET_IVOR(32, SPEUnavailable); + SET_IVOR(33, SPEFloatingPointData); + SET_IVOR(34, SPEFloatingPointRound); + SET_IVOR(35, PerformanceMonitor); + + /* Establish the interrupt vector base */ + lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ + mtspr SPRN_IVPR,r4 + + /* Setup the defaults for TLB entries */ + li r2,MAS4_TSIZED(BOOKE_PAGESZ_4K) + mtspr SPRN_MAS4, r2 + +#if 0 + /* Enable DOZE */ + mfspr r2,SPRN_HID0 + oris r2,r2,HID0_DOZE@h + mtspr SPRN_HID0, r2 +#endif + + /* + * This is where the main kernel code starts. + */ + + /* ptr to current */ + lis r2,init_task@h + ori r2,r2,init_task@l + + /* ptr to current thread */ + addi r4,r2,THREAD /* init task's THREAD */ + mtspr SPRG3,r4 + + /* stack */ + lis r1,init_thread_union@h + ori r1,r1,init_thread_union@l + li r0,0 + stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) + + bl early_init + + mfspr r3,SPRN_TLB1CFG + andi. r3,r3,0xfff + lis r4,num_tlbcam_entries@ha + stw r3,num_tlbcam_entries@l(r4) +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl machine_init + bl MMU_init + + /* Setup PTE pointers for the Abatron bdiGDB */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + lis r4, KERNELBASE@h + ori r4, r4, KERNELBASE@l + stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ + stw r6, 0(r5) + + /* Let's move on */ + lis r4,start_kernel@h + ori r4,r4,start_kernel@l + lis r3,MSR_KERNEL@h + ori r3,r3,MSR_KERNEL@l + mtspr SRR0,r4 + mtspr SRR1,r3 + rfi /* change context and jump to start_kernel */ + +/* + * Interrupt vector entry code + * + * The Book E MMUs are always on so we don't need to handle + * interrupts in real mode as with previous PPC processors. In + * this case we handle interrupts in the kernel virtual address + * space. + * + * Interrupt vectors are dynamically placed relative to the + * interrupt prefix as determined by the address of interrupt_base. + * The interrupt vectors offsets are programmed using the labels + * for each interrupt vector entry. + * + * Interrupt vectors must be aligned on a 16 byte boundary. + * We align on a 32 byte cache line boundary for good measure. + */ + +#define NORMAL_EXCEPTION_PROLOG \ + mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ + mtspr SPRN_SPRG1,r11; \ + mtspr SPRN_SPRG4W,r1; \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + beq 1f; \ + mfspr r1,SPRG3; /* if from user, start at top of */\ + lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ + addi r1,r1,THREAD_SIZE; \ +1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ + tophys(r11,r1); \ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mfspr r10,SPRG0; \ + stw r10,GPR10(r11); \ + mfspr r12,SPRG1; \ + stw r12,GPR11(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r10,SPRG4R; \ + mfspr r12,SRR0; \ + stw r10,GPR1(r11); \ + mfspr r9,SRR1; \ + stw r10,0(r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for critical exceptions. This is a little different + * from the normal exception prolog above since a critical exception + * can potentially occur at any point during normal exception processing. + * Thus we cannot use the same SPRG registers as the normal prolog above. + * Instead we use a couple of words of memory at low physical addresses. + * This is OK since we don't support SMP on these processors. For Book E + * processors, we also have a reserved register (SPRG2) that is only used + * in critical exceptions so we can free up a GPR to use as the base for + * indirect access to the critical exception save area. This is necessary + * since the MMU is always on and the save area is offset from KERNELBASE. + */ +#define CRITICAL_EXCEPTION_PROLOG \ + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ + lis r8,crit_save@ha; \ + stw r10,crit_r10@l(r8); \ + stw r11,crit_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,crit_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,crit_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,crit_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,crit_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,crit_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,crit_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,crit_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,crit_srr1@l(r8); \ + mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,critical_stack_top@h; \ + ori r11,r11,critical_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,CSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,CSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception prolog for machine check exceptions. This is similar to + * the critical exception prolog, except that machine check exceptions + * have their own save area. For Book E processors, we also have a + * reserved register (SPRG6) that is only used in machine check exceptions + * so we can free up a GPR to use as the base for indirect access to the + * machine check exception save area. This is necessary since the MMU + * is always on and the save area is offset from KERNELBASE. + */ +#define MCHECK_EXCEPTION_PROLOG \ + mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ + lis r8,mcheck_save@ha; \ + stw r10,mcheck_r10@l(r8); \ + stw r11,mcheck_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,mcheck_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,mcheck_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,mcheck_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,mcheck_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,mcheck_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,mcheck_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,mcheck_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,mcheck_srr1@l(r8); \ + mfspr r10,CSRR0; \ + stw r10,mcheck_csrr0@l(r8); \ + mfspr r10,CSRR1; \ + stw r10,mcheck_csrr1@l(r8); \ + mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,mcheck_stack_top@h; \ + ori r11,r11,mcheck_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,MCSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,MCSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + +/* + * Exception vectors. + */ +#define START_EXCEPTION(label) \ + .align 5; \ +label: + +#define FINISH_EXCEPTION(func) \ + bl transfer_to_handler_full; \ + .long func; \ + .long ret_from_except_full + +#define EXCEPTION(n, label, hdlr, xfer) \ + START_EXCEPTION(label); \ + NORMAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + xfer(n, hdlr) + +#define CRITICAL_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + CRITICAL_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define MCHECK_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + MCHECK_EXCEPTION_PROLOG; \ + mfspr r5,SPRN_ESR; \ + stw r5,_ESR(r11); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, mcheck_transfer_to_handler, \ + ret_from_mcheck_exc) + +#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ + li r10,trap; \ + stw r10,TRAP(r11); \ + lis r10,msr@h; \ + ori r10,r10,msr@l; \ + copyee(r10, r9); \ + bl tfer; \ + .long hdlr; \ + .long ret + +#define COPY_EE(d, s) rlwimi d,s,0,16,16 +#define NOCOPY(d, s) + +#define EXC_XFER_STD(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ + ret_from_except) + +#define EXC_XFER_EE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ + ret_from_except_full) + +#define EXC_XFER_EE_LITE(n, hdlr) \ + EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ + ret_from_except) + +interrupt_base: + /* Critical Input Interrupt */ + CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) + + /* Machine Check Interrupt */ + MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + + /* Data Storage Interrupt */ + START_EXCEPTION(DataStorage) + mtspr SPRG0, r10 /* Save some working registers */ + mtspr SPRG1, r11 + mtspr SPRG4W, r12 + mtspr SPRG5W, r13 + mfcr r11 + mtspr SPRG7W, r11 + + /* + * Check if it was a store fault, if not then bail + * because a user tried to access a kernel or + * read-protected page. Otherwise, get the + * offending address and handle it. + */ + mfspr r10, SPRN_ESR + andis. r10, r10, ESR_ST@h + beq 2f + + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 0, r10, r11 + bge 2f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRG3 + lwz r11,PGDIR(r11) +4: + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r11, 0(r11) /* Get L1 entry */ + rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + + /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */ + andi. r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE + cmpwi 0, r13, _PAGE_RW|_PAGE_USER + bne 2f /* Bail if not */ + + /* Update 'changed'. */ + ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + stw r11, 0(r12) /* Update Linux page table */ + + /* MAS2 not updated as the entry does exist in the tlb, this + fault taken to detect state transition (eg: COW -> DIRTY) + */ + lis r12, MAS3_RPN@h + ori r12, r12, _PAGE_HWEXEC | MAS3_RPN@l + and r11, r11, r12 + rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ + ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ + + /* update search PID in MAS6, AS = 0 */ + mfspr r12, SPRN_PID0 + slwi r12, r12, 16 + mtspr SPRN_MAS6, r12 + + /* find the TLB index that caused the fault. It has to be here. */ + tlbsx 0, r10 + + mtspr SPRN_MAS3,r11 + tlbwe + + /* Done...restore registers and get out of here. */ + mfspr r11, SPRG7R + mtcr r11 + mfspr r13, SPRG5R + mfspr r12, SPRG4R + mfspr r11, SPRG1 + mfspr r10, SPRG0 + rfi /* Force context change */ + +2: + /* + * The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRG7R + mtcr r11 + mfspr r13, SPRG5R + mfspr r12, SPRG4R + mfspr r11, SPRG1 + mfspr r10, SPRG0 + b data_access + + /* Instruction Storage Interrupt */ + START_EXCEPTION(InstructionStorage) + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR and save it */ + stw r5,_ESR(r11) + mr r4,r12 /* Pass SRR0 as arg2 */ + li r5,0 /* Pass zero as arg3 */ + EXC_XFER_EE_LITE(0x0400, handle_page_fault) + + /* External Input Interrupt */ + EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) + + /* Alignment Interrupt */ + START_EXCEPTION(Alignment) + NORMAL_EXCEPTION_PROLOG + mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ + stw r4,_DEAR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0x0600, AlignmentException) + + /* Program Interrupt */ + START_EXCEPTION(Program) + NORMAL_EXCEPTION_PROLOG + mfspr r4,SPRN_ESR /* Grab the ESR and save it */ + stw r4,_ESR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_STD(0x0700, ProgramCheckException) + + /* Floating Point Unavailable Interrupt */ + EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) + + /* System Call Interrupt */ + START_EXCEPTION(SystemCall) + NORMAL_EXCEPTION_PROLOG + EXC_XFER_EE_LITE(0x0c00, DoSyscall) + + /* Auxillary Processor Unavailable Interrupt */ + EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) + + /* Decrementer Interrupt */ + START_EXCEPTION(Decrementer) + NORMAL_EXCEPTION_PROLOG + lis r0,TSR_DIS@h /* Setup the DEC interrupt mask */ + mtspr SPRN_TSR,r0 /* Clear the DEC interrupt */ + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_LITE(0x0900, timer_interrupt) + + /* Fixed Internal Timer Interrupt */ + /* TODO: Add FIT support */ + EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) + + /* Watchdog Timer Interrupt */ + /* TODO: Add watchdog support */ + CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) + + /* Data TLB Error Interrupt */ + START_EXCEPTION(DataTLBError) + mtspr SPRG0, r10 /* Save some working registers */ + mtspr SPRG1, r11 + mtspr SPRG4W, r12 + mtspr SPRG5W, r13 + mfcr r11 + mtspr SPRG7W, r11 + mfspr r10, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 5, r10, r11 + blt 5, 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MAS1 /* Set TID to 0 */ + li r13,MAS1_TID@l + andc r12,r12,r13 + mtspr SPRN_MAS1,r12 + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRG3 + lwz r11,PGDIR(r11) + +4: + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r11, 0(r11) /* Get L1 entry */ + rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + andi. r13, r11, _PAGE_PRESENT + beq 2f + + ori r11, r11, _PAGE_ACCESSED + stw r11, 0(r12) + + /* Jump to common tlb load */ + b finish_tlb_load +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRG7R + mtcr r11 + mfspr r13, SPRG5R + mfspr r12, SPRG4R + mfspr r11, SPRG1 + mfspr r10, SPRG0 + b data_access + + /* Instruction TLB Error Interrupt */ + /* + * Nearly the same as above, except we get our + * information from different registers and bailout + * to a different point. + */ + START_EXCEPTION(InstructionTLBError) + mtspr SPRG0, r10 /* Save some working registers */ + mtspr SPRG1, r11 + mtspr SPRG4W, r12 + mtspr SPRG5W, r13 + mfcr r11 + mtspr SPRG7W, r11 + mfspr r10, SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11, TASK_SIZE@h + ori r11, r11, TASK_SIZE@l + cmplw 5, r10, r11 + blt 5, 3f + lis r11, swapper_pg_dir@h + ori r11, r11, swapper_pg_dir@l + + mfspr r12,SPRN_MAS1 /* Set TID to 0 */ + li r13,MAS1_TID@l + andc r12,r12,r13 + mtspr SPRN_MAS1,r12 + + b 4f + + /* Get the PGD for the current thread */ +3: + mfspr r11,SPRG3 + lwz r11,PGDIR(r11) + +4: + rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r11, 0(r11) /* Get L1 entry */ + rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ + lwz r11, 0(r12) /* Get Linux PTE */ + andi. r13, r11, _PAGE_PRESENT + beq 2f + + ori r11, r11, _PAGE_ACCESSED + stw r11, 0(r12) + + /* Jump to common TLB load point */ + b finish_tlb_load + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRG7R + mtcr r11 + mfspr r13, SPRG5R + mfspr r12, SPRG4R + mfspr r11, SPRG1 + mfspr r10, SPRG0 + b InstructionStorage + +#ifdef CONFIG_SPE + /* SPE Unavailable */ + START_EXCEPTION(SPEUnavailable) + NORMAL_EXCEPTION_PROLOG + bne load_up_spe + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x2010, KernelSPE) +#else + EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE) +#endif /* CONFIG_SPE */ + + /* SPE Floating Point Data */ +#ifdef CONFIG_SPE + EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE); +#else + EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE) +#endif /* CONFIG_SPE */ + + /* SPE Floating Point Round */ + EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE) + + /* Performance Monitor */ + EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE) + +/* Check for a single step debug exception while in an exception + * handler before state has been saved. This is to catch the case + * where an instruction that we are trying to single step causes + * an exception (eg ITLB/DTLB miss) and thus the first instruction of + * the exception handler generates a single step debug exception. + * + * If we get a debug trap on the first instruction of an exception handler, + * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is + * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). + * The exception handler was handling a non-critical interrupt, so it will + * save (and later restore) the MSR via SPRN_SRR1, which will still have + * the MSR_DE bit set. + */ + /* Debug Interrupt */ + START_EXCEPTION(Debug) + CRITICAL_EXCEPTION_PROLOG + + /* + * If this is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the CSRR1 value and clearing the debug status. + */ + mfspr r10,SPRN_DBSR /* check single-step/branch taken */ + andis. r10,r10,(DBSR_IC|DBSR_BT)@h + beq+ 1f + andi. r0,r9,MSR_PR /* check supervisor */ + beq 2f /* branch if we need to fix it up... */ + + /* continue normal handling for a critical exception... */ +1: mfspr r4,SPRN_DBSR + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(DebugException, 0x2002, \ + (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) + + /* here it looks like we got an inappropriate debug exception. */ +2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the CSRR1 value */ + mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */ + /* restore state and get out */ + lwz r10,_CCR(r11) + lwz r0,GPR0(r11) + lwz r1,GPR1(r11) + mtcrf 0x80,r10 + mtspr CSRR0,r12 + mtspr CSRR1,r9 + lwz r9,GPR9(r11) + + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ + lis r8,crit_save@ha; + lwz r10,crit_r10@l(r8) + lwz r11,crit_r11@l(r8) + mfspr r8,SPRG2 + + rfci + b . + +/* + * Local functions + */ + /* + * Data TLB exceptions will bail out to this point + * if they can't resolve the lightweight TLB fault. + */ +data_access: + NORMAL_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r11) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + andis. r10,r5,(ESR_ILK|ESR_DLK)@h + bne 1f + EXC_XFER_EE_LITE(0x0300, handle_page_fault) +1: + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE_LITE(0x0300, CacheLockingException) + +/* + + * Both the instruction and data TLB miss get to this + * point to load the TLB. + * r10 - EA of fault + * r11 - TLB (info from Linux PTE) + * r12, r13 - available to use + * CR5 - results of addr < TASK_SIZE + * MAS0, MAS1 - loaded with proper value when we get here + * MAS2, MAS3 - will need additional info from Linux PTE + * Upon exit, we reload everything and RFI. + */ +finish_tlb_load: + /* + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + + mfspr r12, SPRN_MAS2 + rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ + mtspr SPRN_MAS2, r12 + + bge 5, 1f + + /* addr > TASK_SIZE */ + li r10, (MAS3_UX | MAS3_UW | MAS3_UR) + andi. r13, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC) + andi. r12, r11, _PAGE_USER /* Test for _PAGE_USER */ + iseleq r12, 0, r10 + and r10, r12, r13 + srwi r12, r10, 1 + or r12, r12, r10 /* Copy user perms into supervisor */ + b 2f + + /* addr <= TASK_SIZE */ +1: rlwinm r12, r11, 31, 29, 29 /* Extract _PAGE_HWWRITE into SW */ + ori r12, r12, (MAS3_SX | MAS3_SR) + +2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ + mtspr SPRN_MAS3, r11 + tlbwe + + /* Done...restore registers and get out of here. */ + mfspr r11, SPRG7R + mtcr r11 + mfspr r13, SPRG5R + mfspr r12, SPRG4R + mfspr r11, SPRG1 + mfspr r10, SPRG0 + rfi /* Force context change */ + +#ifdef CONFIG_SPE +/* Note that the SPE support is closely modeled after the AltiVec + * support. Changes to one are likely to be applicable to the + * other! */ +load_up_spe: +/* + * Disable SPE for the task which had SPE previously, + * and save its SPE registers in its thread_struct. + * Enables SPE for use in the kernel on return. + * On SMP we know the SPE units are free, since we give it up every + * switch. -- Kumar + */ + mfmsr r5 + oris r5,r5,MSR_SPE@h + mtmsr r5 /* enable use of SPE now */ + isync +/* + * For SMP, we don't do lazy SPE switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_spe in switch_to. + */ +#ifndef CONFIG_SMP + lis r3,last_task_used_spe@ha + lwz r4,last_task_used_spe@l(r3) + cmpi 0,r4,0 + beq 1f + addi r4,r4,THREAD /* want THREAD of last_task_used_spe */ + SAVE_32EVR(0,r10,r4) + evxor evr10, evr10, evr10 /* clear out evr10 */ + evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */ + li r5,THREAD_ACC + evstddx evr10, r4, r5 /* save off accumulator */ + lwz r5,PT_REGS(r4) + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r10,MSR_SPE@h + andc r4,r4,r10 /* disable SPE for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* CONFIG_SMP */ + /* enable use of SPE after return */ + oris r9,r9,MSR_SPE@h + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + li r4,1 + li r10,THREAD_ACC + stw r4,THREAD_USED_SPE(r5) + evlddx evr4,r10,r5 + evmra evr4,evr4 + REST_32EVR(0,r10,r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + stw r4,last_task_used_spe@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ +2: REST_4GPRS(3, r11) + lwz r10,_CCR(r11) + REST_GPR(1, r11) + mtcr r10 + lwz r10,_LINK(r11) + mtlr r10 + REST_GPR(10, r11) + mtspr SRR1,r9 + mtspr SRR0,r12 + REST_GPR(9, r11) + REST_GPR(12, r11) + lwz r11,GPR11(r11) + SYNC + rfi + + + +/* + * SPE unavailable trap from kernel - print a message, but let + * the task use SPE in the kernel until it returns to user mode. + */ +KernelSPE: + lwz r3,_MSR(r1) + oris r3,r3,MSR_SPE@h + stw r3,_MSR(r1) /* enable use of SPE after return */ + lis r3,87f@h + ori r3,r3,87f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +87: .string "SPE used in kernel (task=%p, pc=%x) \n" + .align 4,0 + +#endif /* CONFIG_SPE */ + +/* + * Global functions + */ + +/* + * extern void loadcam_entry(unsigned int index) + * + * Load TLBCAM[index] entry in to the L2 CAM MMU + */ +_GLOBAL(loadcam_entry) + lis r4,TLBCAM@ha + addi r4,r4,TLBCAM@l + mulli r5,r3,20 + add r3,r5,r4 + lwz r4,0(r3) + mtspr SPRN_MAS0,r4 + lwz r4,4(r3) + mtspr SPRN_MAS1,r4 + lwz r4,8(r3) + mtspr SPRN_MAS2,r4 + lwz r4,12(r3) + mtspr SPRN_MAS3,r4 + tlbwe + isync + blr + +/* + * extern void giveup_altivec(struct task_struct *prev) + * + * The e500 core does not have an AltiVec unit. + */ +_GLOBAL(giveup_altivec) + blr + +#ifdef CONFIG_SPE +/* + * extern void giveup_spe(struct task_struct *prev) + * + */ +_GLOBAL(giveup_spe) + mfmsr r5 + oris r5,r5,MSR_SPE@h + SYNC + mtmsr r5 /* enable use of SPE now */ + isync + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32EVR(0, r4, r3) + evxor evr6, evr6, evr6 /* clear out evr6 */ + evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */ + li r4,THREAD_ACC + evstddx evr6, r4, r3 /* save off accumulator */ + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_SPE@h + andc r4,r4,r3 /* disable SPE for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_spe@ha + stw r5,last_task_used_spe@l(r4) +#endif /* CONFIG_SMP */ + blr +#endif /* CONFIG_SPE */ + +/* + * extern void giveup_fpu(struct task_struct *prev) + * + * The e500 core does not have an FPU. + */ +_GLOBAL(giveup_fpu) + blr + +/* + * extern void abort(void) + * + * At present, this routine just applies a system reset. + */ +_GLOBAL(abort) + li r13,0 + mtspr SPRN_DBCR0,r13 /* disable all debug events */ + mfmsr r13 + ori r13,r13,MSR_DE@l /* Enable Debug Events */ + mtmsr r13 + mfspr r13,SPRN_DBCR0 + lis r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h + mtspr SPRN_DBCR0,r13 + +_GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is the second parameter. + */ + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r4, 0x4(r5) +#endif + mtspr SPRN_PID,r3 + isync /* Force context change */ + blr + +/* + * We put a few things here that have to be page-aligned. This stuff + * goes at the beginning of the data segment, which is page-aligned. + */ + .data +_GLOBAL(sdata) +_GLOBAL(empty_zero_page) + .space 4096 +_GLOBAL(swapper_pg_dir) + .space 4096 + + .section .bss +/* Stack for handling critical exceptions from kernel mode */ +critical_stack_bottom: + .space 4096 +critical_stack_top: + .previous + +/* Stack for handling machine check exceptions from kernel mode */ +mcheck_stack_bottom: + .space 4096 +mcheck_stack_top: + .previous + +/* + * This area is used for temporarily saving registers during the + * critical and machine check exception prologs. It must always + * follow the page aligned allocations, so it starts on a page + * boundary, ensuring that all crit_save areas are in a single + * page. + */ + +/* crit_save */ +_GLOBAL(crit_save) + .space 4 +_GLOBAL(crit_r10) + .space 4 +_GLOBAL(crit_r11) + .space 4 +_GLOBAL(crit_sprg0) + .space 4 +_GLOBAL(crit_sprg1) + .space 4 +_GLOBAL(crit_sprg4) + .space 4 +_GLOBAL(crit_sprg5) + .space 4 +_GLOBAL(crit_sprg7) + .space 4 +_GLOBAL(crit_pid) + .space 4 +_GLOBAL(crit_srr0) + .space 4 +_GLOBAL(crit_srr1) + .space 4 + +/* mcheck_save */ +_GLOBAL(mcheck_save) + .space 4 +_GLOBAL(mcheck_r10) + .space 4 +_GLOBAL(mcheck_r11) + .space 4 +_GLOBAL(mcheck_sprg0) + .space 4 +_GLOBAL(mcheck_sprg1) + .space 4 +_GLOBAL(mcheck_sprg4) + .space 4 +_GLOBAL(mcheck_sprg5) + .space 4 +_GLOBAL(mcheck_sprg7) + .space 4 +_GLOBAL(mcheck_pid) + .space 4 +_GLOBAL(mcheck_srr0) + .space 4 +_GLOBAL(mcheck_srr1) + .space 4 +_GLOBAL(mcheck_csrr0) + .space 4 +_GLOBAL(mcheck_csrr1) + .space 4 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* + * Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 + + diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index c3ed5ed1d..bd006ca95 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1386,7 +1386,7 @@ _GLOBAL(sys_call_table) .long ppc_fadvise64_64 .long sys_ni_syscall /* 255 - rtas (used on ppc64) */ .long sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .long sys_ni_syscall /* 257 reserved for vserver */ + .long sys_vserver .long sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ .long sys_ni_syscall /* 259 reserved for new sys_mbind */ .long sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index eaeb6eb1e..0bcd36a64 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -200,6 +200,15 @@ EXPORT_SYMBOL(last_task_used_altivec); EXPORT_SYMBOL(giveup_altivec); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP +#ifdef CONFIG_DEBUG_SPINLOCK +EXPORT_SYMBOL(_raw_spin_lock); +EXPORT_SYMBOL(_raw_spin_unlock); +EXPORT_SYMBOL(_raw_spin_trylock); +EXPORT_SYMBOL(_raw_read_lock); +EXPORT_SYMBOL(_raw_read_unlock); +EXPORT_SYMBOL(_raw_write_lock); +EXPORT_SYMBOL(_raw_write_unlock); +#endif EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_hw_index); EXPORT_SYMBOL(synchronize_irq); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index b82a2009e..19515a1f9 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -163,7 +163,7 @@ dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) void enable_kernel_altivec(void) { - WARN_ON(preemptible()); + WARN_ON(current_thread_info()->preempt_count == 0 && !irqs_disabled()); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) @@ -180,7 +180,7 @@ EXPORT_SYMBOL(enable_kernel_altivec); void enable_kernel_fp(void) { - WARN_ON(preemptible()); + WARN_ON(current_thread_info()->preempt_count == 0 && !irqs_disabled()); #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 2ddfb1a37..f9120785b 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -197,6 +197,8 @@ int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 7f2531d12..d33e63520 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -229,7 +229,7 @@ int sys_uname(struct old_utsname __user * name) int err = -EFAULT; down_read(&uts_sem); - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, vx_new_utsname(), sizeof (*name))) err = 0; up_read(&uts_sem); return err; @@ -238,6 +238,7 @@ int sys_uname(struct old_utsname __user * name) int sys_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -245,15 +246,16 @@ int sys_olduname(struct oldold_utsname __user * name) return -EFAULT; down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); diff --git a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c deleted file mode 100644 index 2033eec9b..000000000 --- a/arch/ppc/mm/cachemap.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * PowerPC version derived from arch/arm/mm/consistent.c - * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) - * - * arch/ppc/mm/cachemap.c - * - * Copyright (C) 2000 Russell King - * - * Consistent memory allocators. Used for DMA devices that want to - * share uncached memory with the processor core. The function return - * is the virtual address and 'dma_handle' is the physical address. - * Mostly stolen from the ARM port, with some changes for PowerPC. - * -- Dan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int map_page(unsigned long va, phys_addr_t pa, int flags); - -/* This function will allocate the requested contiguous pages and - * map them into the kernel's vmalloc() space. This is done so we - * get unique mapping for these pages, outside of the kernel's 1:1 - * virtual:physical mapping. This is necessary so we can cover large - * portions of the kernel with single large page TLB entries, and - * still get unique uncached pages for consistent DMA. - */ -void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) -{ - int order, err; - struct page *page, *free, *end; - phys_addr_t pa; - unsigned long flags, offset; - struct vm_struct *area = NULL; - unsigned long va = 0; - - BUG_ON(in_interrupt()); - - /* Only allocate page size areas */ - size = PAGE_ALIGN(size); - order = get_order(size); - - free = page = alloc_pages(gfp, order); - if (! page) - return NULL; - - pa = page_to_phys(page); - *dma_handle = page_to_bus(page); - end = page + (1 << order); - - /* - * we need to ensure that there are no cachelines in use, - * or worse dirty in this area. - */ - invalidate_dcache_range((unsigned long)page_address(page), - (unsigned long)page_address(page) + size); - - /* - * alloc_pages() expects the block to be handled as a unit, so - * it only sets the page count on the first page. We set the - * counts on each page so they can be freed individually - */ - for (; page < end; page++) - set_page_count(page, 1); - - - /* Allocate some common virtual space to map the new pages*/ - area = get_vm_area(size, VM_ALLOC); - if (! area) - goto out; - - va = (unsigned long) area->addr; - - flags = _PAGE_KERNEL | _PAGE_NO_CACHE; - - for (offset = 0; offset < size; offset += PAGE_SIZE) { - err = map_page(va+offset, pa+offset, flags); - if (err) { - vfree((void *)va); - va = 0; - goto out; - } - - free++; - } - - out: - /* Free pages which weren't mapped */ - for (; free < end; free++) { - __free_page(free); - } - - return (void *)va; -} - -/* - * free page(s) as defined by the above mapping. - */ -void consistent_free(void *vaddr) -{ - BUG_ON(in_interrupt()); - vfree(vaddr); -} - -/* - * make an area consistent. - */ -void consistent_sync(void *vaddr, size_t size, int direction) -{ - unsigned long start = (unsigned long)vaddr; - unsigned long end = start + size; - - switch (direction) { - case DMA_NONE: - BUG(); - case DMA_FROM_DEVICE: /* invalidate only */ - invalidate_dcache_range(start, end); - break; - case DMA_TO_DEVICE: /* writeback only */ - clean_dcache_range(start, end); - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - flush_dcache_range(start, end); - break; - } -} - -/* - * consistent_sync_page make a page are consistent. identical - * to consistent_sync, but takes a struct page instead of a virtual address - */ - -void consistent_sync_page(struct page *page, unsigned long offset, - size_t size, int direction) -{ - unsigned long start; - - start = (unsigned long)page_address(page) + offset; - consistent_sync((void *)start, size, direction); -} - -EXPORT_SYMBOL(consistent_sync_page); diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c new file mode 100644 index 000000000..baed25b9f --- /dev/null +++ b/arch/ppc/mm/fsl_booke_mmu.c @@ -0,0 +1,236 @@ +/* + * Modifications by Kumar Gala (kumar.gala@freescale.com) to support + * E500 Book E processors. + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This file contains the routines for initializing the MMU + * on the 4xx series of chips. + * -- paulus + * + * Derived from arch/ppc/mm/init.c: + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) + * and Cort Dougan (PReP) (cort@cs.nmt.edu) + * Copyright (C) 1996 Paul Mackerras + * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). + * + * Derived from "arch/i386/mm/init.c" + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void loadcam_entry(unsigned int index); +unsigned int tlbcam_index; +unsigned int num_tlbcam_entries; +static unsigned long __cam0, __cam1, __cam2; +extern unsigned long total_lowmem; +extern unsigned long __max_low_memory; +#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE + +struct tlbcam { + u32 MAS0; + u32 MAS1; + u32 MAS2; + u32 MAS3; + u32 MAS7; +} TLBCAM[NUM_TLBCAMS]; + +struct tlbcamrange { + unsigned long start; + unsigned long limit; + phys_addr_t phys; +} tlbcam_addrs[NUM_TLBCAMS]; + +extern unsigned int tlbcam_index; + +/* + * Return PA for this VA if it is mapped by a CAM, or 0 + */ +unsigned long v_mapped_by_tlbcam(unsigned long va) +{ + int b; + for (b = 0; b < tlbcam_index; ++b) + if (va >= tlbcam_addrs[b].start && va < tlbcam_addrs[b].limit) + return tlbcam_addrs[b].phys + (va - tlbcam_addrs[b].start); + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +unsigned long p_mapped_by_tlbcam(unsigned long pa) +{ + int b; + for (b = 0; b < tlbcam_index; ++b) + if (pa >= tlbcam_addrs[b].phys + && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) + +tlbcam_addrs[b].phys) + return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); + return 0; +} + +/* + * Set up one of the I/D BAT (block address translation) register pairs. + * The parameters are not checked; in particular size must be a power + * of 4 between 4k and 256M. + */ +void settlbcam(int index, unsigned long virt, phys_addr_t phys, + unsigned int size, int flags, unsigned int pid) +{ + unsigned int tsize, lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size)); + tsize = (21 - lz) / 2; + +#ifdef CONFIG_SMP + if ((flags & _PAGE_NO_CACHE) == 0) + flags |= _PAGE_COHERENT; +#endif + + TLBCAM[index].MAS0 = MAS0_TLBSEL | (index << 16); + TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | ((pid << 16) & MAS1_TID); + TLBCAM[index].MAS2 = virt & PAGE_MASK; + + TLBCAM[index].MAS2 |= (flags & _PAGE_WRITETHRU) ? MAS2_W : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_NO_CACHE) ? MAS2_I : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_COHERENT) ? MAS2_M : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; + TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; + + TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); + +#ifndef CONFIG_KGDB /* want user access for breakpoints */ + if (flags & _PAGE_USER) { + TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); + } +#else + TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR; + TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0); +#endif + + tlbcam_addrs[index].start = virt; + tlbcam_addrs[index].limit = virt + size - 1; + tlbcam_addrs[index].phys = phys; + + loadcam_entry(index); +} + +void invalidate_tlbcam_entry(int index) +{ + TLBCAM[index].MAS0 = MAS0_TLBSEL | (index << 16); + TLBCAM[index].MAS1 = ~MAS1_VALID; + + loadcam_entry(index); +} + +void __init cam_mapin_ram(unsigned long cam0, unsigned long cam1, + unsigned long cam2) +{ + settlbcam(0, KERNELBASE, PPC_MEMSTART, cam0, _PAGE_KERNEL, 0); + tlbcam_index++; + if (cam1) { + tlbcam_index++; + settlbcam(1, KERNELBASE+cam0, PPC_MEMSTART+cam0, cam1, _PAGE_KERNEL, 0); + } + if (cam2) { + tlbcam_index++; + settlbcam(2, KERNELBASE+cam0+cam1, PPC_MEMSTART+cam0+cam1, cam2, _PAGE_KERNEL, 0); + } +} + +/* + * MMU_init_hw does the chip-specific initialization of the MMU hardware. + */ +void __init MMU_init_hw(void) +{ + flush_instruction_cache(); +} + +unsigned long __init mmu_mapin_ram(void) +{ + cam_mapin_ram(__cam0, __cam1, __cam2); + + return __cam0 + __cam1 + __cam2; +} + + +void __init +adjust_total_lowmem(void) +{ + unsigned long max_low_mem = MAX_LOW_MEM; + unsigned long cam_max = 0x10000000; + unsigned long ram; + + /* adjust CAM size to max_low_mem */ + if (max_low_mem < cam_max) + cam_max = max_low_mem; + + /* adjust lowmem size to max_low_mem */ + if (max_low_mem < total_lowmem) + ram = max_low_mem; + else + ram = total_lowmem; + + /* Calculate CAM values */ + __cam0 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam0 > cam_max) + __cam0 = cam_max; + ram -= __cam0; + if (ram) { + __cam1 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam1 > cam_max) + __cam1 = cam_max; + ram -= __cam1; + } + if (ram) { + __cam2 = 1UL << 2 * (__ilog2(ram) / 2); + if (__cam2 > cam_max) + __cam2 = cam_max; + ram -= __cam2; + } + + printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb," + " CAM2=%ldMb residual: %ldMb\n", + __cam0 >> 20, __cam1 >> 20, __cam2 >> 20, + (total_lowmem - __cam0 - __cam1 - __cam2) >> 20); + __max_low_memory = max_low_mem = __cam0 + __cam1 + __cam2; +} diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 4628e26ab..5584e1dde 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -642,3 +642,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, } #endif } + +int page_is_ram (unsigned long pagenr) +{ + return 1; +} diff --git a/arch/ppc/ocp/Makefile b/arch/ppc/ocp/Makefile deleted file mode 100644 index f669ee042..000000000 --- a/arch/ppc/ocp/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-y := ocp.o ocp-driver.o ocp-probe.o - diff --git a/arch/ppc/ocp/ocp-driver.c b/arch/ppc/ocp/ocp-driver.c deleted file mode 100644 index 9f6bb3f42..000000000 --- a/arch/ppc/ocp/ocp-driver.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * FILE NAME: ocp-driver.c - * - * BRIEF MODULE DESCRIPTION: - * driver callback, id matching and registration - * Based on drivers/pci/pci-driver, Copyright (c) 1997--1999 Martin Mares - * - * Maintained by: Armin - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -/* - * Registration of OCP drivers and handling of hot-pluggable devices. - */ - -static int -ocp_device_probe(struct device *dev) -{ - int error = 0; - struct ocp_driver *drv; - struct ocp_device *ocp_dev; - - drv = to_ocp_driver(dev->driver); - ocp_dev = to_ocp_dev(dev); - - if (drv->probe) { - error = drv->probe(ocp_dev); - DBG("probe return code %d\n", error); - if (error >= 0) { - ocp_dev->driver = drv; - error = 0; - } - } - return error; -} - -static int -ocp_device_remove(struct device *dev) -{ - struct ocp_device *ocp_dev = to_ocp_dev(dev); - - if (ocp_dev->driver) { - if (ocp_dev->driver->remove) - ocp_dev->driver->remove(ocp_dev); - ocp_dev->driver = NULL; - } - return 0; -} - -static int -ocp_device_suspend(struct device *dev, u32 state, u32 level) -{ - struct ocp_device *ocp_dev = to_ocp_dev(dev); - - int error = 0; - - if (ocp_dev->driver) { - if (level == SUSPEND_SAVE_STATE && ocp_dev->driver->save_state) - error = ocp_dev->driver->save_state(ocp_dev, state); - else if (level == SUSPEND_POWER_DOWN - && ocp_dev->driver->suspend) - error = ocp_dev->driver->suspend(ocp_dev, state); - } - return error; -} - -static int -ocp_device_resume(struct device *dev, u32 level) -{ - struct ocp_device *ocp_dev = to_ocp_dev(dev); - - if (ocp_dev->driver) { - if (level == RESUME_POWER_ON && ocp_dev->driver->resume) - ocp_dev->driver->resume(ocp_dev); - } - return 0; -} - -/** - * ocp_bus_match - Works out whether an OCP device matches any - * of the IDs listed for a given OCP driver. - * @dev: the generic device struct for the OCP device - * @drv: the generic driver struct for the OCP driver - * - * Used by a driver to check whether a OCP device present in the - * system is in its list of supported devices. Returns 1 for a - * match, or 0 if there is no match. - */ -static int -ocp_bus_match(struct device *dev, struct device_driver *drv) -{ - struct ocp_device *ocp_dev = to_ocp_dev(dev); - struct ocp_driver *ocp_drv = to_ocp_driver(drv); - const struct ocp_device_id *ids = ocp_drv->id_table; - - if (!ids) - return 0; - - while (ids->vendor || ids->device) { - if ((ids->vendor == OCP_ANY_ID - || ids->vendor == ocp_dev->vendor) - && (ids->device == OCP_ANY_ID - || ids->device == ocp_dev->device)) { - DBG("Bus match -vendor:%x device:%x\n", ids->vendor, - ids->device); - return 1; - } - ids++; - } - return 0; -} - -struct bus_type ocp_bus_type = { - .name = "ocp", - .match = ocp_bus_match, -}; - -static int __init -ocp_driver_init(void) -{ - return bus_register(&ocp_bus_type); -} - -postcore_initcall(ocp_driver_init); - -/** - * ocp_register_driver - register a new ocp driver - * @drv: the driver structure to register - * - * Adds the driver structure to the list of registered drivers - * Returns the number of ocp devices which were claimed by the driver - * during registration. The driver remains registered even if the - * return value is zero. - */ -int -ocp_register_driver(struct ocp_driver *drv) -{ - int count = 0; - - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &ocp_bus_type; - drv->driver.probe = ocp_device_probe; - drv->driver.resume = ocp_device_resume; - drv->driver.suspend = ocp_device_suspend; - drv->driver.remove = ocp_device_remove; - - /* register with core */ - count = driver_register(&drv->driver); - return count ? count : 1; -} - -/** - * ocp_unregister_driver - unregister a ocp driver - * @drv: the driver structure to unregister - * - * Deletes the driver structure from the list of registered OCP drivers, - * gives it a chance to clean up by calling its remove() function for - * each device it was responsible for, and marks those devices as - * driverless. - */ - -void -ocp_unregister_driver(struct ocp_driver *drv) -{ - driver_unregister(&drv->driver); -} - -EXPORT_SYMBOL(ocp_register_driver); -EXPORT_SYMBOL(ocp_unregister_driver); -EXPORT_SYMBOL(ocp_bus_type); diff --git a/arch/ppc/ocp/ocp-probe.c b/arch/ppc/ocp/ocp-probe.c deleted file mode 100644 index bb4aff7a6..000000000 --- a/arch/ppc/ocp/ocp-probe.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * FILE NAME: ocp-probe.c - * - * BRIEF MODULE DESCRIPTION: - * Device scanning & bus set routines - * Based on drivers/pci/probe, Copyright (c) 1997--1999 Martin Mares - * - * Maintained by: Armin - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -LIST_HEAD(ocp_devices); -struct device *ocp_bus; - -static struct ocp_device * __devinit -ocp_setup_dev(struct ocp_def *odef, unsigned int index) -{ - struct ocp_device *dev; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, sizeof(*dev)); - - dev->vendor = odef->vendor; - dev->device = odef->device; - dev->num = ocp_get_num(dev->device); - dev->paddr = odef->paddr; - dev->irq = odef->irq; - dev->pm = odef->pm; - dev->current_state = 4; - - sprintf(dev->name, "OCP device %04x:%04x", dev->vendor, dev->device); - - DBG("%s %s 0x%lx irq:%d pm:0x%lx \n", dev->slot_name, dev->name, - (unsigned long) dev->paddr, dev->irq, dev->pm); - - /* now put in global tree */ - sprintf(dev->dev.bus_id, "%d", index); - dev->dev.parent = ocp_bus; - dev->dev.bus = &ocp_bus_type; - device_register(&dev->dev); - - return dev; -} - -static struct device * __devinit ocp_alloc_primary_bus(void) -{ - struct device *b; - - b = kmalloc(sizeof(struct device), GFP_KERNEL); - if (b == NULL) - return NULL; - memset(b, 0, sizeof(struct device)); - strcpy(b->bus_id, "ocp"); - - device_register(b); - - return b; -} - -void __devinit ocp_setup_devices(struct ocp_def *odef) -{ - int index; - struct ocp_device *dev; - - if (ocp_bus == NULL) - ocp_bus = ocp_alloc_primary_bus(); - for (index = 0; odef->vendor != OCP_VENDOR_INVALID; ++index, ++odef) { - dev = ocp_setup_dev(odef, index); - if (dev != NULL) - list_add_tail(&dev->global_list, &ocp_devices); - } -} - -extern struct ocp_def core_ocp[]; - -static int __init -ocparch_init(void) -{ - ocp_setup_devices(core_ocp); - return 0; -} - -subsys_initcall(ocparch_init); - -EXPORT_SYMBOL(ocp_devices); diff --git a/arch/ppc/ocp/ocp.c b/arch/ppc/ocp/ocp.c deleted file mode 100644 index 8df60d79f..000000000 --- a/arch/ppc/ocp/ocp.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * ocp.c - * - * The is drived from pci.c - * - * Current Maintainer - * Armin Kuster akuster@dslextreme.com - * Jan, 2002 - * - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * ocp_get_num - This determines how many OCP devices of a given - * device are registered - * @device: OCP device such as HOST, PCI, GPT, UART, OPB, IIC, GPIO, EMAC, ZMII, - * - * The routine returns the number that devices which is registered - */ -unsigned int ocp_get_num(unsigned int device) -{ - unsigned int count = 0; - struct ocp_device *ocp; - struct list_head *ocp_l; - - list_for_each(ocp_l, &ocp_devices) { - ocp = list_entry(ocp_l, struct ocp_device, global_list); - if (device == ocp->device) - count++; - } - return count; -} - -/** - * ocp_get_dev - get ocp driver pointer for ocp device and instance of it - * @device: OCP device such as PCI, GPT, UART, OPB, IIC, GPIO, EMAC, ZMII - * @dev_num: ocp device number whos paddr you want - * - * The routine returns ocp device pointer - * in list based on device and instance of that device - * - */ -struct ocp_device * -ocp_get_dev(unsigned int device, int dev_num) -{ - struct ocp_device *ocp; - struct list_head *ocp_l; - int count = 0; - - list_for_each(ocp_l, &ocp_devices) { - ocp = list_entry(ocp_l, struct ocp_device, global_list); - if (device == ocp->device) { - if (dev_num == count) - return ocp; - count++; - } - } - return NULL; -} - -EXPORT_SYMBOL(ocp_get_dev); -EXPORT_SYMBOL(ocp_get_num); - -#ifdef CONFIG_PM -int ocp_generic_suspend(struct ocp_device *pdev, u32 state) -{ - ocp_force_power_off(pdev); - return 0; -} - -int ocp_generic_resume(struct ocp_device *pdev) -{ - ocp_force_power_on(pdev); -} - -EXPORT_SYMBOL(ocp_generic_suspend); -EXPORT_SYMBOL(ocp_generic_resume); -#endif /* CONFIG_PM */ diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig new file mode 100644 index 000000000..cfe29eb04 --- /dev/null +++ b/arch/ppc/platforms/85xx/Kconfig @@ -0,0 +1,44 @@ +config 85xx + bool + depends on E500 + default y + +config PPC_INDIRECT_PCI_BE + bool + depends on 85xx + default y + +menu "Freescale 85xx options" + depends on E500 + +choice + prompt "Machine Type" + depends on 85xx + default MPC8540_ADS + +config MPC8540_ADS + bool "MPC8540ADS" + help + This option enables support for the MPC 8540 ADS evaluation board. + +endchoice + +# It's often necessary to know the specific 85xx processor type. +# Fortunately, it is implied (so far) from the board type, so we +# don't need to ask more redundant questions. +config MPC8540 + bool + depends on MPC8540_ADS + default y + +config FSL_OCP + bool + depends on 85xx + default y + +config PPC_GEN550 + bool + depends on MPC8540 + default y + +endmenu diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile new file mode 100644 index 000000000..92a88233f --- /dev/null +++ b/arch/ppc/platforms/85xx/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the PowerPC 85xx linux kernel. +# + +obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o + +obj-$(CONFIG_MPC8540) += mpc8540.o diff --git a/arch/ppc/platforms/85xx/mpc8540.c b/arch/ppc/platforms/85xx/mpc8540.c new file mode 100644 index 000000000..f05ef12d2 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8540.c @@ -0,0 +1,97 @@ +/* + * arch/ppc/platforms/85xx/mpc8540.c + * + * MPC8540 I/O descriptions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +/* These should be defined in platform code */ +extern struct ocp_gfar_data mpc85xx_tsec1_def; +extern struct ocp_gfar_data mpc85xx_tsec2_def; +extern struct ocp_gfar_data mpc85xx_fec_def; +extern struct ocp_mpc_i2c_data mpc85xx_i2c1_def; + +/* We use offsets for paddr since we do not know at compile time + * what CCSRBAR is, platform code should fix this up in + * setup_arch + * + * Only the first IRQ is given even if a device has + * multiple lines associated with ita + */ +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = MPC85xx_IIC1_OFFSET, + .irq = MPC85xx_IRQ_IIC1, + .pm = OCP_CPM_NA, + .additions = &mpc85xx_i2c1_def, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = MPC85xx_UART0_OFFSET, + .irq = MPC85xx_IRQ_DUART, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = MPC85xx_UART1_OFFSET, + .irq = MPC85xx_IRQ_DUART, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_GFAR, + .index = 0, + .paddr = MPC85xx_ENET1_OFFSET, + .irq = MPC85xx_IRQ_TSEC1_TX, + .pm = OCP_CPM_NA, + .additions = &mpc85xx_tsec1_def, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_GFAR, + .index = 1, + .paddr = MPC85xx_ENET2_OFFSET, + .irq = MPC85xx_IRQ_TSEC2_TX, + .pm = OCP_CPM_NA, + .additions = &mpc85xx_tsec2_def, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_GFAR, + .index = 2, + .paddr = MPC85xx_ENET3_OFFSET, + .irq = MPC85xx_IRQ_FEC, + .pm = OCP_CPM_NA, + .additions = &mpc85xx_fec_def, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_DMA, + .index = 0, + .paddr = MPC85xx_DMA_OFFSET, + .irq = MPC85xx_IRQ_DMA0, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_PERFMON, + .index = 0, + .paddr = MPC85xx_PERFMON_OFFSET, + .irq = MPC85xx_IRQ_PERFMON, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c new file mode 100644 index 000000000..aada593a6 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -0,0 +1,238 @@ +/* + * arch/ppc/platforms/85xx/mpc8540_ads.c + * + * MPC8540ADS board specific routines + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct ocp_gfar_data mpc85xx_tsec1_def = { + .interruptTransmit = MPC85xx_IRQ_TSEC1_TX, + .interruptError = MPC85xx_IRQ_TSEC1_ERROR, + .interruptReceive = MPC85xx_IRQ_TSEC1_RX, + .interruptPHY = MPC85xx_IRQ_EXT5, + .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR + | GFAR_HAS_RMON + | GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE), + .phyid = 0, + .phyregidx = 0, +}; + +struct ocp_gfar_data mpc85xx_tsec2_def = { + .interruptTransmit = MPC85xx_IRQ_TSEC2_TX, + .interruptError = MPC85xx_IRQ_TSEC2_ERROR, + .interruptReceive = MPC85xx_IRQ_TSEC2_RX, + .interruptPHY = MPC85xx_IRQ_EXT5, + .flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR + | GFAR_HAS_RMON + | GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE), + .phyid = 1, + .phyregidx = 0, +}; + +struct ocp_gfar_data mpc85xx_fec_def = { + .interruptTransmit = MPC85xx_IRQ_FEC, + .interruptError = MPC85xx_IRQ_FEC, + .interruptReceive = MPC85xx_IRQ_FEC, + .interruptPHY = MPC85xx_IRQ_EXT5, + .flags = 0, + .phyid = 3, + .phyregidx = 0, +}; + +struct ocp_fs_i2c_data mpc85xx_i2c1_def = { + .flags = FS_I2C_SEPARATE_DFSRR, +}; + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +mpc8540ads_setup_arch(void) +{ + struct ocp_def *def; + struct ocp_gfar_data *einfo; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("mpc8540ads_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + +#ifdef CONFIG_SERIAL_8250 + mpc85xx_early_serial_map(); +#endif + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Invalidate the entry we stole earlier the serial ports + * should be properly mapped */ + invalidate_tlbcam_entry(NUM_TLBCAMS - 1); +#endif + + def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0); + if (def) { + einfo = (struct ocp_gfar_data *) def->additions; + memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6); + } + + def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1); + if (def) { + einfo = (struct ocp_gfar_data *) def->additions; + memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6); + } + + def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 2); + if (def) { + einfo = (struct ocp_gfar_data *) def->additions; + memcpy(einfo->mac_addr, binfo->bi_enet2addr, 6); + } + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base)); +} + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } +#ifdef CONFIG_SERIAL_TEXT_DEBUG + { + bd_t *binfo = (bd_t *) __res; + + /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ + settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base, + binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); + } +#endif + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = mpc8540ads_setup_arch; + ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo; + + ppc_md.init_IRQ = mpc85xx_ads_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ + + if (ppc_md.progress) + ppc_md.progress("mpc8540ads_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h new file mode 100644 index 000000000..9056361f7 --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc8540_ads.h @@ -0,0 +1,30 @@ +/* + * arch/ppc/platforms/85xx/mpc8540_ads.h + * + * MPC8540ADS board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC8540ADS_H__ +#define __MACH_MPC8540ADS_H__ + +#include +#include +#include +#include +#include + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +#endif /* __MACH_MPC8540ADS_H__ */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c new file mode 100644 index 000000000..7f0fabc5d --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -0,0 +1,237 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_ads_common.c + * + * MPC85xx ADS board common routines + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ + +static u_char mpc85xx_ads_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + 0x0, /* External 0: */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 3 */ +#else + 0x0, /* External 1: */ + 0x0, /* External 2: */ + 0x0, /* External 3: */ + 0x0, /* External 4: */ +#endif + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */ + 0x0, /* External 6: */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */ + 0x0, /* External 8: */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ + 0x0, /* External 11: */ +}; + +/* ************************************************************************ */ +int +mpc85xx_ads_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(PVR); + svid = mfspr(SVR); + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + + switch (svid & 0xffff0000) { + case SVR_8540: + seq_printf(m, "Machine\t\t: mpc8540ads\n"); + break; + case SVR_8560: + seq_printf(m, "Machine\t\t: mpc8560ads\n"); + break; + default: + seq_printf(m, "Machine\t\t: unknown\n"); + break; + } + seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000, + freq % 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +void __init +mpc85xx_ads_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = + binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = mpc85xx_ads_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (mpc85xx_ads_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + /* Map PIC IRQs 0-11 */ + openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + + /* we let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + + return; +} + +#ifdef CONFIG_PCI +/* + * interrupt routing + */ + +int +mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * This is little evil, but works around the fact + * that revA boards have IDSEL starting at 18 + * and others boards (older) start at 12 + * + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 2 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 5 */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 12 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 15 */ + {0, 0, 0, 0}, /* -- */ + {0, 0, 0, 0}, /* -- */ + {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 18 */ + {PIRQD, PIRQA, PIRQB, PIRQC}, + {PIRQC, PIRQD, PIRQA, PIRQB}, + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 21 */ + }; + + const long min_idsel = 2, max_idsel = 21, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +int +mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +#endif /* CONFIG_PCI */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h new file mode 100644 index 000000000..3875e839c --- /dev/null +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h @@ -0,0 +1,50 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_ads_common.h + * + * MPC85XX ADS common board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC85XX_ADS_H__ +#define __MACH_MPC85XX_ADS_H__ + +#include +#include +#include +#include + +#define BOARD_CCSRBAR ((uint)0xe0000000) +#define BCSR_ADDR ((uint)0xf8000000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +extern int mpc85xx_ads_show_cpuinfo(struct seq_file *m); +extern void mpc85xx_ads_init_IRQ(void) __init; +extern void mpc85xx_ads_map_io(void) __init; + +/* PCI interrupt controller */ +#define PIRQA MPC85xx_IRQ_EXT1 +#define PIRQB MPC85xx_IRQ_EXT2 +#define PIRQC MPC85xx_IRQ_EXT3 +#define PIRQD MPC85xx_IRQ_EXT4 + +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +#endif /* __MACH_MPC85XX_ADS_H__ */ diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index f77cdf1d0..626b77acd 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -9,8 +9,8 @@ ifdef CONFIG_4xx EXTRA_AFLAGS := -Wa,-m405 endif -CFLAGS_prom_init.o += -fPIC -CFLAGS_btext.o += -fPIC +CFLAGS_prom_init.o += -mrelocatable-lib +CFLAGS_btext.o += -mrelocatable-lib obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o obj-$(CONFIG_PPC_OCP) += ocp.o @@ -63,7 +63,6 @@ obj-$(CONFIG_PRPMC750) += open_pic.o indirect_pci.o pci_auto.o \ obj-$(CONFIG_HARRIER) += harrier.o obj-$(CONFIG_PRPMC800) += open_pic.o indirect_pci.o pci_auto.o obj-$(CONFIG_SANDPOINT) += i8259.o open_pic.o pci_auto.o todc_time.o -obj-$(CONFIG_SBC82xx) += todc_time.o obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \ todc_time.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o @@ -73,5 +72,3 @@ obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o endif obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o -obj-$(CONFIG_40x) += dcr.o -obj-$(CONFIG_BOOKE) += dcr.o diff --git a/arch/ppc/syslib/ppc85xx_common.c b/arch/ppc/syslib/ppc85xx_common.c new file mode 100644 index 000000000..7de3e4560 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_common.c @@ -0,0 +1,46 @@ +/* + * arch/ppc/syslib/ppc85xx_common.c + * + * MPC85xx support routines + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* ************************************************************************ */ +/* Return the value of CCSRBAR for the current board */ + +phys_addr_t +get_ccsrbar(void) +{ + return BOARD_CCSRBAR; +} + +/* ************************************************************************ */ +/* Update the 85xx OCP tables paddr field */ +void +mpc85xx_update_paddr_ocp(struct ocp_device *dev, void *arg) +{ + phys_addr_t ccsrbar; + if (arg) { + ccsrbar = *(phys_addr_t *)arg; + dev->def->paddr += ccsrbar; + } +} + +EXPORT_SYMBOL(get_ccsrbar); diff --git a/arch/ppc/syslib/ppc85xx_common.h b/arch/ppc/syslib/ppc85xx_common.h new file mode 100644 index 000000000..741e2a955 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_common.h @@ -0,0 +1,29 @@ +/* + * arch/ppc/syslib/ppc85xx_common.h + * + * MPC85xx support routines + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_SYSLIB_PPC85XX_COMMON_H +#define __PPC_SYSLIB_PPC85XX_COMMON_H + +#include +#include +#include + +/* Provide access to ccsrbar for any modules, etc */ +phys_addr_t get_ccsrbar(void); + +/* Update the 85xx OCP tables paddr field */ +void mpc85xx_update_paddr_ocp(struct ocp_device *dev, void *ccsrbar); + +#endif /* __PPC_SYSLIB_PPC85XX_COMMON_H */ diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c new file mode 100644 index 000000000..33aa1dc93 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -0,0 +1,341 @@ +/* + * arch/ppc/syslib/ppc85xx_setup.c + * + * MPC85XX common board code + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Return the amount of memory */ +unsigned long __init +mpc85xx_find_end_of_memory(void) +{ + bd_t *binfo; + + binfo = (bd_t *) __res; + + return binfo->bi_memsize; +} + +/* The decrementer counts at the system (internal) clock freq divided by 8 */ +void __init +mpc85xx_calibrate_decr(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq, divisor; + + /* get the core frequency */ + freq = binfo->bi_busfreq; + + /* The timebase is updated every 8 bus clocks, HID0[SEL_TBCLK] = 0 */ + divisor = 8; + tb_ticks_per_jiffy = freq / divisor / HZ; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +} + +#ifdef CONFIG_SERIAL_8250 +void __init +mpc85xx_early_serial_map(void) +{ + struct uart_port serial_req; + bd_t *binfo = (bd_t *) __res; + phys_addr_t duart_paddr = binfo->bi_immr_base + MPC85xx_UART0_OFFSET; + + /* Setup serial port access */ + memset(&serial_req, 0, sizeof (serial_req)); + serial_req.uartclk = binfo->bi_busfreq; + serial_req.line = 0; + serial_req.irq = MPC85xx_IRQ_DUART; + serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + serial_req.iotype = SERIAL_IO_MEM; + serial_req.membase = ioremap(duart_paddr, MPC85xx_UART0_SIZE); + serial_req.mapbase = duart_paddr; + serial_req.regshift = 0; + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + gen550_init(0, &serial_req); +#endif + + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 0 failed\n"); + + /* Assume early_serial_setup() doesn't modify serial_req */ + duart_paddr = binfo->bi_immr_base + MPC85xx_UART1_OFFSET; + serial_req.line = 1; + serial_req.mapbase = duart_paddr; + serial_req.membase = ioremap(duart_paddr, MPC85xx_UART1_SIZE); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + gen550_init(1, &serial_req); +#endif + + if (early_serial_setup(&serial_req) != 0) + printk("Early serial init of port 1 failed\n"); +} +#endif + +void +mpc85xx_restart(char *cmd) +{ + local_irq_disable(); + abort(); +} + +void +mpc85xx_power_off(void) +{ + local_irq_disable(); + for(;;); +} + +void +mpc85xx_halt(void) +{ + local_irq_disable(); + for(;;); +} + +#ifdef CONFIG_PCI +static void __init +mpc85xx_setup_pci1(struct pci_controller *hose) +{ + volatile struct ccsr_pci *pci; + volatile struct ccsr_guts *guts; + unsigned short temps; + bd_t *binfo = (bd_t *) __res; + + pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI1_OFFSET, + MPC85xx_PCI1_SIZE); + + guts = ioremap(binfo->bi_immr_base + MPC85xx_GUTS_OFFSET, + MPC85xx_GUTS_SIZE); + + early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps); + temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + early_write_config_word(hose, 0, 0, PCI_COMMAND, temps); + +#define PORDEVSR_PCI (0x00800000) /* PCI Mode */ + if (guts->pordevsr & PORDEVSR_PCI) { + early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); + } else { + /* PCI-X init */ + temps = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ + | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E; + early_write_config_word(hose, 0, 0, PCIX_COMMAND, temps); + } + + /* Disable all windows (except powar0 since its ignored) */ + pci->powar1 = 0; + pci->powar2 = 0; + pci->powar3 = 0; + pci->powar4 = 0; + pci->piwar1 = 0; + pci->piwar2 = 0; + pci->piwar3 = 0; + + /* Setup 512M Phys:PCI 1:1 outbound mem window @ 0x80000000 */ + pci->potar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff; + pci->potear1 = 0x00000000; + pci->powbar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff; + pci->powar1 = 0x8004401c; /* Enable, Mem R/W, 512M */ + + /* Setup 16M outboud IO windows @ 0xe2000000 */ + pci->potar2 = 0x00000000; + pci->potear2 = 0x00000000; + pci->powbar2 = (MPC85XX_PCI1_IO_BASE >> 12) & 0x000fffff; + pci->powar2 = 0x80088017; /* Enable, IO R/W, 16M */ + + /* Setup 2G inbound Memory Window @ 0 */ + pci->pitar1 = 0x00000000; + pci->piwbar1 = 0x00000000; + pci->piwar1 = 0xa0f5501e; /* Enable, Prefetch, Local + Mem, Snoop R/W, 2G */ +} + + +extern int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin); +extern int mpc85xx_exclude_device(u_char bus, u_char devfn); + +#if CONFIG_85xx_PCI2 +static void __init +mpc85xx_setup_pci2(struct pci_controller *hose) +{ + volatile struct ccsr_pci *pci; + unsigned short temps; + bd_t *binfo = (bd_t *) __res; + + pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI2_OFFSET, + MPC85xx_PCI2_SIZE); + + early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps); + temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + early_write_config_word(hose, 0, 0, PCI_COMMAND, temps); + early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); + + /* Disable all windows (except powar0 since its ignored) */ + pci->powar1 = 0; + pci->powar2 = 0; + pci->powar3 = 0; + pci->powar4 = 0; + pci->piwar1 = 0; + pci->piwar2 = 0; + pci->piwar3 = 0; + + /* Setup 512M Phys:PCI 1:1 outbound mem window @ 0xa0000000 */ + pci->potar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff; + pci->potear1 = 0x00000000; + pci->powbar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff; + pci->powar1 = 0x8004401c; /* Enable, Mem R/W, 512M */ + + /* Setup 16M outboud IO windows @ 0xe3000000 */ + pci->potar2 = 0x00000000; + pci->potear2 = 0x00000000; + pci->powbar2 = (MPC85XX_PCI2_IO_BASE >> 12) & 0x000fffff; + pci->powar2 = 0x80088017; /* Enable, IO R/W, 16M */ + + /* Setup 2G inbound Memory Window @ 0 */ + pci->pitar1 = 0x00000000; + pci->piwbar1 = 0x00000000; + pci->piwar1 = 0xa0f5501e; /* Enable, Prefetch, Local + Mem, Snoop R/W, 2G */ +} +#endif /* CONFIG_85xx_PCI2 */ + +void __init +mpc85xx_setup_hose(void) +{ + struct pci_controller *hose_a; +#ifdef CONFIG_85xx_PCI2 + struct pci_controller *hose_b; +#endif + bd_t *binfo = (bd_t *) __res; + + hose_a = pcibios_alloc_controller(); + + if (!hose_a) + return; + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mpc85xx_map_irq; + + hose_a->first_busno = 0; + hose_a->bus_offset = 0; + hose_a->last_busno = 0xff; + + setup_indirect_pci(hose_a, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET, + binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET); + hose_a->set_cfg_type = 1; + + mpc85xx_setup_pci1(hose_a); + + hose_a->pci_mem_offset = MPC85XX_PCI1_MEM_OFFSET; + hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM; + hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM; + + hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO; + hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO; + hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE; +#if CONFIG_85xx_PCI2 + isa_io_base = + (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, + MPC85XX_PCI1_IO_SIZE + + MPC85XX_PCI2_IO_SIZE); +#else + isa_io_base = + (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE, + MPC85XX_PCI1_IO_SIZE); +#endif + hose_a->io_base_virt = (void *) isa_io_base; + + /* setup resources */ + pci_init_resource(&hose_a->mem_resources[0], + MPC85XX_PCI1_LOWER_MEM, + MPC85XX_PCI1_UPPER_MEM, + IORESOURCE_MEM, "PCI1 host bridge"); + + pci_init_resource(&hose_a->io_resource, + MPC85XX_PCI1_LOWER_IO, + MPC85XX_PCI1_UPPER_IO, + IORESOURCE_IO, "PCI1 host bridge"); + + ppc_md.pci_exclude_device = mpc85xx_exclude_device; + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + +#if CONFIG_85xx_PCI2 + hose_b = pcibios_alloc_controller(); + + if (!hose_b) + return; + + hose_b->bus_offset = hose_a->last_busno + 1; + hose_b->first_busno = hose_a->last_busno + 1; + hose_b->last_busno = 0xff; + + setup_indirect_pci(hose_b, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET, + binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET); + hose_b->set_cfg_type = 1; + + mpc85xx_setup_pci2(hose_b); + + hose_b->pci_mem_offset = MPC85XX_PCI2_MEM_OFFSET; + hose_b->mem_space.start = MPC85XX_PCI2_LOWER_MEM; + hose_b->mem_space.end = MPC85XX_PCI2_UPPER_MEM; + + hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO; + hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO; + hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE; + hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE; + + /* setup resources */ + pci_init_resource(&hose_b->mem_resources[0], + MPC85XX_PCI2_LOWER_MEM, + MPC85XX_PCI2_UPPER_MEM, + IORESOURCE_MEM, "PCI2 host bridge"); + + pci_init_resource(&hose_b->io_resource, + MPC85XX_PCI2_LOWER_IO, + MPC85XX_PCI2_UPPER_IO, + IORESOURCE_IO, "PCI2 host bridge"); + + hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno); +#endif + return; +} +#endif /* CONFIG_PCI */ + + diff --git a/arch/ppc/syslib/ppc85xx_setup.h b/arch/ppc/syslib/ppc85xx_setup.h new file mode 100644 index 000000000..311b8a418 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_setup.h @@ -0,0 +1,67 @@ +/* + * arch/ppc/syslib/ppc85xx_setup.h + * + * MPC85XX common board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __PPC_SYSLIB_PPC85XX_SETUP_H +#define __PPC_SYSLIB_PPC85XX_SETUP_H + +#include +#include +#include +#include + +extern unsigned long mpc85xx_find_end_of_memory(void) __init; +extern void mpc85xx_calibrate_decr(void) __init; +extern void mpc85xx_early_serial_map(void) __init; +extern void mpc85xx_restart(char *cmd); +extern void mpc85xx_power_off(void); +extern void mpc85xx_halt(void); +extern void mpc85xx_setup_hose(void) __init; + +/* PCI config */ +#define PCI1_CFG_ADDR_OFFSET (0x8000) +#define PCI1_CFG_DATA_OFFSET (0x8004) + +#define PCI2_CFG_ADDR_OFFSET (0x9000) +#define PCI2_CFG_DATA_OFFSET (0x9004) + +/* Additional register for PCI-X configuration */ +#define PCIX_NEXT_CAP 0x60 +#define PCIX_CAP_ID 0x61 +#define PCIX_COMMAND 0x62 +#define PCIX_STATUS 0x64 + +/* Serial Config */ +#define MPC85XX_0_SERIAL (CCSRBAR + 0x4500) +#define MPC85XX_1_SERIAL (CCSRBAR + 0x4600) + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 2 +#endif + +#define BASE_BAUD 0 + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, num, MPC85xx_IRQ_DUART, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)MPC85XX_##num##_SERIAL, \ + io_type: SERIAL_IO_MEM}, + +/* Offset of CPM register space */ +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) + +#endif /* __PPC_SYSLIB_PPC85XX_SETUP_H */ diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index f0a6ef197..8d5e077fd 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -437,6 +437,8 @@ config SPINLINE If in doubt, say N. +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 10c1d6299..00ffc9ffe 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -17,7 +17,7 @@ KERNELLOAD := 0xc000000000000000 HAS_BIARCH := $(shell if $(CC) -m64 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi;) ifeq ($(HAS_BIARCH),y) -AS := $(AS) -a64 +AS := $(AS) -64 LD := $(LD) -m elf64ppc CC := $(CC) -m64 endif @@ -48,6 +48,8 @@ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/ppc64/oprofile/ boot := arch/ppc64/boot +bzImage: vmlinux + cp vmlinux arch/ppc64/boot/bzImage boottarget-$(CONFIG_PPC_PSERIES) := zImage zImage.initrd boottarget-$(CONFIG_PPC_ISERIES) := vmlinux.sminitrd vmlinux.initrd vmlinux.sm diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index e868fe7b8..6b22a87d9 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -926,8 +926,8 @@ _GLOBAL(do_hash_page_DSI) stb r0,PACAPROCENABLED(r20) /* Soft Disabled */ mfmsr r0 - ori r0,r0,MSR_EE - mtmsrd r0,1 /* Hard Enable */ + ori r0,r0,MSR_EE+MSR_RI + mtmsrd r0 /* Hard Enable, RI on */ #endif /* @@ -946,9 +946,9 @@ _GLOBAL(do_hash_page_DSI) */ mfmsr r0 li r4,0 - ori r4,r4,MSR_EE + ori r4,r4,MSR_EE+MSR_RI andc r0,r0,r4 - mtmsrd r0,1 /* Hard Disable */ + mtmsrd r0 /* Hard Disable, RI off */ ld r0,SOFTE(r1) cmpdi 0,r0,0 /* See if we will soft enable in */ diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 9f784fb56..5a6064a2d 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -831,7 +831,15 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_sched_setaffinity .llong .compat_sys_sched_getaffinity .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ +#ifdef CONFIG_TUX + .llong .__sys_tux +#else +# ifdef CONFIG_TUX_MODULE + .llong .sys_tux +# else + .llong .sys_ni_syscall +# endif +#endif .llong .sys32_sendfile64 .llong .compat_sys_io_setup .llong .sys_io_destroy @@ -863,7 +871,7 @@ _GLOBAL(sys_call_table32) .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ .llong .ppc_rtas /* 255 */ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ + .llong .sys_vserver .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ .llong .sys_ni_syscall /* 259 reserved for new sys_mbind */ .llong .sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ @@ -1103,7 +1111,15 @@ _GLOBAL(sys_call_table) .llong .sys_sched_setaffinity .llong .sys_sched_getaffinity .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ +#ifdef CONFIG_TUX + .llong .__sys_tux +#else +# ifdef CONFIG_TUX_MODULE + .llong .sys_tux +# else + .llong .sys_ni_syscall +# endif +#endif .llong .sys_ni_syscall /* 32bit only sendfile64 */ .llong .sys_io_setup .llong .sys_io_destroy diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index efc9dbd3b..5ff2b1c90 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -76,6 +76,8 @@ int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c index ff59b0057..603c9db19 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/ppc64/kernel/rtas.c @@ -58,6 +58,8 @@ struct rtas_t rtas = { .lock = SPIN_LOCK_UNLOCKED }; +EXPORT_SYMBOL_GPL(rtas); + char rtas_err_buf[RTAS_ERROR_LOG_MAX]; extern unsigned long reloc_offset(void); diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 7fa0e5a10..ae52b2050 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -390,7 +390,8 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) } /* Fixup atomic count: it exited inside IRQ handler. */ - paca[lcpu].xCurrent->thread_info->preempt_count = 0; + ((struct task_struct *)paca[lcpu].xCurrent)->thread_info->preempt_count + = 0; /* Fixup SLB round-robin so next segment (kernel) goes in segment 0 */ paca[lcpu].xStab_data.next_round_robin = 0; @@ -753,6 +754,8 @@ out: return ret; } +EXPORT_SYMBOL_GPL(smp_call_function); + void smp_call_function_interrupt(void) { void (*func) (void *info); @@ -816,7 +819,7 @@ static void __init smp_create_idle(unsigned int cpu) init_idle(p, cpu); unhash_process(p); - paca[cpu].xCurrent = p; + paca[cpu].xCurrent = (u64)p; current_set[cpu] = p->thread_info; } @@ -868,7 +871,7 @@ void __devinit smp_prepare_boot_cpu(void) /* cpu_possible is set up in prom.c */ cpu_set(boot_cpuid, cpu_online_map); - paca[boot_cpuid].xCurrent = current; + paca[boot_cpuid].xCurrent = (u64)current; current_set[boot_cpuid] = current->thread_info; } @@ -911,20 +914,8 @@ int __devinit __cpu_up(unsigned int cpu) * use this value that I found through experimentation. * -- Cort */ - if (system_state == SYSTEM_BOOTING) - for (c = 5000; c && !cpu_callin_map[cpu]; c--) - udelay(100); -#ifdef CONFIG_HOTPLUG_CPU - else - /* - * CPUs can take much longer to come up in the - * hotplug case. Wait five seconds. - */ - for (c = 25; c && !cpu_callin_map[cpu]; c--) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/5); - } -#endif + for (c = 5000; c && !cpu_callin_map[cpu]; c--) + udelay(100); if (!cpu_callin_map[cpu]) { printk("Processor %u is stuck.\n", cpu); diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index ca8014224..ddd1cb7c6 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -1158,6 +1158,7 @@ asmlinkage long sys32_time(compat_time_t __user * tloc) asmlinkage int sys32_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -1165,15 +1166,16 @@ asmlinkage int sys32_olduname(struct oldold_utsname __user * name) return -EFAULT; down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index dcb1097ce..244550256 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -172,6 +173,8 @@ void ppc64_enable_pmcs(void) } #endif +EXPORT_SYMBOL_GPL(ppc64_enable_pmcs); + /* XXX convert to rusty's on_one_cpu */ static unsigned long run_on_cpu(unsigned long cpu, unsigned long (*func)(unsigned long), diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index c941b796a..7c1594d0c 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -466,18 +466,6 @@ SingleStepException(struct pt_regs *regs) _exception(SIGTRAP, &info, regs); } -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static inline void emulate_single_step(struct pt_regs *regs) -{ - if (regs->msr & MSR_SE) - SingleStepException(regs); -} - static void dummy_perf(struct pt_regs *regs) { } @@ -499,8 +487,10 @@ AlignmentException(struct pt_regs *regs) fixed = fix_alignment(regs); if (fixed == 1) { + if (!user_mode(regs)) + PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lx\n", + regs->nip); regs->nip += 4; /* skip over emulated instruction */ - emulate_single_step(regs); return; } diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c index 78b05df91..ce758a3c6 100644 --- a/arch/ppc64/kernel/vio.c +++ b/arch/ppc64/kernel/vio.c @@ -32,9 +32,7 @@ extern struct subsystem devices_subsys; /* needed for vio_find_name() */ -static struct iommu_table *vio_build_iommu_table(struct vio_dev *); -static const struct vio_device_id *vio_match_device( - const struct vio_device_id *, const struct vio_dev *); +struct iommu_table *vio_build_iommu_table(struct vio_dev *dev); #ifdef CONFIG_PPC_PSERIES static int vio_num_address_cells; @@ -138,15 +136,15 @@ EXPORT_SYMBOL(vio_unregister_driver); * system is in its list of supported devices. Returns the matching * vio_device_id structure or NULL if there is no match. */ -static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, +const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, const struct vio_dev *dev) { DBGENTER(); #ifdef CONFIG_PPC_PSERIES while (ids->type) { - if ((strncmp(((struct device_node *)dev->dev.platform_data)->type, ids->type, strlen(ids->type)) == 0) && - device_is_compatible(dev->dev.platform_data, ids->compat)) + if ((strncmp(dev->archdata->type, ids->type, strlen(ids->type)) == 0) && + device_is_compatible((struct device_node*)dev->archdata, ids->compat)) return ids; ids++; } @@ -265,13 +263,14 @@ static void __devinit vio_dev_release(struct device *dev) DBGENTER(); /* XXX free TCE table */ - of_node_put(viodev->dev.platform_data); + of_node_put(viodev->archdata); kfree(viodev); } static ssize_t viodev_show_devspec(struct device *dev, char *buf) { - struct device_node *of_node = dev->platform_data; + struct vio_dev *viodev = to_vio_dev(dev); + struct device_node *of_node = viodev->archdata; return sprintf(buf, "%s\n", of_node->full_name); } @@ -279,7 +278,8 @@ DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); static ssize_t viodev_show_name(struct device *dev, char *buf) { - struct device_node *of_node = dev->platform_data; + struct vio_dev *viodev = to_vio_dev(dev); + struct device_node *of_node = viodev->archdata; return sprintf(buf, "%s\n", of_node->name); } @@ -290,7 +290,7 @@ DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); * @of_node: The OF node for this device. * * Creates and initializes a vio_dev structure from the data in - * of_node (dev.platform_data) and adds it to the list of virtual devices. + * of_node (archdata) and adds it to the list of virtual devices. * Returns a pointer to the created vio_dev or NULL if node has * NULL device_type or compatible fields. */ @@ -324,7 +324,7 @@ struct vio_dev * __devinit vio_register_device(struct device_node *of_node) } memset(viodev, 0, sizeof(struct vio_dev)); - viodev->dev.platform_data = of_node_get(of_node); + viodev->archdata = (void *)of_node_get(of_node); viodev->unit_address = *unit_address; viodev->iommu_table = vio_build_iommu_table(viodev); @@ -380,7 +380,7 @@ EXPORT_SYMBOL(vio_unregister_device); */ const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) { - return get_property(vdev->dev.platform_data, (char*)which, length); + return get_property((struct device_node *)vdev->archdata, (char*)which, length); } EXPORT_SYMBOL(vio_get_attribute); @@ -427,7 +427,7 @@ EXPORT_SYMBOL(vio_find_node); * Returns a pointer to the built tce tree, or NULL if it can't * find property. */ -static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev) +struct iommu_table * vio_build_iommu_table(struct vio_dev *dev) { unsigned int *dma_window; struct iommu_table *newTceTable; @@ -435,7 +435,7 @@ static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev) unsigned long size; int dma_window_property_size; - dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); + dma_window = (unsigned int *) get_property((struct device_node *)dev->archdata, "ibm,my-dma-window", &dma_window_property_size); if(!dma_window) { return NULL; } diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index 3fbdd00d3..f0cb2d70a 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -191,6 +191,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) { char *buf; u16 vlanMap; + int vlanIndex; dma_addr_t handle; HvLpEvent_Rc hvrc; DECLARE_MUTEX_LOCKED(Semaphore); @@ -218,10 +219,17 @@ static int proc_viopath_show(struct seq_file *m, void *v) down(&Semaphore); vlanMap = HvLpConfig_getVirtualLanIndexMap(); + vlanIndex = 0; + while (vlanMap != 0){ + if (vlanMap & 0x8000) + vlanIndex++;; + vlanMap = vlanMap << 1; + } buf[PAGE_SIZE-1] = '\0'; seq_printf(m, "%s", buf); - seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); + + seq_printf(m, "AVAILABLE_VETH=%d\n", vlanIndex ); seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n", e2a(xItExtVpdPanel.mfgID[2]), e2a(xItExtVpdPanel.mfgID[3]), diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index d660b0d28..9416e53df 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -125,7 +125,8 @@ static void setup_huge_pte(struct mm_struct *mm, struct page *page, hugepte_t entry; int i; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + // mm->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_sub(mm, HPAGE_SIZE / PAGE_SIZE); entry = mk_hugepte(page, write_access); for (i = 0; i < HUGEPTE_BATCH_SIZE; i++) set_hugepte(ptep+i, entry); @@ -287,7 +288,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, /* This is the first hugepte in a batch */ ptepage = hugepte_page(entry); get_page(ptepage); - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + // dst->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(dst, HPAGE_SIZE / PAGE_SIZE); } set_hugepte(dst_pte, entry); @@ -407,7 +409,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, put_page(page); } - mm->rss -= (end - start) >> PAGE_SHIFT; + // mm->rss -= (end - start) >> PAGE_SHIFT; + vx_rsspages_sub(mm, (end - start) >> PAGE_SHIFT); } int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index eab5d1e96..c0b72b438 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -425,6 +425,8 @@ config DEBUG_SPINLOCK_SLEEP endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 68c1a72b0..df7c55fc7 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -57,6 +57,11 @@ boot := arch/$(ARCH)/boot all: image +# This is a white lie which helps to keep our spec simpler. +# No $(Q) or other trickery because nobody should use it outside of RPM builds. +bzImage: image + ln -s image arch/$(ARCH)/boot/bzImage + install: vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ diff --git a/arch/s390/defconfig b/arch/s390/defconfig index c694ae543..3fb822396 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -28,7 +28,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -113,6 +112,7 @@ CONFIG_CHR_DEV_SG=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_REPORT_LUNS is not set CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y @@ -126,7 +126,6 @@ CONFIG_SCSI_LOGGING=y # SCSI low-level drivers # # CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_DEBUG is not set @@ -311,7 +310,11 @@ CONFIG_NET_ETHERNET=y # CONFIG_MII is not set # -# Gigabit Ethernet (1000/10000 Mbit) +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) # # diff --git a/arch/s390/kernel/compat_exec.c b/arch/s390/kernel/compat_exec.c index 595c43a89..3e781bd77 100644 --- a/arch/s390/kernel/compat_exec.c +++ b/arch/s390/kernel/compat_exec.c @@ -36,7 +36,7 @@ int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack) { - unsigned long stack_base; + unsigned long stack_base, grow; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i; @@ -53,7 +53,10 @@ int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack) if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + grow = (STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p)) + >> PAGE_SHIFT; + if (security_vm_enough_memory(grow) || + !vx_vmpages_avail(mm, grow)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -69,7 +72,9 @@ int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + // mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + vx_vmpages_sub(mm, mm->total_vm - + ((mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 41adc6120..a0c43663e 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1097,8 +1097,6 @@ compat_sys_futex_wrapper: lgfr %r4,%r4 # int llgtr %r5,%r5 # struct compat_timespec * llgtr %r6,%r6 # u32 * - lgf %r0,164(%r15) # int - stg %r0,160(%r15) jg compat_sys_futex # branch to system call .globl sys32_setxattr_wrapper diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f716b41f0..4cce894cc 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -24,8 +24,7 @@ * Stack layout for the system_call stack entry. * The first few entries are identical to the user_regs_struct. */ -SP_PTREGS = STACK_FRAME_OVERHEAD -SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS +SP_PTREGS = STACK_FRAME_OVERHEAD SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4 @@ -48,8 +47,7 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_RESTART_SVC) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) #define BASED(name) name-system_call(%r13) @@ -231,16 +229,13 @@ system_call: lh %r7,0x8a # get svc number from lowcore sysc_enter: GET_THREAD_INFO # load pointer to task_struct to R9 -sysc_do_svc: sla %r7,2 # *4 and test for svc 0 - bnz BASED(sysc_nr_ok) # svc number > 0 + bnz BASED(sysc_do_restart) # svc number > 0 # svc 0: system call number in %r1 cl %r1,BASED(.Lnr_syscalls) - bnl BASED(sysc_nr_ok) + bnl BASED(sysc_do_restart) lr %r7,%r1 # copy svc number to %r7 sla %r7,2 # *4 -sysc_nr_ok: - mvc SP_ARGS(4,%r15),SP_R7(%r15) sysc_do_restart: tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr. @@ -267,6 +262,7 @@ sysc_work_loop: bz BASED(sysc_leave) # there is no work to do # # One of the work bits is on. Find out which one. +# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED # sysc_work: tm __TI_flags+3(%r9),_TIF_NEED_RESCHED @@ -275,8 +271,6 @@ sysc_work: bo BASED(sysc_sigpending) tm __TI_flags+3(%r9),_TIF_RESTART_SVC bo BASED(sysc_restart) - tm __TI_flags+3(%r9),_TIF_SINGLE_STEP - bo BASED(sysc_singlestep) b BASED(sysc_leave) # @@ -310,17 +304,6 @@ sysc_restart: lm %r2,%r6,SP_R2(%r15) # load svc arguments b BASED(sysc_do_restart) # restart svc -# -# _TIF_SINGLE_STEP is set, call do_debugger_trap -# -sysc_singlestep: - ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP - mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check - la %r2,SP_PTREGS(%r15) # address of register-save area - l %r1,BASED(.Lhandle_per) # load adr. of per handler - la %r14,BASED(sysc_return) # load adr. of system return - br %r1 # branch to do_debugger_trap - __critical_end: # @@ -512,15 +495,71 @@ pgm_per_only: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 - lh %r7,0x8a # get svc number from lowcore - GET_THREAD_INFO # load pointer to task_struct to R9 + lh %r7,0x8a # get svc number from lowcore + GET_THREAD_INFO # load pointer to task_struct to R9 l %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID - oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 24(%r15),0x03 # reenable interrupts - b BASED(sysc_do_svc) + stosm 24(%r15),0x03 # reenable interrupts + sla %r7,2 # *4 and test for svc 0 + bnz BASED(pgm_svcstd) # svc number > 0 ? + # svc 0: system call number in %r1 + cl %r1,BASED(.Lnr_syscalls) + bnl BASED(pgm_svcstd) + lr %r7,%r1 # copy svc number to %r7 + sla %r7,2 # *4 +pgm_svcstd: + tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) + l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr. + bnz BASED(pgm_tracesys) + basr %r14,%r8 # call sys_xxxx + st %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! + +pgm_svcret: + tm __TI_flags+3(%r9),_TIF_SIGPENDING + bno BASED(pgm_svcper_nosig) + la %r2,SP_PTREGS(%r15) # load pt_regs + sr %r3,%r3 # clear *oldset + l %r1,BASED(.Ldo_signal) + basr %r14,%r1 # call do_signal + +pgm_svcper_nosig: + mvi SP_TRAP+3(%r15),0x28 # set trap indication to pgm check + la %r2,SP_PTREGS(15) # address of register-save area + l %r1,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_return) # load adr. of system return + br %r1 # branch to do_debugger_trap +# +# call trace before and after sys_call +# +pgm_tracesys: + l %r1,BASED(.Ltrace) + la %r2,SP_PTREGS(%r15) # load pt_regs + la %r3,0 + srl %r7,2 + st %r7,SP_R2(%r15) + basr %r14,%r1 + clc SP_R2(4,%r15),BASED(.Lnr_syscalls) + bnl BASED(pgm_svc_nogo) + l %r7,SP_R2(%r15) # strace changed the syscall + sll %r7,2 + l %r8,sys_call_table-system_call(%r7,%r13) +pgm_svc_go: + lm %r3,%r6,SP_R3(%r15) + l %r2,SP_ORIG_R2(%r15) + basr %r14,%r8 # call sys_xxx + st %r2,SP_R2(%r15) # store return value +pgm_svc_nogo: + tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) + bz BASED(pgm_svcret) + l %r1,BASED(.Ltrace) + la %r2,SP_PTREGS(%r15) # load pt_regs + la %r3,1 + la %r14,BASED(pgm_svcret) + br %r1 /* * IO interrupt handler routine diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 533fa85ce..85a9876f7 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -24,8 +24,7 @@ * Stack layout for the system_call stack entry. * The first few entries are identical to the user_regs_struct. */ -SP_PTREGS = STACK_FRAME_OVERHEAD -SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS +SP_PTREGS = STACK_FRAME_OVERHEAD SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 @@ -48,8 +47,7 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_RESTART_SVC) _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) /* @@ -215,17 +213,14 @@ system_call: llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore sysc_enter: GET_THREAD_INFO # load pointer to task_struct to R9 -sysc_do_svc: slag %r7,%r7,2 # *4 and test for svc 0 - jnz sysc_nr_ok + jnz sysc_do_restart # svc 0: system call number in %r1 lghi %r0,NR_syscalls clr %r1,%r0 - jnl sysc_nr_ok + jnl sysc_do_restart lgfr %r7,%r1 # clear high word in r1 slag %r7,%r7,2 # svc 0: system call number in %r1 -sysc_nr_ok: - mvc SP_ARGS(8,%r15),SP_R7(%r15) sysc_do_restart: larl %r10,sys_call_table #ifdef CONFIG_S390_SUPPORT @@ -259,6 +254,7 @@ sysc_work_loop: jz sysc_leave # there is no work to do # # One of the work bits is on. Find out which one. +# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED # sysc_work: tm __TI_flags+7(%r9),_TIF_NEED_RESCHED @@ -267,8 +263,6 @@ sysc_work: jo sysc_sigpending tm __TI_flags+7(%r9),_TIF_RESTART_SVC jo sysc_restart - tm __TI_flags+7(%r9),_TIF_SINGLE_STEP - jo sysc_singlestep j sysc_leave # @@ -300,17 +294,6 @@ sysc_restart: lmg %r2,%r6,SP_R2(%r15) # load svc arguments j sysc_do_restart # restart svc -# -# _TIF_SINGLE_STEP is set, call do_debugger_trap -# -sysc_singlestep: - ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP - mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check - la %r2,SP_PTREGS(%r15) # address of register-save area - larl %r14,sysc_return # load adr. of system return - jg do_debugger_trap # branch to do_debugger_trap - - __critical_end: # @@ -545,15 +528,75 @@ pgm_per_only: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 - llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore - GET_THREAD_INFO # load pointer to task_struct to R9 + llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore + GET_THREAD_INFO # load pointer to task_struct to R9 lg %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID - oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - stosm 48(%r15),0x03 # reenable interrupts - j sysc_do_svc + stosm 48(%r15),0x03 # reenable interrupts + slag %r7,%r7,2 # *4 and test for svc 0 + jnz pgm_svcstd + # svc 0: system call number in %r1 + lghi %r0,NR_syscalls + clr %r1,%r0 + slag %r7,%r1,2 +pgm_svcstd: + larl %r10,sys_call_table +#ifdef CONFIG_S390_SUPPORT + tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? + jo pgm_svcper_noemu + larl %r10,sys_call_table_emu # use 31 bit emulation system calls +pgm_svcper_noemu: +#endif + tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) + lgf %r8,0(%r7,%r10) # load address of system call routine + jnz pgm_tracesys + basr %r14,%r8 # call sys_xxxx + stg %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! + +pgm_svcret: + tm __TI_flags+7(%r9),_TIF_SIGPENDING + jno pgm_svcper_nosig + la %r2,SP_PTREGS(%r15) # load pt_regs + sgr %r3,%r3 # clear *oldset + brasl %r14,do_signal + +pgm_svcper_nosig: + lhi %r0,__LC_PGM_OLD_PSW # set trap indication back to pgm_chk + st %r0,SP_TRAP(%r15) + la %r2,SP_PTREGS(15) # address of register-save area + larl %r14,sysc_return # load adr. of system return + jg do_debugger_trap +# +# call trace before and after sys_call +# +pgm_tracesys: + la %r2,SP_PTREGS(%r15) # load pt_regs + la %r3,0 + srlg %r7,%r7,2 + stg %r7,SP_R2(%r15) + brasl %r14,syscall_trace + lghi %r0,NR_syscalls + clg %r0,SP_R2(%r15) + jnh pgm_svc_nogo + lg %r7,SP_R2(%r15) + sllg %r7,%r7,2 # strace wants to change the syscall + lgf %r8,0(%r7,%r10) +pgm_svc_go: + lmg %r3,%r6,SP_R3(%r15) + lg %r2,SP_ORIG_R2(%r15) + basr %r14,%r8 # call sys_xxx + stg %r2,SP_R2(%r15) # store return value +pgm_svc_nogo: + tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) + jz pgm_svcret + la %r2,SP_PTREGS(%r15) # load pt_regs + la %r3,1 + larl %r14,pgm_svcret # return point is sysc_return + jg syscall_trace /* * IO interrupt handler routine diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 63818a50e..a18d5f444 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include @@ -293,12 +292,12 @@ asmlinkage long sys_clone(struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; + int *parent_tidptr, *child_tidptr; clone_flags = regs.gprs[3]; newsp = regs.orig_gpr2; - parent_tidptr = (int __user *) regs.gprs[4]; - child_tidptr = (int __user *) regs.gprs[5]; + parent_tidptr = (int *) regs.gprs[4]; + child_tidptr = (int *) regs.gprs[5]; if (!newsp) newsp = regs.gprs[15]; return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, @@ -329,12 +328,12 @@ asmlinkage long sys_execve(struct pt_regs regs) int error; char * filename; - filename = getname((char __user *) regs.orig_gpr2); + filename = getname((char *) regs.orig_gpr2); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user * __user *) regs.gprs[3], - (char __user * __user *) regs.gprs[4], ®s); + error = do_execve(filename, (char **) regs.gprs[3], + (char **) regs.gprs[4], ®s); if (error == 0) { current->ptrace &= ~PT_DTRACE; current->thread.fp_regs.fpc = 0; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index a0ddc4f7d..fa7875fba 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -141,7 +141,7 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) /* * psw and gprs are stored on the stack */ - tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr); + tmp = *(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr); if (addr == (addr_t) &dummy->regs.psw.mask) /* Remove per bit from user psw. */ tmp &= ~PSW_MASK_PER; @@ -176,7 +176,7 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) } else tmp = 0; - return put_user(tmp, (addr_t __user *) data); + return put_user(tmp, (addr_t *) data); } /* @@ -215,7 +215,7 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) high order bit but older gdb's rely on it */ data |= PSW_ADDR_AMODE; #endif - *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data; + *(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr) = data; } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { /* @@ -269,7 +269,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned long __user *) data); + return put_user(tmp, (unsigned long *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -291,8 +291,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, - sizeof(parea))) + if (copy_from_user(&parea, (void *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; data = parea.process_addr; @@ -302,7 +301,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) ret = peek_user(child, addr, data); else { addr_t tmp; - if (get_user (tmp, (addr_t __user *) data)) + if (get_user (tmp, (addr_t *) data)) return -EFAULT; ret = poke_user(child, addr, tmp); } @@ -361,7 +360,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) PSW32_ADDR_AMODE31; } else { /* gpr 0-15 */ - tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw + + tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4); } } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { @@ -403,7 +402,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) } else tmp = 0; - return put_user(tmp, (__u32 __user *) data); + return put_user(tmp, (__u32 *) data); } /* @@ -440,8 +439,8 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) (__u64) tmp & PSW32_ADDR_INSN; } else { /* gpr 0-15 */ - *(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw - + addr*2 + 4) = tmp; + *(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) = + tmp; } } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { /* @@ -510,7 +509,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned int __user *) data); + return put_user(tmp, (unsigned int *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -531,8 +530,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, - sizeof(parea))) + if (copy_from_user(&parea, (void *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; data = parea.process_addr; @@ -542,7 +540,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) ret = peek_user_emu31(child, addr, data); else { __u32 tmp; - if (get_user (tmp, (__u32 __user *) data)) + if (get_user (tmp, (__u32 *) data)) return -EFAULT; ret = poke_user_emu31(child, addr, tmp); } @@ -682,9 +680,11 @@ sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = do_ptrace(child, request, addr, data); - +out_tsk: put_task_struct(child); out: unlock_kernel(); diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index 9ea8becb8..c51ff0d13 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -37,7 +37,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage long sys_pipe(unsigned long __user *fildes) +asmlinkage long sys_pipe(unsigned long * fildes) { int fd[2]; int error; @@ -92,7 +92,7 @@ struct mmap_arg_struct { unsigned long offset; }; -asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg) +asmlinkage long sys_mmap2(struct mmap_arg_struct *arg) { struct mmap_arg_struct a; int error = -EFAULT; @@ -104,7 +104,7 @@ out: return error; } -asmlinkage long old_mmap(struct mmap_arg_struct __user *arg) +asmlinkage long old_mmap(struct mmap_arg_struct *arg) { struct mmap_arg_struct a; long error = -EFAULT; @@ -128,7 +128,7 @@ struct sel_arg_struct { struct timeval *tvp; }; -asmlinkage long old_select(struct sel_arg_struct __user *arg) +asmlinkage long old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; @@ -145,37 +145,37 @@ asmlinkage long old_select(struct sel_arg_struct __user *arg) * * This is really horribly ugly. */ -asmlinkage long sys_ipc(uint call, int first, int second, - unsigned long third, void __user *ptr) +asmlinkage long sys_ipc (uint call, int first, int second, + unsigned long third, void *ptr) { struct ipc_kludge tmp; int ret; switch (call) { case SEMOP: - return sys_semtimedop (first, (struct sembuf __user *) ptr, second, + return sys_semtimedop (first, (struct sembuf *) ptr, second, NULL); case SEMTIMEDOP: - return sys_semtimedop (first, (struct sembuf __user *) ptr, second, - (const struct timespec __user *) third); + return sys_semtimedop (first, (struct sembuf *) ptr, second, + (const struct timespec *) third); case SEMGET: return sys_semget (first, second, third); case SEMCTL: { union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void __user * __user *) ptr)) + if (get_user(fourth.__pad, (void **) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); - } + } case MSGSND: - return sys_msgsnd (first, (struct msgbuf __user *) ptr, + return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); break; case MSGRCV: if (!ptr) return -EINVAL; - if (copy_from_user (&tmp, (struct ipc_kludge __user *) ptr, + if (copy_from_user (&tmp, (struct ipc_kludge *) ptr, sizeof (struct ipc_kludge))) return -EFAULT; return sys_msgrcv (first, tmp.msgp, @@ -183,33 +183,33 @@ asmlinkage long sys_ipc(uint call, int first, int second, case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); - + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + case SHMAT: { ulong raddr; - ret = do_shmat (first, (char __user *) ptr, second, &raddr); + ret = do_shmat (first, (char *) ptr, second, &raddr); if (ret) return ret; - return put_user (raddr, (ulong __user *) third); + return put_user (raddr, (ulong *) third); break; } - case SHMDT: - return sys_shmdt ((char __user *)ptr); + case SHMDT: + return sys_shmdt ((char *)ptr); case SHMGET: return sys_shmget (first, second, third); case SHMCTL: return sys_shmctl (first, second, - (struct shmid_ds __user *) ptr); + (struct shmid_ds *) ptr); default: return -ENOSYS; } - + return -EINVAL; } #ifdef CONFIG_ARCH_S390X -asmlinkage long s390x_newuname(struct new_utsname __user *name) +asmlinkage long s390x_newuname(struct new_utsname * name) { int ret = sys_newuname(name); @@ -256,7 +256,7 @@ struct fadvise64_64_args { }; asmlinkage long -s390_fadvise64_64(struct fadvise64_64_args __user *args) +s390_fadvise64_64(struct fadvise64_64_args *args) { struct fadvise64_64_args a; diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9186fe765..d17ba7b7c 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -271,7 +271,7 @@ SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper) SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */ SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper) SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper) -NI_SYSCALL /* reserved for vserver */ +SYSCALL(sys_vserver,sys_vserver,sys_vserver) SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper) SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper) diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 177a3d26e..27ec3e08b 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -240,6 +240,11 @@ void __init paging_init(void) } #endif /* CONFIG_ARCH_S390X */ +int page_is_ram (unsigned long pagenr) +{ + return pagenr < max_mapnr; +} + void __init mem_init(void) { unsigned long codesize, reservedpages, datasize, initsize; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 8efb8e02a..e774424d6 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -792,6 +792,8 @@ config FRAME_POINTER endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c index 602f6c570..732afaeaf 100644 --- a/arch/sh/kernel/ptrace.c +++ b/arch/sh/kernel/ptrace.c @@ -108,6 +108,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c index 4d5d687d1..4bc97038e 100644 --- a/arch/sh/mm/hugetlbpage.c +++ b/arch/sh/mm/hugetlbpage.c @@ -62,7 +62,8 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long i; pte_t entry; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + // mm->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(mm, HPAGE_SIZE / PAGE_SIZE); if (write_access) entry = pte_mkwrite(pte_mkdirty(mk_pte(page, @@ -115,7 +116,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, pte_val(entry) += PAGE_SIZE; dst_pte++; } - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + // dst->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(dst, HPAGE_SIZE / PAGE_SIZE); addr += HPAGE_SIZE; } return 0; @@ -206,7 +208,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, pte++; } } - mm->rss -= (end - start) >> PAGE_SHIFT; + // mm->rss -= (end - start) >> PAGE_SHIFT; + vx_rsspages_sub(mm, (end - start) >> PAGE_SHIFT); flush_tlb_range(vma, start, end); } diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 79d52a1dd..4b3dd85b5 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -450,6 +450,8 @@ config DEBUG_BUGVERBOSE endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 15fcf89e1..6a9edfeb4 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -53,6 +53,9 @@ all: image boot := arch/sparc/boot +bzImage: image + cp $(boot)/image $(boot)/bzImage + image tftpboot.img: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index d838bd8f6..949072b1c 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -321,6 +321,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, ESRCH); goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + pt_error_return(regs, ESRCH); + goto out_tsk; + } if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 1222d0192..7f2ab05ce 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -332,7 +332,7 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, new_addr = get_unmapped_area(file, addr, new_len, vma ? vma->vm_pgoff : 0, - map_flags); + map_flags, vma->vm_flags & VM_EXEC); ret = new_addr; if (new_addr & ~PAGE_MASK) goto out_sem; @@ -471,13 +471,13 @@ asmlinkage int sys_getdomainname(char __user *name, int len) down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(vx_new_uts(domainname)) + 1; if (nlen < len) len = nlen; if (len > __NEW_UTS_LEN) goto done; - if (copy_to_user(name, system_utsname.domainname, len)) + if (copy_to_user(name, vx_new_uts(domainname), len)) goto done; err = 0; done: diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index fd452a6d3..56c8c878d 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -72,7 +72,7 @@ sys_call_table: /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_nis_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun -/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy +/*265*/ .long sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall /*280*/ .long sys_ni_syscall, sys_ni_syscall, sys_ni_syscall diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index a9a9e0c73..3a1ccaccb 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -137,8 +137,8 @@ static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *re return &win->locals[reg - 16]; } -static unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn) +static inline unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; @@ -153,8 +153,8 @@ static unsigned long compute_effective_address(struct pt_regs *regs, } } -unsigned long safe_compute_effective_address(struct pt_regs *regs, - unsigned int insn) +static inline unsigned long safe_compute_effective_address(struct pt_regs *regs, + unsigned int insn) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index cc857f681..44db33516 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -201,25 +201,6 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, return 0; } -extern unsigned long safe_compute_effective_address(struct pt_regs *, - unsigned int); - -static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) -{ - unsigned int insn; - - if (text_fault) - return regs->pc; - - if (regs->psr & PSR_PS) { - insn = *(unsigned int *) regs->pc; - } else { - __get_user(insn, (unsigned int *) regs->pc); - } - - return safe_compute_effective_address(regs, insn); -} - asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -326,7 +307,7 @@ bad_area_nosemaphore: info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *) compute_si_addr(regs, text_fault); + info.si_addr = (void *)address; info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -380,7 +361,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) compute_si_addr(regs, text_fault); + info.si_addr = (void *)address; info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); if (!from_user) @@ -549,7 +530,7 @@ bad_area: info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *) address; + info.si_addr = (void *)address; info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -559,7 +540,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) address; + info.si_addr = (void *)address; info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); } diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 3b110a53f..57156710c 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -707,6 +707,8 @@ config FRAME_POINTER endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index fc57c40c2..d33535f52 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -69,6 +69,9 @@ drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ boot := arch/sparc64/boot +bzImage: image + cp $(boot)/image $(boot)/bzImage + image tftpboot.img vmlinux.aout: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index dfedd7e73..3891ac582 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -233,6 +233,7 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=m # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -341,6 +342,7 @@ CONFIG_SCSI_SATA_SIS=m CONFIG_SCSI_SATA_VIA=m CONFIG_SCSI_SATA_VITESSE=m # CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set CONFIG_SCSI_DMX3191D=m # CONFIG_SCSI_EATA is not set CONFIG_SCSI_EATA_PIO=m @@ -862,8 +864,9 @@ CONFIG_VIA_RHINE=m # CONFIG_VIA_RHINE_MMIO is not set # -# Ethernet (1000 Mbit) +# Gigabit Ethernet (1000/10000 Mbit) # +CONFIG_NET_GIGE=y CONFIG_ACENIC=m # CONFIG_ACENIC_OMIT_TIGON_I is not set CONFIG_DL2K=m @@ -876,10 +879,6 @@ CONFIG_YELLOWFIN=m CONFIG_R8169=m CONFIG_SK98LIN=m CONFIG_TIGON3=m - -# -# Ethernet (10000 Mbit) -# CONFIG_IXGB=m CONFIG_IXGB_NAPI=y CONFIG_S2IO=m @@ -1585,7 +1584,6 @@ CONFIG_USB_HPUSBSCSI=m # CONFIG_USB_IBMCAM is not set # CONFIG_USB_KONICAWC is not set # CONFIG_USB_OV511 is not set -CONFIG_USB_PWC=m # CONFIG_USB_SE401 is not set # CONFIG_USB_STV680 is not set CONFIG_USB_W9968CF=m diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 580a8c5d2..14533fdb8 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -238,7 +238,8 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index b7f6a1eb9..9a48757d3 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -174,8 +174,6 @@ void enable_irq(unsigned int irq) if (imap == 0UL) return; - preempt_disable(); - if (tlb_type == cheetah || tlb_type == cheetah_plus) { unsigned long ver; @@ -216,8 +214,6 @@ void enable_irq(unsigned int irq) * Things like FFB can now be handled via the new IRQ mechanism. */ upa_writel(tid | IMAP_VALID, imap); - - preempt_enable(); } /* This now gets passed true ino's as well. */ diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 3e9aa09a9..8e5e09832 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -172,6 +172,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, ESRCH); goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + pt_error_return(regs, ESRCH); + goto out_tsk; + } if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 64b873212..040323b38 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -547,18 +547,15 @@ retry: static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, cpumask_t mask) { u64 data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff)); - int this_cpu = get_cpu(); cpus_and(mask, mask, cpu_online_map); - cpu_clear(this_cpu, mask); + cpu_clear(smp_processor_id(), mask); if (tlb_type == spitfire) spitfire_xcall_deliver(data0, data1, data2, mask); else cheetah_xcall_deliver(data0, data1, data2, mask); /* NOTE: Caller runs local copy on master. */ - - put_cpu(); } extern unsigned long xcall_sync_tick; @@ -688,12 +685,11 @@ static __inline__ void __local_flush_dcache_page(struct page *page) void smp_flush_dcache_page_impl(struct page *page, int cpu) { cpumask_t mask = cpumask_of_cpu(cpu); - int this_cpu = get_cpu(); #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes); #endif - if (cpu == this_cpu) { + if (cpu == smp_processor_id()) { __local_flush_dcache_page(page); } else if (cpu_online(cpu)) { u64 data0; @@ -718,17 +714,14 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) atomic_inc(&dcpage_flushes_xcall); #endif } - - put_cpu(); } void flush_dcache_page_all(struct mm_struct *mm, struct page *page) { cpumask_t mask = cpu_online_map; u64 data0; - int this_cpu = get_cpu(); - cpu_clear(this_cpu, mask); + cpu_clear(smp_processor_id(), mask); #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes); @@ -754,8 +747,6 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) #endif flush_self: __local_flush_dcache_page(page); - - put_cpu(); } void smp_receive_signal(int cpu) @@ -851,7 +842,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm) { u32 ctx = CTX_HWBITS(mm->context); - int cpu = get_cpu(); + int cpu = smp_processor_id(); if (atomic_read(&mm->mm_users) == 1) { /* See smp_flush_tlb_page for info about this. */ @@ -865,8 +856,6 @@ void smp_flush_tlb_mm(struct mm_struct *mm) local_flush_and_out: __flush_tlb_mm(ctx, SECONDARY_CONTEXT); - - put_cpu(); } } @@ -874,7 +863,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { u32 ctx = CTX_HWBITS(mm->context); - int cpu = get_cpu(); + int cpu = smp_processor_id(); start &= PAGE_MASK; end = PAGE_ALIGN(end); @@ -891,8 +880,6 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, local_flush_and_out: __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); - - put_cpu(); } void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end) @@ -911,7 +898,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) { { u32 ctx = CTX_HWBITS(mm->context); - int cpu = get_cpu(); + int cpu = smp_processor_id(); page &= PAGE_MASK; if (mm == current->active_mm && @@ -951,8 +938,6 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) local_flush_and_out: __flush_tlb_page(ctx, page, SECONDARY_CONTEXT); - - put_cpu(); } } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 10c782137..ea2c0e3b0 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -189,11 +189,6 @@ EXPORT_SYMBOL(___test_and_change_bit); EXPORT_SYMBOL(___test_and_set_le_bit); EXPORT_SYMBOL(___test_and_clear_le_bit); -/* Bit searching */ -EXPORT_SYMBOL(find_next_bit); -EXPORT_SYMBOL(find_next_zero_bit); -EXPORT_SYMBOL(find_next_zero_le_bit); - EXPORT_SYMBOL(ivector_table); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 7a5d4f4e5..95e3d3ace 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -91,7 +91,7 @@ SIGN1(sys32_io_submit, compat_sys_io_submit, %o1) SIGN1(sys32_mq_open, compat_sys_mq_open, %o1) SIGN1(sys32_select, compat_sys_select, %o0) SIGN1(sys32_mkdir, sys_mkdir, %o1) -SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5) +SIGN2(sys32_futex, compat_sys_futex, %o1, %o2) SIGN1(sys32_sysfs, compat_sys_sysfs, %o0) SIGN3(sys32_ipc, compat_sys_ipc, %o1, %o2, %o3) SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1) diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 5325e41e8..f1a61914b 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -127,7 +127,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u if (flags & MAP_FIXED) { /* Ok, don't mess with it. */ - return get_unmapped_area(NULL, addr, len, pgoff, flags); + return get_unmapped_area(NULL, addr, len, pgoff, flags, 0); } flags &= ~MAP_SHARED; @@ -140,7 +140,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u align_goal = (64UL * 1024); do { - addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); + addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags, 0); if (!(addr & ~PAGE_MASK)) { addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); break; @@ -158,7 +158,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u * be obtained. */ if (addr & ~PAGE_MASK) - addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); + addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags, 0); return addr; } @@ -402,7 +402,7 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, /* MREMAP_FIXED checked above. */ new_addr = get_unmapped_area(file, addr, new_len, vma ? vma->vm_pgoff : 0, - map_flags); + map_flags, vma->vm_flags & VM_EXEC); ret = new_addr; if (new_addr & ~PAGE_MASK) goto out_sem; @@ -465,13 +465,13 @@ asmlinkage long sys_getdomainname(char __user *name, int len) down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(vx_new_uts(domainname)) + 1; if (nlen < len) len = nlen; if (len > __NEW_UTS_LEN) goto done; - if (copy_to_user(name, system_utsname.domainname, len)) + if (copy_to_user(name, vx_new_uts(domainname), len)) goto done; err = 0; done: diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index e55f9e494..c3a52ceb3 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1750,7 +1750,7 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, /* MREMAP_FIXED checked above. */ new_addr = get_unmapped_area(file, addr, new_len, vma ? vma->vm_pgoff : 0, - map_flags); + map_flags, vma->vm_flags & VM_EXEC); ret = new_addr; if (new_addr & ~PAGE_MASK) goto out_sem; diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 0ed11eaec..c1c064021 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -800,8 +800,8 @@ asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) } /* So stupid... */ -extern long compat_sys_wait4(compat_pid_t, compat_uint_t __user *, int, - struct compat_rusage __user *); +extern long compat_sys_wait4(compat_pid_t, compat_uint_t *, int, + struct compat_rusage *); asmlinkage int sunos_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, struct compat_rusage __user *ru) { diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 966e2b11f..2187876ec 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -72,7 +72,7 @@ sys_call_table32: /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl .word sys_ni_syscall, sys32_clock_settime, compat_clock_gettime, compat_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy + .word sys_timer_delete, sys32_timer_create, sys_vserver, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, sys_ni_syscall /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall @@ -136,7 +136,7 @@ sys_call_table: /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_ni_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy + .word sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 646a788fa..5b664354e 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -158,8 +158,8 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) } } -unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn, unsigned int rd) +static unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn, unsigned int rd) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index 230e59f18..14a4c728b 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -10,8 +10,7 @@ lib-y := PeeCeeI.o blockops.o strlen.o strncmp.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o ipcsum.o rwsem.o xor.o splock.o \ - find_bit.o + U3copy_in_user.o mcount.o ipcsum.o rwsem.o xor.o splock.o lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c index 9e083e27d..7b68a4deb 100644 --- a/arch/sparc64/lib/debuglocks.c +++ b/arch/sparc64/lib/debuglocks.c @@ -55,7 +55,7 @@ void _do_spin_lock(spinlock_t *lock, char *str) { unsigned long caller, val; int stuck = INIT_STUCK; - int cpu = get_cpu(); + int cpu = smp_processor_id(); int shown = 0; GET_CALLER(caller); @@ -80,14 +80,12 @@ again: lock->owner_cpu = cpu; current->thread.smp_lock_count++; current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); } int _spin_trylock(spinlock_t *lock) { unsigned long val, caller; - int cpu = get_cpu(); + int cpu = smp_processor_id(); GET_CALLER(caller); __asm__ __volatile__("ldstub [%1], %0" @@ -101,9 +99,6 @@ int _spin_trylock(spinlock_t *lock) current->thread.smp_lock_count++; current->thread.smp_lock_pc = ((unsigned int)caller); } - - put_cpu(); - return val == 0; } @@ -122,7 +117,7 @@ void _do_read_lock (rwlock_t *rw, char *str) { unsigned long caller, val; int stuck = INIT_STUCK; - int cpu = get_cpu(); + int cpu = smp_processor_id(); int shown = 0; GET_CALLER(caller); @@ -153,15 +148,13 @@ wlock_again: rw->reader_pc[cpu] = ((unsigned int)caller); current->thread.smp_lock_count++; current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); } void _do_read_unlock (rwlock_t *rw, char *str) { unsigned long caller, val; int stuck = INIT_STUCK; - int cpu = get_cpu(); + int cpu = smp_processor_id(); int shown = 0; GET_CALLER(caller); @@ -188,15 +181,13 @@ runlock_again: } goto runlock_again; } - - put_cpu(); } void _do_write_lock (rwlock_t *rw, char *str) { unsigned long caller, val; int stuck = INIT_STUCK; - int cpu = get_cpu(); + int cpu = smp_processor_id(); int shown = 0; GET_CALLER(caller); @@ -272,8 +263,6 @@ wlock_again: rw->writer_cpu = cpu; current->thread.smp_lock_count++; current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); } void _do_write_unlock(rwlock_t *rw) @@ -313,7 +302,7 @@ wlock_again: int _do_write_trylock (rwlock_t *rw, char *str) { unsigned long caller, val; - int cpu = get_cpu(); + int cpu = smp_processor_id(); GET_CALLER(caller); @@ -333,10 +322,8 @@ int _do_write_trylock (rwlock_t *rw, char *str) : "0" (&(rw->lock)) : "g3", "g5", "g7", "memory"); - if (val) { - put_cpu(); + if (val) return 0; - } if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { /* Readers still around, drop the write @@ -355,8 +342,6 @@ int _do_write_trylock (rwlock_t *rw, char *str) : "r" (&(rw->lock)) : "g3", "g5", "g7", "cc", "memory"); - put_cpu(); - return 0; } @@ -366,8 +351,6 @@ int _do_write_trylock (rwlock_t *rw, char *str) current->thread.smp_lock_count++; current->thread.smp_lock_pc = ((unsigned int)caller); - put_cpu(); - return 1; } diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 6da2759c2..c9954c2ec 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -59,7 +59,8 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long i; pte_t entry; - mm->rss += (HPAGE_SIZE / PAGE_SIZE); + // mm->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(mm, HPAGE_SIZE / PAGE_SIZE); if (write_access) entry = pte_mkwrite(pte_mkdirty(mk_pte(page, @@ -112,7 +113,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, pte_val(entry) += PAGE_SIZE; dst_pte++; } - dst->rss += (HPAGE_SIZE / PAGE_SIZE); + // dst->rss += (HPAGE_SIZE / PAGE_SIZE); + vx_rsspages_add(dst, HPAGE_SIZE / PAGE_SIZE); addr += HPAGE_SIZE; } return 0; @@ -203,7 +205,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, pte++; } } - mm->rss -= (end - start) >> PAGE_SHIFT; + // mm->rss -= (end - start) >> PAGE_SHIFT; + vx_rsspages_sub(mm, (end - start) >> PAGE_SHIFT); flush_tlb_range(vma, start, end); } diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 043861f31..1e9519db0 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -152,9 +152,9 @@ __inline__ void flush_dcache_page_impl(struct page *page) #define dcache_dirty_cpu(page) \ (((page)->flags >> 24) & (NR_CPUS - 1UL)) -static __inline__ void set_dcache_dirty(struct page *page, int this_cpu) +static __inline__ void set_dcache_dirty(struct page *page) { - unsigned long mask = this_cpu; + unsigned long mask = smp_processor_id(); unsigned long non_cpu_bits = ~((NR_CPUS - 1UL) << 24UL); mask = (mask << 24) | (1UL << PG_dcache_dirty); __asm__ __volatile__("1:\n\t" @@ -206,19 +206,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p (page = pfn_to_page(pfn), page_mapping(page)) && ((pg_flags = page->flags) & (1UL << PG_dcache_dirty))) { int cpu = ((pg_flags >> 24) & (NR_CPUS - 1UL)); - int this_cpu = get_cpu(); /* This is just to optimize away some function calls * in the SMP case. */ - if (cpu == this_cpu) + if (cpu == smp_processor_id()) flush_dcache_page_impl(page); else smp_flush_dcache_page_impl(page, cpu); clear_dcache_dirty_cpu(page, cpu); - - put_cpu(); } if (get_thread_fault_code()) __update_mmu_cache(vma->vm_mm->context & TAG_CONTEXT_BITS, @@ -230,15 +227,14 @@ void flush_dcache_page(struct page *page) struct address_space *mapping = page_mapping(page); int dirty = test_bit(PG_dcache_dirty, &page->flags); int dirty_cpu = dcache_dirty_cpu(page); - int this_cpu = get_cpu(); if (mapping && !mapping_mapped(mapping)) { if (dirty) { - if (dirty_cpu == this_cpu) - goto out; + if (dirty_cpu == smp_processor_id()) + return; smp_flush_dcache_page_impl(page, dirty_cpu); } - set_dcache_dirty(page, this_cpu); + set_dcache_dirty(page); } else { /* We could delay the flush for the !page_mapping * case too. But that case is for exec env/arg @@ -247,9 +243,6 @@ void flush_dcache_page(struct page *page) */ flush_dcache_page_impl(page); } - -out: - put_cpu(); } /* When shared+writable mmaps of files go away, we lose all dirty diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 47fbaf3f4..48a634167 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -61,6 +61,20 @@ config MODE_SKAS config NET bool "Networking support" + help + Unless you really know what you are doing, you should say Y here. + The reason is that some programs need kernel networking support even + when running on a stand-alone machine that isn't connected to any + other computer. If you are upgrading from an older kernel, you + should consider updating your networking tools too because changes + in the kernel and the tools often go hand in hand. The tools are + contained in the package net-tools, the location and version number + of which are given in Documentation/Changes. + + For a general introduction to Linux networking, it is highly + recommended to read the NET-HOWTO, available from + . + source "fs/Kconfig.binfmt" @@ -85,6 +99,19 @@ config HOSTFS If you'd like to be able to work with files stored on the host, say Y or M here; otherwise say N. +config HPPFS + tristate "HoneyPot ProcFS" + help + hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc + entries to be overridden, removed, or fabricated from the host. + Its purpose is to allow a UML to appear to be a physical machine + by removing or changing anything in /proc which gives away the + identity of a UML. + + See http://user-mode-linux.sf.net/hppfs.html for more information. + + You only need this if you are setting up a UML honeypot. Otherwise, + it is safe to say 'N' here. config MCONSOLE bool "Management console" @@ -105,6 +132,16 @@ config MCONSOLE config MAGIC_SYSRQ bool "Magic SysRq key" depends on MCONSOLE + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in Documentation/sysrq.txt. Don't say Y + unless you really know what this hack does. config HOST_2G_2G bool "2G/2G host address space split" @@ -160,6 +197,9 @@ config KERNEL_HALF_GIGS config HIGHMEM bool "Highmem support" +config PROC_MM + bool "/proc/mm support" + config KERNEL_STACK_ORDER int "Kernel stack size order" default 2 @@ -168,6 +208,17 @@ config KERNEL_STACK_ORDER be 1 << order pages. The default is OK unless you're running Valgrind on UML, in which case, set this to 3. +config UML_REAL_TIME_CLOCK + bool "Real-time Clock" + default y + help + This option makes UML time deltas match wall clock deltas. This should + normally be enabled. The exception would be if you are debugging with + UML and spend long times with UML stopped at a breakpoint. In this + case, when UML is restarted, it will call the timer enough times to make + up for the time spent at the breakpoint. This could result in a + noticable lag. If this is a problem, then disable this option. + endmenu source "init/Kconfig" @@ -188,6 +239,8 @@ source "net/Kconfig" source "fs/Kconfig" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" @@ -240,6 +293,10 @@ config FRAME_POINTER config PT_PROXY bool "Enable ptrace proxy" depends on XTERM_CHAN && DEBUG_INFO + help + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. config GPROF bool "Enable gprof support" diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block index fba53d9bb..46e97fc78 100644 --- a/arch/um/Kconfig_block +++ b/arch/um/Kconfig_block @@ -29,6 +29,20 @@ config BLK_DEV_UBD_SYNC wise choice too. In all other cases (for example, if you're just playing around with User-Mode Linux) you can choose N. +# Turn this back on when the driver actually works +# +#config BLK_DEV_COW +# tristate "COW block device" +# help +# This is a layered driver which sits above two other block devices. +# One is read-only, and the other is a read-write layer which stores +# all changes. This provides the illusion that the read-only layer +# can be mounted read-write and changed. + +config BLK_DEV_COW_COMMON + bool + default BLK_DEV_COW || BLK_DEV_UBD + config BLK_DEV_LOOP tristate "Loopback device support" diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net index 443a74bd6..94c6bf098 100644 --- a/arch/um/Kconfig_net +++ b/arch/um/Kconfig_net @@ -1,5 +1,5 @@ -menu "Network Devices" +menu "UML Network Devices" depends on NET # UML virtual driver @@ -176,73 +176,5 @@ config UML_NET_SLIRP Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" - -# Below are hardware-independent drivers mirrored from -# drivers/net/Config.in. It would be nice if Linux -# had HW independent drivers separated from the other -# but it does not. Until then each non-ISA/PCI arch -# needs to provide it's own menu of network drivers -config DUMMY - tristate "Dummy net driver support" - -config BONDING - tristate "Bonding driver support" - -config EQUALIZER - tristate "EQL (serial line load balancing) support" - -config TUN - tristate "Universal TUN/TAP device driver support" - -config ETHERTAP - tristate "Ethertap network tap (OBSOLETE)" - depends on EXPERIMENTAL && NETLINK - -config PPP - tristate "PPP (point-to-point protocol) support" - -config PPP_MULTILINK - bool "PPP multilink support (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config PPP_FILTER - bool "PPP filtering" - depends on PPP && FILTER - -config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP - -config PPP_SYNC_TTY - tristate "PPP support for sync tty ports" - depends on PPP - -config PPP_DEFLATE - tristate "PPP Deflate compression" - depends on PPP - -config PPP_BSDCOMP - tristate "PPP BSD-Compress compression" - depends on PPP - -config PPPOE - tristate "PPP over Ethernet (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config SLIP - tristate "SLIP (serial line) support" - -config SLIP_COMPRESSED - bool "CSLIP compressed headers" - depends on SLIP=y - -config SLIP_SMART - bool "Keepalive and linefill" - depends on SLIP=y - -config SLIP_MODE_SLIP6 - bool "Six bit SLIP encapsulation" - depends on SLIP=y - endmenu diff --git a/arch/um/Makefile b/arch/um/Makefile index bb7d3f6ba..4e9bbefe4 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -22,17 +22,21 @@ core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ # Have to precede the include because the included Makefiles reference them. -SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ - include/asm-um/sigcontext.h include/asm-um/processor.h \ - include/asm-um/ptrace.h include/asm-um/arch-signal.h +SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \ + arch-signal.h module.h +SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h -include $(ARCH_DIR)/Makefile-$(SUBARCH) -include $(ARCH_DIR)/Makefile-os-$(OS) +# This target adds dependencies to "prepare". They are defined in the included +# Makefiles (see Makefile-i386). + +.PHONY: sys_prepare +sys_prepare: + @: MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas @@ -41,6 +45,9 @@ ifneq ($(MAKEFILE-y),) include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) endif +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) + EXTRAVERSION := $(EXTRAVERSION)-1um ARCH_INCLUDE = -I$(ARCH_DIR)/include @@ -52,14 +59,20 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ - $(MODE_INCLUDE) + -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc +# These are needed for clean and mrproper, since in that case .config is not +# included; the values here are meaningless + +CONFIG_NEST_LEVEL ?= 0 +CONFIG_KERNEL_HALF_GIGS ?= 0 + SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) ifeq ($(CONFIG_MODE_SKAS), y) -$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h endif include/linux/version.h: arch/$(ARCH)/Makefile @@ -98,17 +111,17 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT) CONFIG_KERNEL_STACK_ORDER ?= 2 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) -AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \ +AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \ -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) + -DKERNEL_STACK_SIZE=$(STACK_SIZE)) -AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum +export AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) -$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE - $(call if_changed_dep,as_s_S) +#$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE +# $(call if_changed_dep,as_s_S) linux: vmlinux $(LD_SCRIPT-y) $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ @@ -116,37 +129,47 @@ linux: vmlinux $(LD_SCRIPT-y) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) +USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS)) USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE +# From main Makefile, these options are set after including the ARCH makefile. +# So copy them here. + +ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +USER_CFLAGS += -Os +else +USER_CFLAGS += -O2 +endif + +ifndef CONFIG_FRAME_POINTER +USER_CFLAGS += -fomit-frame-pointer +endif + +ifdef CONFIG_DEBUG_INFO +USER_CFLAGS += -g +endif + CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \ - $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) + $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \ + $(GEN_HEADERS) -$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c - $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< +MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ + $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) + +$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare + @ echo ' MAIN $@' + @ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< archmrproper: - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d archmrproper; \ - done - rm -f $(CLEAN_FILES) $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) - -archclean: sysclean - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d clean; \ - done - find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ - -o -name '*.gcov' \) -type f -print | xargs rm -f - rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) + @: -archdep: - for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done +archclean: + @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ + -o -name '*.gcov' \) -type f -print | xargs rm -f $(SYMLINK_HEADERS): cd $(TOPDIR)/$(dir $@) ; \ @@ -161,19 +184,26 @@ $(ARCH_DIR)/include/sysdep: $(ARCH_DIR)/os: cd $(ARCH_DIR) && ln -sf os-$(OS) os -$(ARCH_DIR)/include/uml-config.h : - sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ +# Generated files +define filechk_umlconfig + sed 's/ CONFIG/ UML_CONFIG/' +endef + +$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h + $(call filechk,umlconfig) + +filechk_gen_header = $< $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task - $< > $@ + $(call filechk,gen_header) $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants - $< > $@ + $(call filechk,gen_header) -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ - $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \ + sys_prepare FORCE ; $(ARCH_DIR)/util: FORCE - @$(call descend,$@,) + $(Q)$(MAKE) $(build)=$@ -export SUBARCH USER_CFLAGS OS +export SUBARCH USER_CFLAGS OS diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 3bd90fbdb..36b1f692e 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -16,22 +16,27 @@ SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h +sys_prepare: $(SYS_DIR)/sc.h + prepare: $(SYS_HEADERS) +filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc + $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc - $< > $@ + $(call filechk,$@) + +filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread - $< > $@ + $(call filechk,$@) -$(SYS_UTIL_DIR)/mk_sc: FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_sc: scripts/basic/fixdep include/config/MARKER FORCE ; + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ; + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ $(SYS_UTIL_DIR): include/asm FORCE - @$(call descend,$@,) + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) -sysclean : - rm -f $(SYS_HEADERS) +CLEAN_FILES += $(SYS_HEADERS) diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas index b9dfec5f7..d114908c9 100644 --- a/arch/um/Makefile-skas +++ b/arch/um/Makefile-skas @@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include LINK_SKAS = -Wl,-rpath,/lib LD_SCRIPT_SKAS = dyn.lds.s -GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h -$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : - $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h : + $(Q)$(MAKE) $(build)=$(ARCH_DIR)/kernel/skas $@ diff --git a/arch/um/config.release b/arch/um/config.release index 82d3badeb..ea9f26986 100644 --- a/arch/um/config.release +++ b/arch/um/config.release @@ -228,7 +228,6 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m CONFIG_UDF_FS=m -# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set diff --git a/arch/um/defconfig b/arch/um/defconfig index 3430e124a..06fe817ca 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -3,29 +3,19 @@ # CONFIG_USERMODE=y CONFIG_MMU=y -CONFIG_SWAP=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_CONFIG_LOG_BUF_SHIFT=14 # -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General Setup +# UML-specific options # CONFIG_MODE_TT=y CONFIG_MODE_SKAS=y CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_HOSTFS=y +CONFIG_HPPFS=y CONFIG_MCONSOLE=y CONFIG_MAGIC_SYSRQ=y # CONFIG_HOST_2G_2G is not set @@ -36,12 +26,46 @@ CONFIG_KERNEL_HALF_GIGS=1 # CONFIG_HIGHMEM is not set CONFIG_PROC_MM=y CONFIG_KERNEL_STACK_ORDER=2 +CONFIG_UML_REAL_TIME_CLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support # -CONFIG_MODULES=y -# CONFIG_KMOD is not set +# CONFIG_MODULES is not set + +# +# Generic Driver Options +# # # Character Devices @@ -69,6 +93,7 @@ CONFIG_HOSTAUDIO=y # CONFIG_BLK_DEV_UBD=y # CONFIG_BLK_DEV_UBD_SYNC is not set +CONFIG_BLK_DEV_COW_COMMON=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -78,7 +103,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_NETDEVICES=y # -# Network Devices +# UML Network Devices # CONFIG_UML_NET=y CONFIG_UML_NET_ETHERTAP=y @@ -88,22 +113,6 @@ CONFIG_UML_NET_DAEMON=y CONFIG_UML_NET_MCAST=y # CONFIG_UML_NET_PCAP is not set CONFIG_UML_NET_SLIRP=y -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=y -# CONFIG_ETHERTAP is not set -CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set -# CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPPOE is not set -CONFIG_SLIP=y -# CONFIG_SLIP_COMPRESSED is not set -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set # # Networking support @@ -115,8 +124,6 @@ CONFIG_SLIP=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y # CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -126,23 +133,24 @@ CONFIG_INET=y # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set -# CONFIG_XFRM_USER is not set +# CONFIG_INET_IPCOMP is not set # CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set # CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_NET_DIVERT is not set @@ -160,94 +168,144 @@ CONFIG_IPV6_SCTP__=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_TUX is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y # # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set +# CONFIG_NE2000 is not set # # Ethernet (1000 Mbit) # # -# Wireless LAN (non-hamradio) +# Ethernet (10000 Mbit) # -# CONFIG_NET_RADIO is not set # -# Token Ring devices (depends on LLC=y) +# Token Ring devices # -# CONFIG_SHAPER is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +# CONFIG_SLIP_COMPRESSED is not set +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # File systems # +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set CONFIG_QUOTA=y # CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V2 is not set CONFIG_QUOTACTL=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set CONFIG_JFFS_FS=y CONFIG_JFFS_FS_VERBOSE=0 -CONFIG_JFFS_PROC_FS=y # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -CONFIG_RAMFS=y -CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_JFS_FS is not set -CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set # CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_XFS_FS is not set # # Network File Systems # -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_NFS_FS is not set # CONFIG_NFSD is not set # CONFIG_EXPORTFS is not set -# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set # CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # @@ -255,11 +313,11 @@ CONFIG_EXT2_FS=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set @@ -299,6 +357,18 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + # # Security options # @@ -313,32 +383,12 @@ CONFIG_NLS_DEFAULT="iso8859-1" # Library routines # # CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set # # SCSI support # -CONFIG_SCSI=y -CONFIG_GENERIC_ISA_DMA=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_SR_EXTRA_DEVS=2 -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -CONFIG_SCSI_DEBUG_QUEUES=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_DEBUG=y +# CONFIG_SCSI is not set # # Multi-device support (RAID and LVM) @@ -360,6 +410,7 @@ CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set +# CONFIG_INFTL is not set # # RAM/ROM/Flash chip drivers @@ -374,20 +425,21 @@ CONFIG_MTD_BLOCK=y # # Mapping drivers for chip access # +# CONFIG_MTD_COMPLEX_MAPPINGS is not set # # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set -CONFIG_MTD_BLKMTD=m +CONFIG_MTD_BLKMTD=y # # Disk-On-Chip Device Drivers # -# CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set # # NAND Flash Device Drivers diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 8ea9ada4a..7dd15474b 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com) # Licensed under the GPL # @@ -39,6 +39,8 @@ obj-$(CONFIG_PTY_CHAN) += pty.o obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o +obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o +obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-y += stdio_console.o $(CHAN_OBJS) @@ -46,18 +48,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ null.o pty.o tty.o xterm.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean: - -modules: - -fastdep: - -dep: - -archmrproper: clean - diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 9e45a082e..56e19fa7b 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "chan_kern.h" @@ -265,6 +266,11 @@ static int one_chan_config_string(struct chan *chan, char *str, int size, { int n = 0; + if(chan == NULL){ + CONFIG_CHUNK(str, size, n, "none", 1); + return(n); + } + CONFIG_CHUNK(str, size, n, chan->ops->type, 0); if(chan->dev == NULL){ @@ -420,7 +426,8 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, INIT_LIST_HEAD(chans); } - if((out = strchr(str, ',')) != NULL){ + out = strchr(str, ','); + if(out != NULL){ in = str; *out = '\0'; out++; @@ -475,12 +482,15 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task, goto out; } err = chan->ops->read(chan->fd, &c, chan->data); - if(err > 0) tty_receive_char(tty, c); + if(err > 0) + tty_receive_char(tty, c); } while(err > 0); + if(err == 0) reactivate_fd(chan->fd, irq); if(err == -EIO){ if(chan->primary){ - if(tty != NULL) tty_hangup(tty); + if(tty != NULL) + tty_hangup(tty); line_disable(dev, irq); close_chan(chans); free_chan(chans); diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 714bace49..7319ddd17 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -24,29 +23,27 @@ void generic_close(int fd, void *unused) { - close(fd); + os_close_file(fd); } int generic_read(int fd, char *c_out, void *unused) { int n; - n = read(fd, c_out, sizeof(*c_out)); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-EIO); - return(1); + n = os_read_file(fd, c_out, sizeof(*c_out)); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-EIO); + return(n); } +/* XXX Trivial wrapper around os_write_file */ + int generic_write(int fd, const char *buf, int n, void *unused) { - int count; - - count = write(fd, buf, n); - if(count < 0) return(-errno); - return(count); + return(os_write_file(fd, buf, n)); } int generic_console_write(int fd, const char *buf, int n, void *unused) @@ -68,15 +65,18 @@ int generic_console_write(int fd, const char *buf, int n, void *unused) int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out) { - struct winsize size; - int ret = 0; - - if(ioctl(fd, TIOCGWINSZ, &size) == 0){ - ret = ((*rows_out != size.ws_row) || - (*cols_out != size.ws_col)); - *rows_out = size.ws_row; - *cols_out = size.ws_col; - } + int rows, cols; + int ret; + + ret = os_window_size(fd, &rows, &cols); + if(ret < 0) + return(ret); + + ret = ((*rows_out != rows) || (*cols_out != cols)); + + *rows_out = rows; + *cols_out = cols; + return(ret); } @@ -100,14 +100,16 @@ static int winch_thread(void *arg) struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; + int count, err; char c = 1; - close(data->close_me); + os_close_file(data->close_me); pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to write synchronization " - "byte, errno = %d\n", errno); + "byte, err = %d\n", -count); signal(SIGWINCH, winch_handler); sigfillset(&sigs); @@ -123,26 +125,24 @@ static int winch_thread(void *arg) exit(1); } - if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){ - printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno); - exit(1); - } - if(tcsetpgrp(pty_fd, os_getpid()) < 0){ - printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno); + err = os_new_tty_pgrp(pty_fd, os_getpid()); + if(err < 0){ + printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); exit(1); } - if(read(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_read_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " - "errno = %d\n", errno); + "err = %d\n", -count); while(1){ pause(); - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){ - printk("winch_thread : write failed, errno = %d\n", - errno); - } + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) + printk("winch_thread : write failed, err = %d\n", + -count); } } @@ -154,8 +154,8 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) char c; err = os_pipe(fds, 1, 1); - if(err){ - printk("winch_tramp : os_pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("winch_tramp : os_pipe failed, err = %d\n", -err); return(err); } @@ -168,12 +168,12 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) return(pid); } - close(fds[1]); + os_close_file(fds[1]); *fd_out = fds[0]; - n = read(fds[0], &c, sizeof(c)); + n = os_read_file(fds[0], &c, sizeof(c)); if(n != sizeof(c)){ printk("winch_tramp : failed to read synchronization byte\n"); - printk("read returned %d, errno = %d\n", n, errno); + printk("read failed, err = %d\n", -n); printk("fd %d will not support SIGWINCH\n", fd); *fd_out = -1; } @@ -183,20 +183,24 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) void register_winch(int fd, void *device_data) { int pid, thread, thread_fd; + int count; char c = 1; - if(!isatty(fd)) return; + if(!isatty(fd)) + return; pid = tcgetpgrp(fd); - if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && - (pid == -1)){ + if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, + device_data) && (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); if(fd != -1){ register_winch_irq(thread_fd, fd, thread, device_data); - if(write(thread_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(thread_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("register_winch : failed to write " - "synchronization byte\n"); + "synchronization byte, err = %d\n", + -count); } } } diff --git a/arch/um/drivers/cow_kern.c b/arch/um/drivers/cow_kern.c new file mode 100644 index 000000000..ad843f3b6 --- /dev/null +++ b/arch/um/drivers/cow_kern.c @@ -0,0 +1,630 @@ +#define COW_MAJOR 60 +#define MAJOR_NR COW_MAJOR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "2_5compat.h" +#include "cow.h" +#include "ubd_user.h" + +#define COW_SHIFT 4 + +struct cow { + int count; + char *cow_path; + dev_t cow_dev; + struct block_device *cow_bdev; + char *backing_path; + dev_t backing_dev; + struct block_device *backing_bdev; + int sectorsize; + unsigned long *bitmap; + unsigned long bitmap_len; + int bitmap_offset; + int data_offset; + devfs_handle_t devfs; + struct semaphore sem; + struct semaphore io_sem; + atomic_t working; + spinlock_t io_lock; + struct buffer_head *bh; + struct buffer_head *bhtail; + void *end_io; +}; + +#define DEFAULT_COW { \ + .count = 0, \ + .cow_path = NULL, \ + .cow_dev = 0, \ + .backing_path = NULL, \ + .backing_dev = 0, \ + .bitmap = NULL, \ + .bitmap_len = 0, \ + .bitmap_offset = 0, \ + .data_offset = 0, \ + .devfs = NULL, \ + .working = ATOMIC_INIT(0), \ + .io_lock = SPIN_LOCK_UNLOCKED, \ +} + +#define MAX_DEV (8) +#define MAX_MINOR (MAX_DEV << COW_SHIFT) + +struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW }; + +/* Not modified by this driver */ +static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE }; +static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 }; + +/* Protected by cow_lock */ +static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 }; + +static struct hd_struct cow_part[MAX_MINOR] = + { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } }; + +/* Protected by io_request_lock */ +static request_queue_t *cow_queue; + +static int cow_open(struct inode *inode, struct file *filp); +static int cow_release(struct inode * inode, struct file * file); +static int cow_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +static int cow_revalidate(kdev_t rdev); + +static struct block_device_operations cow_blops = { + .open = cow_open, + .release = cow_release, + .ioctl = cow_ioctl, + .revalidate = cow_revalidate, +}; + +/* Initialized in an initcall, and unchanged thereafter */ +devfs_handle_t cow_dir_handle; + +#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \ +{ \ + .major = maj, \ + .major_name = name, \ + .minor_shift = shift, \ + .max_p = 1 << shift, \ + .part = parts, \ + .sizes = bsizes, \ + .nr_real = max, \ + .real_devices = NULL, \ + .next = NULL, \ + .fops = blops, \ + .de_arr = NULL, \ + .flags = 0 \ +} + +static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED; + +static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part, + COW_SHIFT, sizes, MAX_DEV, + &cow_blops); + +static int cow_add(int n) +{ + struct cow *dev = &cow_dev[n]; + char name[sizeof("nnnnnn\0")]; + int err = -ENODEV; + + if(dev->cow_path == NULL) + goto out; + + sprintf(name, "%d", n); + dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE, + MAJOR_NR, n << COW_SHIFT, S_IFBLK | + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + &cow_blops, NULL); + + init_MUTEX_LOCKED(&dev->sem); + init_MUTEX(&dev->io_sem); + + return(0); + + out: + return(err); +} + +/* + * Add buffer_head to back of pending list + */ +static void cow_add_bh(struct cow *cow, struct buffer_head *bh) +{ + unsigned long flags; + + spin_lock_irqsave(&cow->io_lock, flags); + if(cow->bhtail != NULL){ + cow->bhtail->b_reqnext = bh; + cow->bhtail = bh; + } + else { + cow->bh = bh; + cow->bhtail = bh; + } + spin_unlock_irqrestore(&cow->io_lock, flags); +} + +/* +* Grab first pending buffer +*/ +static struct buffer_head *cow_get_bh(struct cow *cow) +{ + struct buffer_head *bh; + + spin_lock_irq(&cow->io_lock); + bh = cow->bh; + if(bh != NULL){ + if(bh == cow->bhtail) + cow->bhtail = NULL; + cow->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + } + spin_unlock_irq(&cow->io_lock); + + return(bh); +} + +static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, + struct buffer_head **cow_bh, int ncow_bh) +{ + int i; + + if(ncow_bh > 0) + ll_rw_block(WRITE, ncow_bh, cow_bh); + + for(i = 0; i < ncow_bh ; i++){ + wait_on_buffer(cow_bh[i]); + brelse(cow_bh[i]); + } + + ll_rw_block(WRITE, 1, &bh); + brelse(bh); +} + +static struct buffer_head *cow_new_bh(struct cow *dev, int sector) +{ + struct buffer_head *bh; + + sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize; + bh = getblk(dev->cow_dev, sector, dev->sectorsize); + memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])), + dev->sectorsize); + return(bh); +} + +/* Copied from loop.c, needed to avoid deadlocking in make_request. */ + +static int cow_thread(void *data) +{ + struct cow *dev = data; + struct buffer_head *bh; + + daemonize(); + exit_files(current); + + sprintf(current->comm, "cow%d", dev - cow_dev); + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + + atomic_inc(&dev->working); + + current->policy = SCHED_OTHER; + current->nice = -20; + + current->flags |= PF_NOIO; + + /* + * up sem, we are running + */ + up(&dev->sem); + + for(;;){ + int start, len, nbh, i, update_bitmap = 0; + struct buffer_head *cow_bh[2]; + + down_interruptible(&dev->io_sem); + /* + * could be upped because of tear-down, not because of + * pending work + */ + if(!atomic_read(&dev->working)) + break; + + bh = cow_get_bh(dev); + if(bh == NULL){ + printk(KERN_ERR "cow: missing bh\n"); + continue; + } + + start = bh->b_blocknr * bh->b_size / dev->sectorsize; + len = bh->b_size / dev->sectorsize; + for(i = 0; i < len ; i++){ + if(ubd_test_bit(start + i, + (unsigned char *) dev->bitmap)) + continue; + + update_bitmap = 1; + ubd_set_bit(start + i, (unsigned char *) dev->bitmap); + } + + cow_bh[0] = NULL; + cow_bh[1] = NULL; + nbh = 0; + if(update_bitmap){ + cow_bh[0] = cow_new_bh(dev, start); + nbh++; + if(start / dev->sectorsize != + (start + len) / dev->sectorsize){ + cow_bh[1] = cow_new_bh(dev, start + len); + nbh++; + } + } + + bh->b_dev = dev->cow_dev; + bh->b_blocknr += dev->data_offset / dev->sectorsize; + + cow_handle_bh(dev, bh, cow_bh, nbh); + + /* + * upped both for pending work and tear-down, lo_pending + * will hit zero then + */ + if(atomic_dec_and_test(&dev->working)) + break; + } + + up(&dev->sem); + return(0); +} + +static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh) +{ + struct cow *dev; + int n, minor; + + minor = MINOR(bh->b_rdev); + n = minor >> COW_SHIFT; + dev = &cow_dev[n]; + + dev->end_io = NULL; + if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){ + bh->b_rdev = dev->cow_dev; + bh->b_rsector += dev->data_offset / dev->sectorsize; + } + else if(rw == WRITE){ + bh->b_dev = dev->cow_dev; + bh->b_blocknr += dev->data_offset / dev->sectorsize; + + cow_add_bh(dev, bh); + up(&dev->io_sem); + return(0); + } + else { + bh->b_rdev = dev->backing_dev; + } + + return(1); +} + +int cow_init(void) +{ + int i; + + cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL); + if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) { + printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR); + return -1; + } + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + blksize_size[MAJOR_NR] = blk_sizes; + blk_size[MAJOR_NR] = sizes; + INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes); + + cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR); + blk_init_queue(cow_queue, NULL); + INIT_ELV(cow_queue, &cow_queue->elevator); + blk_queue_make_request(cow_queue, cow_make_request); + + add_gendisk(&cow_gendisk); + + for(i=0;i 0){ + n = (left > blocksize) ? blocksize : left; + + bh = bread(dev, block, (n < 512) ? 512 : n); + if(bh == NULL) + return(-EIO); + + n -= offset; + memcpy(&buf[cur], bh->b_data + offset, n); + block++; + left -= n; + cur += n; + offset = 0; + brelse(bh); + } + + return(count); +} + +static int cow_open(struct inode *inode, struct file *filp) +{ + int (*dev_ioctl)(struct inode *, struct file *, unsigned int, + unsigned long); + mm_segment_t fs; + struct cow *dev; + __u64 size; + __u32 version, align; + time_t mtime; + char *backing_file; + int n, offset, err = 0; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + offset = n << COW_SHIFT; + + spin_lock(&cow_lock); + + if(dev->count == 0){ + dev->cow_dev = name_to_kdev_t(dev->cow_path); + if(dev->cow_dev == 0){ + printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") " + "failed\n", dev->cow_path); + err = -ENODEV; + } + + dev->backing_dev = name_to_kdev_t(dev->backing_path); + if(dev->backing_dev == 0){ + printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") " + "failed\n", dev->backing_path); + err = -ENODEV; + } + + if(err) + goto out; + + dev->cow_bdev = bdget(dev->cow_dev); + if(dev->cow_bdev == NULL){ + printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", + dev->cow_path); + err = -ENOMEM; + } + dev->backing_bdev = bdget(dev->backing_dev); + if(dev->backing_bdev == NULL){ + printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", + dev->backing_path); + err = -ENOMEM; + } + + if(err) + goto out; + + err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, + BDEV_RAW); + if(err){ + printk("cow_open - blkdev_get of COW device failed, " + "error = %d\n", err); + goto out; + } + + err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW); + if(err){ + printk("cow_open - blkdev_get of backing device " + "failed, error = %d\n", err); + goto out; + } + + err = read_cow_header(reader, &dev->cow_dev, &version, + &backing_file, &mtime, &size, + &dev->sectorsize, &align, + &dev->bitmap_offset); + if(err){ + printk(KERN_ERR "cow_open - read_cow_header failed, " + "err = %d\n", err); + goto out; + } + + cow_sizes(version, size, dev->sectorsize, align, + dev->bitmap_offset, &dev->bitmap_len, + &dev->data_offset); + dev->bitmap = (void *) vmalloc(dev->bitmap_len); + if(dev->bitmap == NULL){ + err = -ENOMEM; + printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); + goto out; + } + flush_tlb_kernel_vm(); + + err = reader(dev->bitmap_offset, (char *) dev->bitmap, + dev->bitmap_len, &dev->cow_dev); + if(err < 0){ + printk(KERN_ERR "Failed to read COW bitmap\n"); + vfree(dev->bitmap); + goto out; + } + + dev_ioctl = dev->backing_bdev->bd_op->ioctl; + fs = get_fs(); + set_fs(KERNEL_DS); + err = (*dev_ioctl)(inode, filp, BLKGETSIZE, + (unsigned long) &sizes[offset]); + set_fs(fs); + if(err){ + printk(KERN_ERR "cow_open - BLKGETSIZE failed, " + "error = %d\n", err); + goto out; + } + + kernel_thread(cow_thread, dev, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + down(&dev->sem); + } + dev->count++; + out: + spin_unlock(&cow_lock); + return(err); +} + +static int cow_release(struct inode * inode, struct file * file) +{ + struct cow *dev; + int n, err; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + + spin_lock(&cow_lock); + + if(--dev->count > 0) + goto out; + + err = blkdev_put(dev->cow_bdev, BDEV_RAW); + if(err) + printk("cow_release - blkdev_put of cow device failed, " + "error = %d\n", err); + bdput(dev->cow_bdev); + dev->cow_bdev = 0; + + err = blkdev_put(dev->backing_bdev, BDEV_RAW); + if(err) + printk("cow_release - blkdev_put of backing device failed, " + "error = %d\n", err); + bdput(dev->backing_bdev); + dev->backing_bdev = 0; + + out: + spin_unlock(&cow_lock); + return(0); +} + +static int cow_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct cow *dev; + int (*dev_ioctl)(struct inode *, struct file *, unsigned int, + unsigned long); + int n; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + + dev_ioctl = dev->backing_bdev->bd_op->ioctl; + return((*dev_ioctl)(inode, file, cmd, arg)); +} + +static int cow_revalidate(kdev_t rdev) +{ + printk(KERN_ERR "Need to implement cow_revalidate\n"); + return(0); +} + +static int parse_unit(char **ptr) +{ + char *str = *ptr, *end; + int n = -1; + + if(isdigit(*str)) { + n = simple_strtoul(str, &end, 0); + if(end == str) + return(-1); + *ptr = end; + } + else if (('a' <= *str) && (*str <= 'h')) { + n = *str - 'a'; + str++; + *ptr = str; + } + return(n); +} + +static int cow_setup(char *str) +{ + struct cow *dev; + char *cow_name, *backing_name; + int unit; + + unit = parse_unit(&str); + if(unit < 0){ + printk(KERN_ERR "cow_setup - Couldn't parse unit number\n"); + return(1); + } + + if(*str != '='){ + printk(KERN_ERR "cow_setup - Missing '=' after unit " + "number\n"); + return(1); + } + str++; + + cow_name = str; + backing_name = strchr(str, ','); + if(backing_name == NULL){ + printk(KERN_ERR "cow_setup - missing backing device name\n"); + return(0); + } + *backing_name = '\0'; + backing_name++; + + spin_lock(&cow_lock); + + dev = &cow_dev[unit]; + dev->cow_path = cow_name; + dev->backing_path = backing_name; + + spin_unlock(&cow_lock); + return(0); +} + +__setup("cow", cow_setup); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h new file mode 100644 index 000000000..ce251f083 --- /dev/null +++ b/arch/um/drivers/cow_sys.h @@ -0,0 +1,48 @@ +#ifndef __COW_SYS_H__ +#define __COW_SYS_H__ + +#include "kern_util.h" +#include "user_util.h" +#include "os.h" +#include "user.h" + +static inline void *cow_malloc(int size) +{ + return(um_kmalloc(size)); +} + +static inline void cow_free(void *ptr) +{ + kfree(ptr); +} + +#define cow_printf printk + +static inline char *cow_strdup(char *str) +{ + return(uml_strdup(str)); +} + +static inline int cow_seek_file(int fd, __u64 offset) +{ + return(os_seek_file(fd, offset)); +} + +static inline int cow_file_size(char *file, __u64 *size_out) +{ + return(os_file_size(file, size_out)); +} + +static inline int cow_write_file(int fd, char *buf, int size) +{ + return(os_write_file(fd, buf, size)); +} + +#endif + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index de71aec2d..024972f58 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -53,7 +53,8 @@ static int connect_to_switch(struct daemon_data *pri) struct request_v3 req; int fd, n, err; - if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ + pri->control = socket(AF_UNIX, SOCK_STREAM, 0); + if(pri->control < 0){ printk("daemon_open : control socket failed, errno = %d\n", errno); return(-errno); @@ -67,7 +68,8 @@ static int connect_to_switch(struct daemon_data *pri) goto out; } - if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if(fd < 0){ printk("daemon_open : data socket failed, errno = %d\n", errno); err = -errno; @@ -91,18 +93,18 @@ static int connect_to_switch(struct daemon_data *pri) req.version = SWITCH_VERSION; req.type = REQ_NEW_CONTROL; req.sock = *local_addr; - n = write(pri->control, &req, sizeof(req)); + n = os_write_file(pri->control, &req, sizeof(req)); if(n != sizeof(req)){ - printk("daemon_open : control setup request returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : control setup request failed, err = %d\n", + -n); err = -ENOTCONN; goto out; } - n = read(pri->control, sun, sizeof(*sun)); + n = os_read_file(pri->control, sun, sizeof(*sun)); if(n != sizeof(*sun)){ - printk("daemon_open : read of data socket returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : read of data socket failed, err = %d\n", + -n); err = -ENOTCONN; goto out_close; } @@ -111,9 +113,9 @@ static int connect_to_switch(struct daemon_data *pri) return(fd); out_close: - close(fd); + os_close_file(fd); out: - close(pri->control); + os_close_file(pri->control); return(err); } @@ -153,8 +155,8 @@ static void daemon_remove(void *data) { struct daemon_data *pri = data; - close(pri->fd); - close(pri->control); + os_close_file(pri->fd); + os_close_file(pri->control); if(pri->data_addr != NULL) kfree(pri->data_addr); if(pri->ctl_addr != NULL) kfree(pri->ctl_addr); if(pri->local_addr != NULL) kfree(pri->local_addr); diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 4ac314c1a..33c6c7868 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -35,7 +35,8 @@ void *fd_init(char *str, int device, struct chan_opts *opts) printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct fd_chan) { .fd = n, .raw = opts->raw }); return(data); diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index cbbf41b5f..3563d4ac3 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -27,10 +27,10 @@ static void pre_exec(void *d) dup2(data->stdin, 0); dup2(data->stdout, 1); dup2(data->stdout, 2); - close(data->stdin); - close(data->stdout); - close(data->close_me[0]); - close(data->close_me[1]); + os_close_file(data->stdin); + os_close_file(data->stdout); + os_close_file(data->close_me[0]); + os_close_file(data->close_me[1]); } int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) @@ -44,15 +44,15 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) char **args = NULL; err = os_pipe(in_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out; } err = os_pipe(out_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out_close_in; } data.stdin = out_fds[0]; @@ -72,42 +72,47 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) pid = run_helper(pre_exec, &data, args, NULL); - close(out_fds[0]); - close(in_fds[1]); + os_close_file(out_fds[0]); + os_close_file(in_fds[1]); if(pid < 0){ err = -pid; - printk("harddog_open - run_helper failed, errno = %d\n", err); - goto out; + printk("harddog_open - run_helper failed, errno = %d\n", -err); + goto out_close_out; } - n = read(in_fds[0], &c, sizeof(c)); + n = os_read_file(in_fds[0], &c, sizeof(c)); if(n == 0){ printk("harddog_open - EOF on watchdog pipe\n"); helper_wait(pid); err = -EIO; - goto out; + goto out_close_out; } else if(n < 0){ printk("harddog_open - read of watchdog pipe failed, " - "errno = %d\n", errno); + "err = %d\n", -n); helper_wait(pid); - err = -errno; - goto out; + err = n; + goto out_close_out; } *in_fd_ret = in_fds[0]; *out_fd_ret = out_fds[1]; return(0); + + out_close_in: + os_close_file(in_fds[0]); + os_close_file(in_fds[1]); + out_close_out: + os_close_file(out_fds[0]); + os_close_file(out_fds[1]); out: - close(out_fds[1]); - close(in_fds[0]); return(err); } void stop_watchdog(int in_fd, int out_fd) { - close(in_fd); - close(out_fd); + os_close_file(in_fd); + os_close_file(out_fd); } int ping_watchdog(int fd) @@ -115,11 +120,12 @@ int ping_watchdog(int fd) int n; char c = '\n'; - n = write(fd, &c, sizeof(c)); - if(n < sizeof(c)){ - printk("ping_watchdog - write failed, errno = %d\n", - errno); - return(-errno); + n = os_write_file(fd, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("ping_watchdog - write failed, err = %d\n", -n); + if(n < 0) + return(n); + return(-EIO); } return 1; diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index b512783a4..9f9ae2730 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -5,12 +5,12 @@ #include "linux/config.h" #include "linux/module.h" -#include "linux/version.h" #include "linux/init.h" #include "linux/slab.h" #include "linux/fs.h" #include "linux/sound.h" #include "linux/soundcard.h" +#include "asm/uaccess.h" #include "kern_util.h" #include "init.h" #include "hostaudio.h" @@ -19,30 +19,39 @@ char *dsp = HOSTAUDIO_DEV_DSP; char *mixer = HOSTAUDIO_DEV_MIXER; +#define DSP_HELP \ +" This is used to specify the host dsp device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" + +#define MIXER_HELP \ +" This is used to specify the host mixer device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" + #ifndef MODULE static int set_dsp(char *name, int *add) { - dsp = uml_strdup(name); + dsp = name; return(0); } -__uml_setup("dsp=", set_dsp, -"dsp=\n" -" This is used to specify the host dsp device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" -); +__uml_setup("dsp=", set_dsp, "dsp=\n" DSP_HELP); static int set_mixer(char *name, int *add) { - mixer = uml_strdup(name); + mixer = name; return(0); } -__uml_setup("mixer=", set_mixer, -"mixer=\n" -" This is used to specify the host mixer device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" -); +__uml_setup("mixer=", set_mixer, "mixer=\n" MIXER_HELP); + +#else /*MODULE*/ + +MODULE_PARM(dsp, "s"); +MODULE_PARM_DESC(dsp, DSP_HELP); + +MODULE_PARM(mixer, "s"); +MODULE_PARM_DESC(mixer, MIXER_HELP); + #endif /* /dev/dsp file operations */ @@ -51,23 +60,55 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int err; #ifdef DEBUG printk("hostaudio: read called, count = %d\n", count); #endif - return(hostaudio_read_user(state, buffer, count, ppos)); + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + err = hostaudio_read_user(state, kbuf, count, ppos); + if(err < 0) + goto out; + + if(copy_to_user(buffer, kbuf, err)) + err = -EFAULT; + + out: + kfree(kbuf); + return(err); } static ssize_t hostaudio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int err; #ifdef DEBUG printk("hostaudio: write called, count = %d\n", count); #endif - return(hostaudio_write_user(state, buffer, count, ppos)); + + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + err = -EFAULT; + if(copy_from_user(kbuf, buffer, count)) + goto out; + + err = hostaudio_write_user(state, kbuf, count, ppos); + if(err < 0) + goto out; + + out: + kfree(kbuf); + return(err); } static unsigned int hostaudio_poll(struct file *file, @@ -86,12 +127,43 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct hostaudio_state *state = file->private_data; + unsigned long data = 0; + int err; #ifdef DEBUG printk("hostaudio: ioctl called, cmd = %u\n", cmd); #endif - - return(hostaudio_ioctl_user(state, cmd, arg)); + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(get_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } + + err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data); + + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(put_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } + + return(err); } static int hostaudio_open(struct inode *inode, struct file *file) @@ -225,7 +297,8 @@ MODULE_LICENSE("GPL"); static int __init hostaudio_init_module(void) { - printk(KERN_INFO "UML Audio Relay\n"); + printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", + dsp, mixer); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); if(module_data.dev_audio < 0){ diff --git a/arch/um/drivers/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c index c32fa1b0a..b89fefb4a 100644 --- a/arch/um/drivers/hostaudio_user.c +++ b/arch/um/drivers/hostaudio_user.c @@ -4,9 +4,6 @@ */ #include -#include -#include -#include #include #include #include "hostaudio.h" @@ -20,45 +17,31 @@ ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, size_t count, loff_t *ppos) { - ssize_t ret; - #ifdef DEBUG printk("hostaudio: read_user called, count = %d\n", count); #endif - ret = read(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); + return(os_read_file(state->fd, buffer, count)); } ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, size_t count, loff_t *ppos) { - ssize_t ret; - #ifdef DEBUG printk("hostaudio: write_user called, count = %d\n", count); #endif - ret = write(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); + return(os_write_file(state->fd, buffer, count)); } int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, unsigned long arg) { - int ret; #ifdef DEBUG printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); #endif - ret = ioctl(state->fd, cmd, arg); - - if(ret < 0) return(-errno); - return(ret); + return(os_ioctl_generic(state->fd, cmd, arg)); } int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) @@ -67,14 +50,15 @@ int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) printk("hostaudio: open_user called\n"); #endif - state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd >= 0) return(0); + state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - printk("hostaudio_open_user failed to open '%s', errno = %d\n", - dsp, errno); + if(state->fd < 0) { + printk("hostaudio_open_user failed to open '%s', err = %d\n", + dsp, -state->fd); + return(state->fd); + } - return(-errno); + return(0); } int hostaudio_release_user(struct hostaudio_state *state) @@ -82,10 +66,10 @@ int hostaudio_release_user(struct hostaudio_state *state) #ifdef DEBUG printk("hostaudio: release called\n"); #endif - if(state->fd >= 0){ - close(state->fd); - state->fd=-1; - } + if(state->fd >= 0){ + os_close_file(state->fd); + state->fd = -1; + } return(0); } @@ -95,15 +79,11 @@ int hostaudio_release_user(struct hostaudio_state *state) int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, unsigned int cmd, unsigned long arg) { - int ret; #ifdef DEBUG printk("hostmixer: ioctl_user called cmd = %u\n",cmd); #endif - ret = ioctl(state->fd, cmd, arg); - if(ret < 0) - return(-errno); - return(ret); + return(os_ioctl_generic(state->fd, cmd, arg)); } int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, @@ -115,12 +95,13 @@ int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - if(state->fd >= 0) return(0); - - printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n", - mixer, errno); + if(state->fd < 0) { + printk("hostaudio_open_mixdev_user failed to open '%s', " + "err = %d\n", mixer, state->fd); + return(state->fd); + } - return(-errno); + return(0); } int hostmixer_release_mixdev_user(struct hostmixer_state *state) @@ -130,7 +111,7 @@ int hostmixer_release_mixdev_user(struct hostmixer_state *state) #endif if(state->fd >= 0){ - close(state->fd); + os_close_file(state->fd); state->fd = -1; } diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 92efc73ca..80b3e0e23 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -6,8 +6,8 @@ #include "linux/sched.h" #include "linux/slab.h" #include "linux/list.h" +#include "linux/interrupt.h" #include "linux/devfs_fs_kernel.h" -#include "asm/irq.h" #include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" @@ -16,38 +16,55 @@ #include "user_util.h" #include "kern_util.h" #include "os.h" +#include "irq_kern.h" #define LINE_BUFSIZE 4096 -void line_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) { struct line *dev = data; if(dev->count > 0) chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, dev); + return IRQ_HANDLED; } -void line_timer_cb(void *arg) +static void line_timer_cb(void *arg) { struct line *dev = arg; line_interrupt(dev->driver->read_irq, dev, NULL); } -static void buffer_data(struct line *line, const char *buf, int len) +static int write_room(struct line *dev) { - int end; + int n; + + if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); + + n = dev->head - dev->tail; + if(n <= 0) n = LINE_BUFSIZE + n; + return(n - 1); +} + +static int buffer_data(struct line *line, const char *buf, int len) +{ + int end, room; if(line->buffer == NULL){ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if(line->buffer == NULL){ printk("buffer_data - atomic allocation failed\n"); - return; + return(0); } line->head = line->buffer; line->tail = line->buffer; } + + room = write_room(line); + len = (len > room) ? room : len; + end = line->buffer + LINE_BUFSIZE - line->tail; if(len < end){ memcpy(line->tail, buf, len); @@ -60,6 +77,8 @@ static void buffer_data(struct line *line, const char *buf, int len) memcpy(line->buffer, buf, len); line->tail = line->buffer + len; } + + return(len); } static int flush_buffer(struct line *line) @@ -95,7 +114,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, struct line *line; char *new; unsigned long flags; - int n, err, i; + int n, err, i, ret = 0; if(tty->stopped) return 0; @@ -104,9 +123,13 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, if(new == NULL) return(0); n = copy_from_user(new, buf, len); - if(n == len) - return(-EFAULT); buf = new; + if(n == len){ + len = -EFAULT; + goto out_free; + } + + len -= n; } i = tty->index; @@ -115,41 +138,50 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, down(&line->sem); if(line->head != line->tail){ local_irq_save(flags); - buffer_data(line, buf, len); + ret += buffer_data(line, buf, len); err = flush_buffer(line); local_irq_restore(flags); if(err <= 0) - goto out; + goto out_up; } else { n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); if(n < 0){ - len = n; - goto out; + ret = n; + goto out_up; } - if(n < len) - buffer_data(line, buf + n, len - n); + + len -= n; + ret += n; + if(len > 0) + ret += buffer_data(line, buf + n, len); } - out: + out_up: up(&line->sem); - return(len); + out_free: + if(from_user) + kfree(buf); + return(ret); } -void line_write_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_write_interrupt(int irq, void *data, + struct pt_regs *unused) { struct line *dev = data; struct tty_struct *tty = dev->tty; int err; err = flush_buffer(dev); - if(err == 0) return; + if(err == 0) + return(IRQ_NONE); else if(err < 0){ dev->head = dev->buffer; dev->tail = dev->buffer; } - if(tty == NULL) return; + if(tty == NULL) + return(IRQ_NONE); if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && (tty->ldisc.write_wakeup != NULL)) @@ -161,21 +193,9 @@ void line_write_interrupt(int irq, void *data, struct pt_regs *unused) * writes. */ - if (waitqueue_active(&tty->write_wait)) + if(waitqueue_active(&tty->write_wait)) wake_up_interruptible(&tty->write_wait); - -} - -int line_write_room(struct tty_struct *tty) -{ - struct line *dev = tty->driver_data; - int n; - - if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); - - n = dev->head - dev->tail; - if(n <= 0) n = LINE_BUFSIZE + n; - return(n - 1); + return(IRQ_HANDLED); } int line_setup_irq(int fd, int input, int output, void *data) @@ -305,7 +325,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(1); + return(0); } init = end; } @@ -313,12 +333,12 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", n, num); - return(1); + return(0); } else if(n >= 0){ if(lines[n].count > 0){ printk("line_setup - device %d is open\n", n); - return(1); + return(0); } if(lines[n].init_pri <= INIT_ONE){ lines[n].init_pri = INIT_ONE; @@ -332,7 +352,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) else if(!all_allowed){ printk("line_setup - can't configure all devices from " "mconsole\n"); - return(1); + return(0); } else { for(i = 0; i < num; i++){ @@ -346,7 +366,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) } } } - return(0); + return(1); } int line_config(struct line *lines, int num, char *str) @@ -357,7 +377,7 @@ int line_config(struct line *lines, int num, char *str) printk("line_config - uml_strdup failed\n"); return(-ENOMEM); } - return(line_setup(lines, num, new, 0)); + return(!line_setup(lines, num, new, 0)); } int line_get_config(char *name, struct line *lines, int num, char *str, @@ -369,7 +389,7 @@ int line_get_config(char *name, struct line *lines, int num, char *str, dev = simple_strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - *error_out = "line_setup failed to parse device number"; + *error_out = "line_get_config failed to parse device number"; return(0); } @@ -379,15 +399,15 @@ int line_get_config(char *name, struct line *lines, int num, char *str, } line = &lines[dev]; + down(&line->sem); - if(!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if(line->count == 0) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - up(&line->sem); + return(n); } @@ -396,7 +416,14 @@ int line_remove(struct line *lines, int num, char *str) char config[sizeof("conxxxx=none\0")]; sprintf(config, "%s=none", str); - return(line_setup(lines, num, config, 0)); + return(!line_setup(lines, num, config, 0)); +} + +int line_write_room(struct tty_struct *tty) +{ + struct line *dev = tty->driver_data; + + return(write_room(dev)); } struct tty_driver *line_register_devfs(struct lines *set, @@ -412,7 +439,8 @@ struct tty_driver *line_register_devfs(struct lines *set, return NULL; driver->driver_name = line_driver->name; - driver->name = line_driver->devfs_name; + driver->name = line_driver->device_name; + driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; @@ -432,7 +460,7 @@ struct tty_driver *line_register_devfs(struct lines *set, for(i = 0; i < nlines; i++){ if(!lines[i].valid) - tty_unregister_devfs(driver, i); + tty_unregister_device(driver, i); } mconsole_register_dev(&line_driver->mc); @@ -465,24 +493,25 @@ struct winch { struct line *line; }; -void winch_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) { struct winch *winch = data; struct tty_struct *tty; int err; char c; - err = generic_read(winch->fd, &c, NULL); - if(err < 0){ - if(err != -EAGAIN){ - printk("winch_interrupt : read failed, errno = %d\n", - -err); - printk("fd %d is losing SIGWINCH support\n", - winch->tty_fd); - free_irq(irq, data); - return; + if(winch->fd != -1){ + err = generic_read(winch->fd, &c, NULL); + if(err < 0){ + if(err != -EAGAIN){ + printk("winch_interrupt : read failed, " + "errno = %d\n", -err); + printk("fd %d is losing SIGWINCH support\n", + winch->tty_fd); + return(IRQ_HANDLED); + } + goto out; } - goto out; } tty = winch->line->tty; if(tty != NULL){ @@ -492,7 +521,9 @@ void winch_interrupt(int irq, void *data, struct pt_regs *unused) kill_pg(tty->pgrp, SIGWINCH, 1); } out: - reactivate_fd(winch->fd, WINCH_IRQ); + if(winch->fd != -1) + reactivate_fd(winch->fd, WINCH_IRQ); + return(IRQ_HANDLED); } DECLARE_MUTEX(winch_handler_sem); @@ -529,7 +560,10 @@ static void winch_cleanup(void) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); - close(winch->fd); + if(winch->fd != -1){ + deactivate_fd(winch->fd, WINCH_IRQ); + os_close_file(winch->fd); + } if(winch->pid != -1) os_kill_process(winch->pid, 1); } diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index 58e5db630..0fe1d9fa9 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -23,6 +23,7 @@ #include "kern_util.h" #include "user_util.h" #include "user.h" +#include "os.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) @@ -62,7 +63,8 @@ static int mcast_open(void *data) goto out; } - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); fd = -ENOMEM; @@ -72,7 +74,7 @@ static int mcast_open(void *data) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -82,7 +84,7 @@ static int mcast_open(void *data) sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -91,7 +93,7 @@ static int mcast_open(void *data) if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -99,7 +101,7 @@ static int mcast_open(void *data) /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -115,7 +117,7 @@ static int mcast_open(void *data) "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); - close(fd); + os_close_file(fd); fd = -EINVAL; } @@ -137,7 +139,7 @@ static void mcast_close(int fd, void *data) errno); } - close(fd); + os_close_file(fd); } int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index b12cb189d..d8af1449e 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -15,6 +15,9 @@ #include "linux/sysrq.h" #include "linux/workqueue.h" #include "linux/module.h" +#include "linux/file.h" +#include "linux/fs.h" +#include "linux/namei.h" #include "linux/proc_fs.h" #include "asm/irq.h" #include "asm/uaccess.h" @@ -27,6 +30,7 @@ #include "init.h" #include "os.h" #include "umid.h" +#include "irq_kern.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -67,7 +71,7 @@ void mc_work_proc(void *unused) DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -75,9 +79,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) fd = (int) dev_id; while (mconsole_get_request(fd, &req)){ - if(req.cmd->as_interrupt) (*req.cmd->handler)(&req); + if(req.cmd->context == MCONSOLE_INTR) + (*req.cmd->handler)(&req); else { - new = kmalloc(sizeof(req), GFP_ATOMIC); + new = kmalloc(sizeof(*new), GFP_ATOMIC); if(new == NULL) mconsole_reply(&req, "Out of memory", 1, 0); else { @@ -88,6 +93,7 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); reactivate_fd(fd, MCONSOLE_IRQ); + return(IRQ_HANDLED); } void mconsole_version(struct mc_request *req) @@ -100,20 +106,109 @@ void mconsole_version(struct mc_request *req) mconsole_reply(req, version, 0, 0); } +void mconsole_log(struct mc_request *req) +{ + int len; + char *ptr = req->request.data; + + ptr += strlen("log "); + + len = req->len - (ptr - req->request.data); + printk("%.*s", len, ptr); + mconsole_reply(req, "", 0, 0); +} + +void mconsole_proc(struct mc_request *req) +{ + struct nameidata nd; + struct file_system_type *proc; + struct super_block *super; + struct file *file; + int n, err; + char *ptr = req->request.data, *buf; + + ptr += strlen("proc"); + while(isspace(*ptr)) ptr++; + + proc = get_fs_type("proc"); + if(proc == NULL){ + mconsole_reply(req, "procfs not registered", 1, 0); + goto out; + } + + super = (*proc->get_sb)(proc, 0, NULL, NULL); + put_filesystem(proc); + if(super == NULL){ + mconsole_reply(req, "Failed to get procfs superblock", 1, 0); + goto out; + } + up_write(&super->s_umount); + + nd.dentry = super->s_root; + nd.mnt = NULL; + nd.flags = O_RDONLY + 1; + nd.last_type = LAST_ROOT; + + err = link_path_walk(ptr, &nd); + if(err){ + mconsole_reply(req, "Failed to look up file", 1, 0); + goto out_kill; + } + + file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + if(IS_ERR(file)){ + mconsole_reply(req, "Failed to open file", 1, 0); + goto out_kill; + } + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + goto out_fput; + } + + if((file->f_op != NULL) && (file->f_op->read != NULL)){ + do { + n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, + &file->f_pos); + if(n >= 0){ + buf[n] = '\0'; + mconsole_reply(req, buf, 0, (n > 0)); + } + else { + mconsole_reply(req, "Read of file failed", + 1, 0); + goto out_free; + } + } while(n > 0); + } + else mconsole_reply(req, "", 0, 0); + + out_free: + kfree(buf); + out_fput: + fput(file); + out_kill: + deactivate_super(super); + out: ; +} + #define UML_MCONSOLE_HELPTEXT \ -"Commands: - version - Get kernel version - help - Print this message - halt - Halt UML - reboot - Reboot UML - config = - Add a new device to UML; - same syntax as command line - config - Query the configuration of a device - remove - Remove a device from UML - sysrq - Performs the SysRq action controlled by the letter - cad - invoke the Ctl-Alt-Del handler - stop - pause the UML; it will do nothing until it receives a 'go' - go - continue the UML after a 'stop' +"Commands: \n\ + version - Get kernel version \n\ + help - Print this message \n\ + halt - Halt UML \n\ + reboot - Reboot UML \n\ + config = - Add a new device to UML; \n\ + same syntax as command line \n\ + config - Query the configuration of a device \n\ + remove - Remove a device from UML \n\ + sysrq - Performs the SysRq action controlled by the letter \n\ + cad - invoke the Ctl-Alt-Del handler \n\ + stop - pause the UML; it will do nothing until it receives a 'go' \n\ + go - continue the UML after a 'stop' \n\ + log - make UML enter into the kernel log\n\ + proc - returns the contents of the UML's /proc/\n\ " void mconsole_help(struct mc_request *req) @@ -302,7 +397,7 @@ int mconsole_init(void) if(umid_file_name("mconsole", file, sizeof(file))) return(-1); snprintf(mconsole_socket_name, sizeof(file), "%s", file); - sock = create_unix_socket(file, sizeof(file)); + sock = os_create_unix_socket(file, sizeof(file), 1); if (sock < 0){ printk("Failed to initialize management console\n"); return(1); @@ -344,11 +439,16 @@ static int write_proc_mconsole(struct file *file, const char *buffer, if(buf == NULL) return(-ENOMEM); - if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + if(copy_from_user(buf, buffer, count)){ + count = -EFAULT; + goto out; + } + buf[count] = '\0'; mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); + out: + kfree(buf); return(count); } diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 11b09a96f..fe5afb132 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -18,16 +18,18 @@ #include "umid.h" static struct mconsole_command commands[] = { - { "version", mconsole_version, 1 }, - { "halt", mconsole_halt, 0 }, - { "reboot", mconsole_reboot, 0 }, - { "config", mconsole_config, 0 }, - { "remove", mconsole_remove, 0 }, - { "sysrq", mconsole_sysrq, 1 }, - { "help", mconsole_help, 1 }, - { "cad", mconsole_cad, 1 }, - { "stop", mconsole_stop, 0 }, - { "go", mconsole_go, 1 }, + { "version", mconsole_version, MCONSOLE_INTR }, + { "halt", mconsole_halt, MCONSOLE_PROC }, + { "reboot", mconsole_reboot, MCONSOLE_PROC }, + { "config", mconsole_config, MCONSOLE_PROC }, + { "remove", mconsole_remove, MCONSOLE_PROC }, + { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, + { "help", mconsole_help, MCONSOLE_INTR }, + { "cad", mconsole_cad, MCONSOLE_INTR }, + { "stop", mconsole_stop, MCONSOLE_PROC }, + { "go", mconsole_go, MCONSOLE_INTR }, + { "log", mconsole_log, MCONSOLE_INTR }, + { "proc", mconsole_proc, MCONSOLE_PROC }, }; /* Initialized in mconsole_init, which is an initcall */ @@ -139,6 +141,7 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more) memcpy(reply.data, str, len); reply.data[len] = '\0'; total -= len; + str += len; reply.len = len + 1; len = sizeof(reply) + reply.len - sizeof(reply.data); diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 628d8f804..1862691b9 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -120,7 +120,10 @@ static int __init mmapper_init(void) printk(KERN_INFO "Mapper v0.1\n"); v_buf = (char *) find_iomem("mmapper", &mmapper_size); - if(mmapper_size == 0) return(0); + if(mmapper_size == 0){ + printk(KERN_ERR "mmapper_init - find_iomem failed\n"); + return(0); + } p_buf = __pa(v_buf); diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index a52b79dfd..c97dbe0ee 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -26,6 +26,7 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(opened); @@ -37,7 +38,8 @@ static int uml_net_rx(struct net_device *dev) struct sk_buff *skb; /* If we can't allocate memory, try again next round. */ - if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { + skb = dev_alloc_skb(dev->mtu); + if (skb == NULL) { lp->stats.rx_dropped++; return 0; } @@ -61,14 +63,14 @@ static int uml_net_rx(struct net_device *dev) return pkt_len; } -void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct uml_net_private *lp = dev->priv; int err; if(!netif_running(dev)) - return; + return(IRQ_NONE); spin_lock(&lp->lock); while((err = uml_net_rx(dev)) > 0) ; @@ -83,6 +85,7 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) out: spin_unlock(&lp->lock); + return(IRQ_HANDLED); } static int uml_net_open(struct net_device *dev) @@ -250,37 +253,6 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } -/* - * default do nothing hard header packet routines for struct net_device init. - * real ethernet transports will overwrite with real routines. - */ -static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return(0); /* no change */ -} - -static int uml_net_rebuild_header(struct sk_buff *skb) -{ - return(0); /* ignore */ -} - -static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) -{ - return(-1); /* fail */ -} - -static void uml_net_header_cache_update(struct hh_cache *hh, - struct net_device *dev, unsigned char * haddr) -{ - /* ignore */ -} - -static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) -{ - return(0); /* nothing */ -} - static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); @@ -290,7 +262,7 @@ static int eth_configure(int n, void *init, char *mac, struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int err, size; + int save, err, size; size = transport->private_size + sizeof(struct uml_net_private) + sizeof(((struct uml_net_private *) 0)->user); @@ -332,12 +304,6 @@ static int eth_configure(int n, void *init, char *mac, snprintf(dev->name, sizeof(dev->name), "eth%d", n); device->dev = dev; - dev->hard_header = uml_net_hard_header; - dev->rebuild_header = uml_net_rebuild_header; - dev->hard_header_cache = uml_net_header_cache; - dev->header_cache_update= uml_net_header_cache_update; - dev->hard_header_parse = uml_net_header_parse; - (*transport->kern->init)(dev, init); dev->mtu = transport->user->max_packet; @@ -364,21 +330,29 @@ static int eth_configure(int n, void *init, char *mac, } lp = dev->priv; - INIT_LIST_HEAD(&lp->list); - spin_lock_init(&lp->lock); - lp->dev = dev; - lp->fd = -1; - lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; - lp->have_mac = device->have_mac; - lp->protocol = transport->kern->protocol; - lp->open = transport->user->open; - lp->close = transport->user->close; - lp->remove = transport->user->remove; - lp->read = transport->kern->read; - lp->write = transport->kern->write; - lp->add_address = transport->user->add_address; - lp->delete_address = transport->user->delete_address; - lp->set_mtu = transport->user->set_mtu; + /* lp.user is the first four bytes of the transport data, which + * has already been initialized. This structure assignment will + * overwrite that, so we make sure that .user gets overwritten with + * what it already has. + */ + save = lp->user[0]; + *lp = ((struct uml_net_private) + { .list = LIST_HEAD_INIT(lp->list), + .lock = SPIN_LOCK_UNLOCKED, + .dev = dev, + .fd = -1, + .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, + .have_mac = device->have_mac, + .protocol = transport->kern->protocol, + .open = transport->user->open, + .close = transport->user->close, + .remove = transport->user->remove, + .read = transport->kern->read, + .write = transport->kern->write, + .add_address = transport->user->add_address, + .delete_address = transport->user->delete_address, + .set_mtu = transport->user->set_mtu, + .user = { save } }); init_timer(&lp->tl); lp->tl.function = uml_net_user_timer_expire; @@ -611,7 +585,8 @@ static int net_remove(char *str) unregister_netdev(dev); list_del(&device->list); - free_netdev(device); + kfree(device); + free_netdev(dev); return(0); } diff --git a/arch/um/drivers/net_kern.c.orig b/arch/um/drivers/net_kern.c.orig new file mode 100644 index 000000000..4c2ee09b0 --- /dev/null +++ b/arch/um/drivers/net_kern.c.orig @@ -0,0 +1,870 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * Licensed under the GPL. + */ + +#include "linux/config.h" +#include "linux/kernel.h" +#include "linux/netdevice.h" +#include "linux/rtnetlink.h" +#include "linux/skbuff.h" +#include "linux/socket.h" +#include "linux/spinlock.h" +#include "linux/module.h" +#include "linux/init.h" +#include "linux/etherdevice.h" +#include "linux/list.h" +#include "linux/inetdevice.h" +#include "linux/ctype.h" +#include "linux/bootmem.h" +#include "user_util.h" +#include "kern_util.h" +#include "net_kern.h" +#include "net_user.h" +#include "mconsole_kern.h" +#include "init.h" +#include "irq_user.h" + +static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; +LIST_HEAD(opened); + +static int uml_net_rx(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + int pkt_len; + struct sk_buff *skb; + + /* If we can't allocate memory, try again next round. */ + if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { + lp->stats.rx_dropped++; + return 0; + } + + skb->dev = dev; + skb_put(skb, dev->mtu); + skb->mac.raw = skb->data; + pkt_len = (*lp->read)(lp->fd, &skb, lp); + + if (pkt_len > 0) { + skb_trim(skb, pkt_len); + skb->protocol = (*lp->protocol)(skb); + netif_rx(skb); + + lp->stats.rx_bytes += skb->len; + lp->stats.rx_packets++; + return pkt_len; + } + + kfree_skb(skb); + return pkt_len; +} + +void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct uml_net_private *lp = dev->priv; + int err; + + if(!netif_running(dev)) + return; + + spin_lock(&lp->lock); + while((err = uml_net_rx(dev)) > 0) ; + if(err < 0) { + printk(KERN_ERR + "Device '%s' read returned %d, shutting it down\n", + dev->name, err); + dev_close(dev); + goto out; + } + reactivate_fd(lp->fd, UM_ETH_IRQ); + + out: + spin_unlock(&lp->lock); +} + +static int uml_net_open(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + char addr[sizeof("255.255.255.255\0")]; + int err; + + spin_lock(&lp->lock); + + if(lp->fd >= 0){ + err = -ENXIO; + goto out; + } + + if(!lp->have_mac){ + dev_ip_addr(dev, addr, &lp->mac[2]); + set_ether_mac(dev, lp->mac); + } + + lp->fd = (*lp->open)(&lp->user); + if(lp->fd < 0){ + err = lp->fd; + goto out; + } + + err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, + SA_INTERRUPT | SA_SHIRQ, dev->name, dev); + if(err != 0){ + printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); + if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); + lp->fd = -1; + err = -ENETUNREACH; + } + + lp->tl.data = (unsigned long) &lp->user; + netif_start_queue(dev); + + spin_lock(&opened_lock); + list_add(&lp->list, &opened); + spin_unlock(&opened_lock); + MOD_INC_USE_COUNT; + out: + spin_unlock(&lp->lock); + return(err); +} + +static int uml_net_close(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + + netif_stop_queue(dev); + spin_lock(&lp->lock); + + free_irq(dev->irq, dev); + if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); + lp->fd = -1; + spin_lock(&opened_lock); + list_del(&lp->list); + spin_unlock(&opened_lock); + + MOD_DEC_USE_COUNT; + spin_unlock(&lp->lock); + return 0; +} + +static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + unsigned long flags; + int len; + + netif_stop_queue(dev); + + spin_lock_irqsave(&lp->lock, flags); + + len = (*lp->write)(lp->fd, &skb, lp); + + if(len == skb->len) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* this is normally done in the interrupt when tx finishes */ + netif_wake_queue(dev); + } + else if(len == 0){ + netif_start_queue(dev); + lp->stats.tx_dropped++; + } + else { + netif_start_queue(dev); + printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len); + } + + spin_unlock_irqrestore(&lp->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +static struct net_device_stats *uml_net_get_stats(struct net_device *dev) +{ + struct uml_net_private *lp = dev->priv; + return &lp->stats; +} + +static void uml_net_set_multicast_list(struct net_device *dev) +{ + if (dev->flags & IFF_PROMISC) return; + else if (dev->mc_count) dev->flags |= IFF_ALLMULTI; + else dev->flags &= ~IFF_ALLMULTI; +} + +static void uml_net_tx_timeout(struct net_device *dev) +{ + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int uml_net_set_mac(struct net_device *dev, void *addr) +{ + struct uml_net_private *lp = dev->priv; + struct sockaddr *hwaddr = addr; + + spin_lock(&lp->lock); + memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); + spin_unlock(&lp->lock); + + return(0); +} + +static int uml_net_change_mtu(struct net_device *dev, int new_mtu) +{ + struct uml_net_private *lp = dev->priv; + int err = 0; + + spin_lock(&lp->lock); + + new_mtu = (*lp->set_mtu)(new_mtu, &lp->user); + if(new_mtu < 0){ + err = new_mtu; + goto out; + } + + dev->mtu = new_mtu; + + out: + spin_unlock(&lp->lock); + return err; +} + +static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return(-EINVAL); +} + +void uml_net_user_timer_expire(unsigned long _conn) +{ +#ifdef undef + struct connection *conn = (struct connection *)_conn; + + dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn); + do_connect(conn); +#endif +} + +/* + * default do nothing hard header packet routines for struct net_device init. + * real ethernet transports will overwrite with real routines. + */ +static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + return(0); /* no change */ +} + +static int uml_net_rebuild_header(struct sk_buff *skb) +{ + return(0); /* ignore */ +} + +static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + return(-1); /* fail */ +} + +static void uml_net_header_cache_update(struct hh_cache *hh, + struct net_device *dev, unsigned char * haddr) +{ + /* ignore */ +} + +static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + return(0); /* nothing */ +} + +static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; +static struct list_head devices = LIST_HEAD_INIT(devices); + +static int eth_configure(int n, void *init, char *mac, + struct transport *transport) +{ + struct uml_net *device; + struct net_device *dev; + struct uml_net_private *lp; + int err, size; + + size = transport->private_size + sizeof(struct uml_net_private) + + sizeof(((struct uml_net_private *) 0)->user); + + device = kmalloc(sizeof(*device), GFP_KERNEL); + if (device == NULL) { + printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); + return(1); + } + + memset(device, 0, sizeof(*device)); + INIT_LIST_HEAD(&device->list); + device->index = n; + + spin_lock(&devices_lock); + list_add(&device->list, &devices); + spin_unlock(&devices_lock); + + if (setup_etheraddr(mac, device->mac)) + device->have_mac = 1; + + printk(KERN_INFO "Netdevice %d ", n); + if (device->have_mac) + printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", + device->mac[0], device->mac[1], + device->mac[2], device->mac[3], + device->mac[4], device->mac[5]); + printk(": "); + dev = alloc_etherdev(size); + if (dev == NULL) { + printk(KERN_ERR "eth_configure: failed to allocate device\n"); + return 1; + } + + /* If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof(dev->name), "eth%d", n); + device->dev = dev; + + dev->hard_header = uml_net_hard_header; + dev->rebuild_header = uml_net_rebuild_header; + dev->hard_header_cache = uml_net_header_cache; + dev->header_cache_update= uml_net_header_cache_update; + dev->hard_header_parse = uml_net_header_parse; + + (*transport->kern->init)(dev, init); + + dev->mtu = transport->user->max_packet; + dev->open = uml_net_open; + dev->hard_start_xmit = uml_net_start_xmit; + dev->stop = uml_net_close; + dev->get_stats = uml_net_get_stats; + dev->set_multicast_list = uml_net_set_multicast_list; + dev->tx_timeout = uml_net_tx_timeout; + dev->set_mac_address = uml_net_set_mac; + dev->change_mtu = uml_net_change_mtu; + dev->do_ioctl = uml_net_ioctl; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = UM_ETH_IRQ; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) { + device->dev = NULL; + /* XXX: should we call ->remove() here? */ + free_netdev(dev); + return 1; + } + lp = dev->priv; + + INIT_LIST_HEAD(&lp->list); + spin_lock_init(&lp->lock); + lp->dev = dev; + lp->fd = -1; + lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; + lp->have_mac = device->have_mac; + lp->protocol = transport->kern->protocol; + lp->open = transport->user->open; + lp->close = transport->user->close; + lp->remove = transport->user->remove; + lp->read = transport->kern->read; + lp->write = transport->kern->write; + lp->add_address = transport->user->add_address; + lp->delete_address = transport->user->delete_address; + lp->set_mtu = transport->user->set_mtu; + + init_timer(&lp->tl); + lp->tl.function = uml_net_user_timer_expire; + if (lp->have_mac) + memcpy(lp->mac, device->mac, sizeof(lp->mac)); + + if (transport->user->init) + (*transport->user->init)(&lp->user, dev); + + if (device->have_mac) + set_ether_mac(dev, device->mac); + return(0); +} + +static struct uml_net *find_device(int n) +{ + struct uml_net *device; + struct list_head *ele; + + spin_lock(&devices_lock); + list_for_each(ele, &devices){ + device = list_entry(ele, struct uml_net, list); + if(device->index == n) + goto out; + } + device = NULL; + out: + spin_unlock(&devices_lock); + return(device); +} + +static int eth_parse(char *str, int *index_out, char **str_out) +{ + char *end; + int n; + + n = simple_strtoul(str, &end, 0); + if(end == str){ + printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str); + return(1); + } + if(n < 0){ + printk(KERN_ERR "eth_setup: device %d is negative\n", n); + return(1); + } + str = end; + if(*str != '='){ + printk(KERN_ERR + "eth_setup: expected '=' after device number\n"); + return(1); + } + str++; + if(find_device(n)){ + printk(KERN_ERR "eth_setup: Device %d already configured\n", + n); + return(1); + } + if(index_out) *index_out = n; + *str_out = str; + return(0); +} + +struct eth_init { + struct list_head list; + char *init; + int index; +}; + +/* Filled in at boot time. Will need locking if the transports become + * modular. + */ +struct list_head transports = LIST_HEAD_INIT(transports); + +/* Filled in during early boot */ +struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); + +static int check_transport(struct transport *transport, char *eth, int n, + void **init_out, char **mac_out) +{ + int len; + + len = strlen(transport->name); + if(strncmp(eth, transport->name, len)) + return(0); + + eth += len; + if(*eth == ',') + eth++; + else if(*eth != '\0') + return(0); + + *init_out = kmalloc(transport->setup_size, GFP_KERNEL); + if(*init_out == NULL) + return(1); + + if(!transport->setup(eth, mac_out, *init_out)){ + kfree(*init_out); + *init_out = NULL; + } + return(1); +} + +void register_transport(struct transport *new) +{ + struct list_head *ele, *next; + struct eth_init *eth; + void *init; + char *mac = NULL; + int match; + + list_add(&new->list, &transports); + + list_for_each_safe(ele, next, ð_cmd_line){ + eth = list_entry(ele, struct eth_init, list); + match = check_transport(new, eth->init, eth->index, &init, + &mac); + if(!match) + continue; + else if(init != NULL){ + eth_configure(eth->index, init, mac, new); + kfree(init); + } + list_del(ð->list); + } +} + +static int eth_setup_common(char *str, int index) +{ + struct list_head *ele; + struct transport *transport; + void *init; + char *mac = NULL; + + list_for_each(ele, &transports){ + transport = list_entry(ele, struct transport, list); + if(!check_transport(transport, str, index, &init, &mac)) + continue; + if(init != NULL){ + eth_configure(index, init, mac, transport); + kfree(init); + } + return(1); + } + return(0); +} + +static int eth_setup(char *str) +{ + struct eth_init *new; + int n, err; + + err = eth_parse(str, &n, &str); + if(err) return(1); + + new = alloc_bootmem(sizeof(new)); + if (new == NULL){ + printk("eth_init : alloc_bootmem failed\n"); + return(1); + } + + INIT_LIST_HEAD(&new->list); + new->index = n; + new->init = str; + + list_add_tail(&new->list, ð_cmd_line); + return(1); +} + +__setup("eth", eth_setup); +__uml_help(eth_setup, +"eth[0-9]+=,\n" +" Configure a network device.\n\n" +); + +static int eth_init(void) +{ + struct list_head *ele, *next; + struct eth_init *eth; + + list_for_each_safe(ele, next, ð_cmd_line){ + eth = list_entry(ele, struct eth_init, list); + + if(eth_setup_common(eth->init, eth->index)) + list_del(ð->list); + } + + return(1); +} + +__initcall(eth_init); + +static int net_config(char *str) +{ + int n, err; + + err = eth_parse(str, &n, &str); + if(err) return(err); + + str = uml_strdup(str); + if(str == NULL){ + printk(KERN_ERR "net_config failed to strdup string\n"); + return(-1); + } + err = !eth_setup_common(str, n); + if(err) + kfree(str); + return(err); +} + +static int net_remove(char *str) +{ + struct uml_net *device; + struct net_device *dev; + struct uml_net_private *lp; + char *end; + int n; + + n = simple_strtoul(str, &end, 0); + if((*end != '\0') || (end == str)) + return(-1); + + device = find_device(n); + if(device == NULL) + return(0); + + dev = device->dev; + lp = dev->priv; + if(lp->fd > 0) return(-1); + if(lp->remove != NULL) (*lp->remove)(&lp->user); + unregister_netdev(dev); + + list_del(&device->list); + free_netdev(device); + return(0); +} + +static struct mc_device net_mc = { + .name = "eth", + .config = net_config, + .get_config = NULL, + .remove = net_remove, +}; + +static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa = ptr; + u32 addr = ifa->ifa_address; + u32 netmask = ifa->ifa_mask; + struct net_device *dev = ifa->ifa_dev->dev; + struct uml_net_private *lp; + void (*proc)(unsigned char *, unsigned char *, void *); + unsigned char addr_buf[4], netmask_buf[4]; + + if(dev->open != uml_net_open) return(NOTIFY_DONE); + + lp = dev->priv; + + proc = NULL; + switch (event){ + case NETDEV_UP: + proc = lp->add_address; + break; + case NETDEV_DOWN: + proc = lp->delete_address; + break; + } + if(proc != NULL){ + addr_buf[0] = addr & 0xff; + addr_buf[1] = (addr >> 8) & 0xff; + addr_buf[2] = (addr >> 16) & 0xff; + addr_buf[3] = addr >> 24; + netmask_buf[0] = netmask & 0xff; + netmask_buf[1] = (netmask >> 8) & 0xff; + netmask_buf[2] = (netmask >> 16) & 0xff; + netmask_buf[3] = netmask >> 24; + (*proc)(addr_buf, netmask_buf, &lp->user); + } + return(NOTIFY_DONE); +} + +struct notifier_block uml_inetaddr_notifier = { + .notifier_call = uml_inetaddr_event, +}; + +static int uml_net_init(void) +{ + struct list_head *ele; + struct uml_net_private *lp; + struct in_device *ip; + struct in_ifaddr *in; + + mconsole_register_dev(&net_mc); + register_inetaddr_notifier(¨_inetaddr_notifier); + + /* Devices may have been opened already, so the uml_inetaddr_notifier + * didn't get a chance to run for them. This fakes it so that + * addresses which have already been set up get handled properly. + */ + list_for_each(ele, &opened){ + lp = list_entry(ele, struct uml_net_private, list); + ip = lp->dev->ip_ptr; + if(ip == NULL) continue; + in = ip->ifa_list; + while(in != NULL){ + uml_inetaddr_event(NULL, NETDEV_UP, in); + in = in->ifa_next; + } + } + + return(0); +} + +__initcall(uml_net_init); + +static void close_devices(void) +{ + struct list_head *ele; + struct uml_net_private *lp; + + list_for_each(ele, &opened){ + lp = list_entry(ele, struct uml_net_private, list); + if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); + if(lp->remove != NULL) (*lp->remove)(&lp->user); + } +} + +__uml_exitcall(close_devices); + +int setup_etheraddr(char *str, unsigned char *addr) +{ + char *end; + int i; + + if(str == NULL) + return(0); + for(i=0;i<6;i++){ + addr[i] = simple_strtoul(str, &end, 16); + if((end == str) || + ((*end != ':') && (*end != ',') && (*end != '\0'))){ + printk(KERN_ERR + "setup_etheraddr: failed to parse '%s' " + "as an ethernet address\n", str); + return(0); + } + str = end + 1; + } + if(addr[0] & 1){ + printk(KERN_ERR + "Attempt to assign a broadcast ethernet address to a " + "device disallowed\n"); + return(0); + } + return(1); +} + +void dev_ip_addr(void *d, char *buf, char *bin_buf) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + u32 addr; + + if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ + printk(KERN_WARNING "dev_ip_addr - device not assigned an " + "IP address\n"); + return; + } + addr = in->ifa_address; + sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, + (addr >> 16) & 0xff, addr >> 24); + if(bin_buf){ + bin_buf[0] = addr & 0xff; + bin_buf[1] = (addr >> 8) & 0xff; + bin_buf[2] = (addr >> 16) & 0xff; + bin_buf[3] = addr >> 24; + } +} + +void set_ether_mac(void *d, unsigned char *addr) +{ + struct net_device *dev = d; + + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + +struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) +{ + if((skb != NULL) && (skb_tailroom(skb) < extra)){ + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); + dev_kfree_skb(skb); + skb = skb2; + } + if(skb != NULL) skb_put(skb, extra); + return(skb); +} + +void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, + void *), + void *arg) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + unsigned char address[4], netmask[4]; + + if(ip == NULL) return; + in = ip->ifa_list; + while(in != NULL){ + address[0] = in->ifa_address & 0xff; + address[1] = (in->ifa_address >> 8) & 0xff; + address[2] = (in->ifa_address >> 16) & 0xff; + address[3] = in->ifa_address >> 24; + netmask[0] = in->ifa_mask & 0xff; + netmask[1] = (in->ifa_mask >> 8) & 0xff; + netmask[2] = (in->ifa_mask >> 16) & 0xff; + netmask[3] = in->ifa_mask >> 24; + (*cb)(address, netmask, arg); + in = in->ifa_next; + } +} + +int dev_netmask(void *d, void *m) +{ + struct net_device *dev = d; + struct in_device *ip = dev->ip_ptr; + struct in_ifaddr *in; + __u32 *mask_out = m; + + if(ip == NULL) + return(1); + + in = ip->ifa_list; + if(in == NULL) + return(1); + + *mask_out = in->ifa_mask; + return(0); +} + +void *get_output_buffer(int *len_out) +{ + void *ret; + + ret = (void *) __get_free_pages(GFP_KERNEL, 0); + if(ret) *len_out = PAGE_SIZE; + else *len_out = 0; + return(ret); +} + +void free_output_buffer(void *buffer) +{ + free_pages((unsigned long) buffer, 0); +} + +int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, + char **gate_addr) +{ + char *remain; + + remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL); + if(remain != NULL){ + printk("tap_setup_common - Extra garbage on specification : " + "'%s'\n", remain); + return(1); + } + + return(0); +} + +unsigned short eth_protocol(struct sk_buff *skb) +{ + return(eth_type_trans(skb, skb->dev)); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 75a83e9e1..c9fc2862e 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -26,8 +26,7 @@ int tap_open_common(void *dev, char *gate_addr) if(gate_addr == NULL) return(0); if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ - printk("Invalid tap IP address - '%s'\n", - gate_addr); + printk("Invalid tap IP address - '%s'\n", gate_addr); return(-EINVAL); } return(0); @@ -60,18 +59,18 @@ void read_output(int fd, char *output, int len) } *output = '\0'; - if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){ - printk("read_output - read of length failed, errno = %d\n", - errno); + n = os_read_file(fd, &remain, sizeof(remain)); + if(n != sizeof(remain)){ + printk("read_output - read of length failed, err = %d\n", -n); return; } while(remain != 0){ n = (remain < len) ? remain : len; - actual = read(fd, output, n); + actual = os_read_file(fd, output, n); if(actual != n){ printk("read_output - read of data failed, " - "errno = %d\n", errno); + "err = %d\n", -actual); return; } remain -= actual; @@ -83,13 +82,12 @@ int net_read(int fd, void *buf, int len) { int n; - while(((n = read(fd, buf, len)) < 0) && (errno == EINTR)) ; + n = os_read_file(fd, buf, len); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); return(n); } @@ -112,13 +110,13 @@ int net_write(int fd, void *buf, int len) { int n; - while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ; - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); - return(n); + n = os_write_file(fd, buf, len); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); + return(n); } int net_send(int fd, void *buf, int len) @@ -157,7 +155,7 @@ static void change_pre_exec(void *arg) { struct change_pre_exec_data *data = arg; - close(data->close_me); + os_close_file(data->close_me); dup2(data->stdout, 1); } @@ -167,15 +165,15 @@ static int change_tramp(char **argv, char *output, int output_len) struct change_pre_exec_data pe_data; err = os_pipe(fds, 1, 0); - if(err){ - printk("change_tramp - pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("change_tramp - pipe failed, err = %d\n", -err); return(err); } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); waitpid(pid, NULL, 0); return(pid); diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index d361554eb..66b2fbe3d 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -5,7 +5,6 @@ #include #include -#include #include "chan_user.h" #include "os.h" diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 3c4463019..4044053cd 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -6,6 +6,7 @@ #include "linux/list.h" #include "linux/sched.h" #include "linux/slab.h" +#include "linux/interrupt.h" #include "linux/irq.h" #include "linux/spinlock.h" #include "linux/errno.h" @@ -14,6 +15,7 @@ #include "kern_util.h" #include "kern.h" #include "irq_user.h" +#include "irq_kern.h" #include "port.h" #include "init.h" #include "os.h" @@ -38,21 +40,21 @@ struct port_dev { struct connection { struct list_head list; int fd; - int helper_pid; + int helper_pid; int socket[2]; int telnetd_pid; struct port_list *port; }; -static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) { struct connection *conn = data; int fd; - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); + fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ if(fd == -EAGAIN) - return; + return(IRQ_NONE); printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", -fd); @@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) list_add(&conn->list, &conn->port->connections); up(&conn->port->sem); + return(IRQ_HANDLED); } static int port_accept(struct port_list *port) @@ -102,8 +105,7 @@ static int port_accept(struct port_list *port) } list_add(&conn->list, &port->pending); - ret = 1; - goto out; + return(1); out_free: kfree(conn); @@ -138,12 +140,13 @@ void port_work_proc(void *unused) DECLARE_WORK(port_work, port_work_proc, NULL); -static void port_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs) { struct port_list *port = data; port->has_connection = 1; schedule_work(&port_work); + return(IRQ_HANDLED); } void *port_data(int port_num) diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 7a37cf6a2..8dbad9412 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -47,10 +47,12 @@ void *port_init(char *str, int device, struct chan_opts *opts) return(NULL); } - if((kern_data = port_data(port)) == NULL) + kern_data = port_data(port); + if(kern_data == NULL) return(NULL); - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) goto err; *data = ((struct port_chan) { .raw = opts->raw, @@ -90,7 +92,7 @@ void port_close(int fd, void *d) struct port_chan *data = d; port_remove_dev(data->kernel_data); - close(fd); + os_close_file(fd); } int port_console_write(int fd, const char *buf, int n, void *d) @@ -130,11 +132,15 @@ int port_listen_fd(int port) goto out; } - if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){ + if(listen(fd, 1) < 0){ err = -errno; goto out; } + err = os_set_fd_block(fd, 0); + if(err < 0) + goto out; + return(fd); out: os_close_file(fd); @@ -153,10 +159,10 @@ void port_pre_exec(void *arg) dup2(data->sock_fd, 0); dup2(data->sock_fd, 1); dup2(data->sock_fd, 2); - close(data->sock_fd); + os_close_file(data->sock_fd); dup2(data->pipe_fd, 3); os_shutdown_socket(3, 1, 0); - close(data->pipe_fd); + os_close_file(data->pipe_fd); } int port_connection(int fd, int *socket, int *pid_out) @@ -166,11 +172,12 @@ int port_connection(int fd, int *socket, int *pid_out) "/usr/lib/uml/port-helper", NULL }; struct port_pre_exec_data data; - if((new = os_accept_connection(fd)) < 0) - return(-errno); + new = os_accept_connection(fd); + if(new < 0) + return(new); err = os_pipe(socket, 0, 0); - if(err) + if(err < 0) goto out_close; data = ((struct port_pre_exec_data) @@ -186,11 +193,11 @@ int port_connection(int fd, int *socket, int *pid_out) out_shutdown: os_shutdown_socket(socket[0], 1, 1); - close(socket[0]); + os_close_file(socket[0]); os_shutdown_socket(socket[1], 1, 1); - close(socket[1]); + os_close_file(socket[1]); out_close: - close(new); + os_close_file(new); return(err); } diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 027405386..bfa08d812 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -7,12 +7,12 @@ #include #include #include -#include #include #include "chan_user.h" #include "user.h" #include "user_util.h" #include "kern_util.h" +#include "os.h" struct pty_chan { void (*announce)(char *dev_name, int dev); @@ -26,7 +26,8 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts) { struct pty_chan *data; - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct pty_chan) { .announce = opts->announce, .dev = device, .raw = opts->raw }); @@ -39,7 +40,8 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) char *dev; int fd; - if((fd = get_pty()) < 0){ + fd = get_pty(); + if(fd < 0){ printk("open_pts : Failed to open pts\n"); return(-errno); } @@ -57,29 +59,27 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) int getmaster(char *line) { - struct stat stb; char *pty, *bank, *cp; - int master; + int master, err; pty = &line[strlen("/dev/ptyp")]; for (bank = "pqrs"; *bank; bank++) { line[strlen("/dev/pty")] = *bank; *pty = '0'; - if (stat(line, &stb) < 0) + if (os_stat_file(line, NULL) < 0) break; for (cp = "0123456789abcdef"; *cp; cp++) { *pty = *cp; - master = open(line, O_RDWR); + master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); if (master >= 0) { char *tp = &line[strlen("/dev/")]; - int ok; /* verify slave side is usable */ *tp = 't'; - ok = access(line, R_OK|W_OK) == 0; + err = os_access(line, OS_ACC_RW_OK); *tp = 'p'; - if (ok) return(master); - (void) close(master); + if(err == 0) return(master); + (void) os_close_file(master); } } } diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 782cf522b..1a5255925 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -4,11 +4,9 @@ #include #include #include -#include #include #include #include -#include #include #include "user_util.h" #include "kern_util.h" @@ -65,9 +63,9 @@ static void slip_pre_exec(void *arg) { struct slip_pre_exec_data *data = arg; - if(data->stdin != -1) dup2(data->stdin, 0); + if(data->stdin >= 0) dup2(data->stdin, 0); dup2(data->stdout, 1); - if(data->close_me != -1) close(data->close_me); + if(data->close_me >= 0) os_close_file(data->close_me); } static int slip_tramp(char **argv, int fd) @@ -77,8 +75,8 @@ static int slip_tramp(char **argv, int fd) int status, pid, fds[2], err, output_len; err = os_pipe(fds, 1, 0); - if(err){ - printk("slip_tramp : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("slip_tramp : pipe failed, err = %d\n", -err); return(err); } @@ -96,7 +94,7 @@ static int slip_tramp(char **argv, int fd) printk("slip_tramp : failed to allocate output " "buffer\n"); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); if(output != NULL){ printk("%s", output); @@ -105,7 +103,7 @@ static int slip_tramp(char **argv, int fd) if(waitpid(pid, &status, 0) < 0) err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ printk("'%s' didn't exit with status 0\n", argv[0]); - err = EINVAL; + err = -EINVAL; } } return(err); @@ -118,15 +116,17 @@ static int slip_open(void *data) char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; - int sfd, mfd, disc, sencap, err; + int sfd, mfd, err; - if((mfd = get_pty()) < 0){ - printk("umn : Failed to open pty\n"); - return(-1); + mfd = get_pty(); + if(mfd < 0){ + printk("umn : Failed to open pty, err = %d\n", -mfd); + return(mfd); } - if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("Couldn't open tty for slip line\n"); - return(-1); + sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); + if(sfd < 0){ + printk("Couldn't open tty for slip line, err = %d\n", -sfd); + return(sfd); } if(set_up_tty(sfd)) return(-1); pri->slave = sfd; @@ -138,28 +138,23 @@ static int slip_open(void *data) err = slip_tramp(argv, sfd); - if(err != 0){ - printk("slip_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("slip_tramp failed - err = %d\n", -err); + return(err); } - if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ - printk("SIOCGIFNAME failed, errno = %d\n", errno); - return(-errno); + err = os_get_ifname(pri->slave, pri->name); + if(err < 0){ + printk("get_ifname failed, err = %d\n", -err); + return(err); } iter_addresses(pri->dev, open_addr, pri->name); } else { - disc = N_SLIP; - if(ioctl(sfd, TIOCSETD, &disc) < 0){ - printk("Failed to set slip line discipline - " - "errno = %d\n", errno); - return(-errno); - } - sencap = 0; - if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to set slip encapsulation - " - "errno = %d\n", errno); - return(-errno); + err = os_set_slip(sfd); + if(err < 0){ + printk("Failed to set slip discipline encapsulation - " + "err = %d\n", -err); + return(err); } } return(mfd); @@ -181,9 +176,9 @@ static void slip_close(int fd, void *data) err = slip_tramp(argv, -1); if(err != 0) - printk("slip_tramp failed - errno = %d\n", err); - close(fd); - close(pri->slave); + printk("slip_tramp failed - errno = %d\n", -err); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; } @@ -243,7 +238,7 @@ static void slip_add_addr(unsigned char *addr, unsigned char *netmask, { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; open_addr(addr, netmask, pri->name); } @@ -252,7 +247,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask, { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; close_addr(addr, netmask, pri->name); } diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index cbdbb65c3..edb45d9b0 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -48,15 +47,15 @@ static int slirp_tramp(char **argv, int fd) return(pid); } - + +/* XXX This is just a trivial wrapper around os_pipe */ static int slirp_datachan(int *mfd, int *sfd) { int fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("slirp_datachan: Failed to open pipe, errno = %d\n", - -err); + if(err < 0){ + printk("slirp_datachan: Failed to open pipe, err = %d\n", -err); return(err); } @@ -77,7 +76,7 @@ static int slirp_open(void *data) pid = slirp_tramp(pri->argw.argv, sfd); if(pid < 0){ - printk("slirp_tramp failed - errno = %d\n", pid); + printk("slirp_tramp failed - errno = %d\n", -pid); os_close_file(sfd); os_close_file(mfd); return(pid); @@ -97,8 +96,8 @@ static void slirp_close(int fd, void *data) struct slirp_data *pri = data; int status,err; - close(fd); - close(pri->slave); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 826a77c8c..4649c4c22 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -10,6 +10,7 @@ #include "linux/major.h" #include "linux/mm.h" #include "linux/init.h" +#include "linux/console.h" #include "asm/termbits.h" #include "asm/irq.h" #include "line.h" @@ -53,8 +54,9 @@ static int ssl_remove(char *str); static struct line_driver driver = { .name = "UML serial line", - .devfs_name = "tts/%d", - .major = TTYAUX_MAJOR, + .device_name = "ttS", + .devfs_name = "tts/", + .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, .subtype = 0, @@ -149,6 +151,9 @@ static int ssl_ioctl(struct tty_struct *tty, struct file * file, case TCSETSW: case TCGETA: case TIOCMGET: + case TCSBRK: + case TCSBRKP: + case TIOCMSET: ret = -ENOIOCTLCMD; break; default: @@ -212,6 +217,37 @@ static struct tty_operations ssl_ops = { */ static int ssl_init_done = 0; +static void ssl_console_write(struct console *c, const char *string, + unsigned len) +{ + struct line *line = &serial_lines[c->index]; + if(ssl_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(ssl_init_done) + up(&line->sem); +} + +static struct tty_driver *ssl_console_device(struct console *c, int *index) +{ + *index = c->index; + return ssl_driver; +} + +static int ssl_console_setup(struct console *co, char *options) +{ + return(0); +} + +static struct console ssl_cons = { + name: "ttyS", + write: ssl_console_write, + device: ssl_console_device, + setup: ssl_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + int ssl_init(void) { char *new_title; @@ -227,17 +263,18 @@ int ssl_init(void) new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; + register_console(&ssl_cons); ssl_init_done = 1; return(0); } -__initcall(ssl_init); +late_initcall(ssl_init); static int ssl_chan_setup(char *str) { - line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), - str, 1); - return(1); + return(line_setup(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), + str, 1)); } __setup("ssl", ssl_chan_setup); diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 3ae795edf..71593674c 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -83,7 +83,8 @@ static int con_remove(char *str); static struct line_driver driver = { .name = "UML console", - .devfs_name = "vc/%d", + .device_name = "tty", + .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, @@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_struct *tty) static int con_init_done = 0; +static struct tty_operations console_ops = { + .open = con_open, + .close = con_close, + .write = con_write, + .chars_in_buffer = chars_in_buffer, + .set_termios = set_termios, + .write_room = line_write_room, +}; + int stdio_init(void) { char *new_title; @@ -166,7 +176,8 @@ int stdio_init(void) printk(KERN_INFO "Initializing stdio console driver\n"); console_driver = line_register_devfs(&console_lines, &driver, - &console_ops, vts, sizeof(vts)/sizeof(vts[0])); + &console_ops, vts, + sizeof(vts)/sizeof(vts[0])); lines_init(vts, sizeof(vts)/sizeof(vts[0])); @@ -178,24 +189,19 @@ int stdio_init(void) return(0); } -__initcall(stdio_init); +late_initcall(stdio_init); static void console_write(struct console *console, const char *string, unsigned len) { - if(con_init_done) down(&vts[console->index].sem); - console_write_chan(&vts[console->index].chan_list, string, len); - if(con_init_done) up(&vts[console->index].sem); -} + struct line *line = &vts[console->index]; -static struct tty_operations console_ops = { - .open = con_open, - .close = con_close, - .write = con_write, - .chars_in_buffer = chars_in_buffer, - .set_termios = set_termios, - .write_room = line_write_room, -}; + if(con_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(con_init_done) + up(&line->sem); +} static struct tty_driver *console_device(struct console *c, int *index) { @@ -208,22 +214,28 @@ static int console_setup(struct console *co, char *options) return(0); } -static struct console stdiocons = INIT_CONSOLE("tty", console_write, - console_device, console_setup, - CON_PRINTBUFFER); +static struct console stdiocons = { + name: "tty", + write: console_write, + device: console_device, + setup: console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; -static void __init stdio_console_init(void) +static int __init stdio_console_init(void) { INIT_LIST_HEAD(&vts[0].chan_list); list_add(&init_console_chan.list, &vts[0].chan_list); register_console(&stdiocons); + return(0); } + console_initcall(stdio_console_init); static int console_chan_setup(char *str) { - line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); - return(1); + return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1)); } __setup("con", console_chan_setup); diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index e9eb9e362..b3676e9dc 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include "chan_user.h" @@ -30,7 +29,8 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) } str++; - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct tty_chan) { .dev = str, .raw = opts->raw }); diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0c3890b3e..ee47b820f 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -8,6 +8,13 @@ * old style ubd by setting UBD_SHIFT to 0 * 2002-09-27...2002-10-18 massive tinkering for 2.5 * partitions have changed in 2.5 + * 2003-01-29 more tinkering for 2.5.59-1 + * This should now address the sysfs problems and has + * the symlink for devfs to allow for booting with + * the common /dev/ubd/discX/... names rather than + * only /dev/ubdN/discN this version also has lots of + * clean ups preparing for ubd-many. + * James McMechan */ #define MAJOR_NR UBD_MAJOR @@ -40,9 +47,12 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" #include "ubd_user.h" #include "2_5compat.h" #include "os.h" +#include "mem.h" +#include "mem_kern.h" static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED; @@ -56,6 +66,10 @@ static int ubd_ioctl(struct inode * inode, struct file * file, #define MAX_DEV (8) +/* Changed in early boot */ +static int ubd_do_mmap = 0; +#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE + static struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, @@ -67,7 +81,7 @@ static struct block_device_operations ubd_blops = { static request_queue_t *ubd_queue; /* Protected by ubd_lock */ -static int fake_major = 0; +static int fake_major = MAJOR_NR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -96,13 +110,19 @@ struct cow { struct ubd { char *file; - int is_dir; int count; int fd; __u64 size; struct openflags boot_openflags; struct openflags openflags; + int no_cow; struct cow cow; + + int map_writes; + int map_reads; + int nomap_writes; + int nomap_reads; + int write_maps; }; #define DEFAULT_COW { \ @@ -115,21 +135,28 @@ struct ubd { #define DEFAULT_UBD { \ .file = NULL, \ - .is_dir = 0, \ .count = 0, \ .fd = -1, \ .size = -1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ + .no_cow = 0, \ .cow = DEFAULT_COW, \ + .map_writes = 0, \ + .map_reads = 0, \ + .nomap_writes = 0, \ + .nomap_reads = 0, \ + .write_maps = 0, \ } struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; static int ubd0_init(void) { - if(ubd_dev[0].file == NULL) - ubd_dev[0].file = "root_fs"; + struct ubd *dev = &ubd_dev[0]; + + if(dev->file == NULL) + dev->file = "root_fs"; return(0); } @@ -196,19 +223,46 @@ __uml_help(fake_ide_setup, " Create ide0 entries that map onto ubd devices.\n\n" ); +static int parse_unit(char **ptr) +{ + char *str = *ptr, *end; + int n = -1; + + if(isdigit(*str)) { + n = simple_strtoul(str, &end, 0); + if(end == str) + return(-1); + *ptr = end; + } + else if (('a' <= *str) && (*str <= 'h')) { + n = *str - 'a'; + str++; + *ptr = str; + } + return(n); +} + static int ubd_setup_common(char *str, int *index_out) { + struct ubd *dev; struct openflags flags = global_openflags; char *backing_file; int n, err; if(index_out) *index_out = -1; - n = *str++; + n = *str; if(n == '='){ - static int fake_major_allowed = 1; char *end; int major; + str++; + if(!strcmp(str, "mmap")){ + CHOOSE_MODE(printk("mmap not supported by the ubd " + "driver in tt mode\n"), + ubd_do_mmap = 1); + return(0); + } + if(!strcmp(str, "sync")){ global_openflags.s = 1; return(0); @@ -220,20 +274,14 @@ static int ubd_setup_common(char *str, int *index_out) return(1); } - if(!fake_major_allowed){ - printk(KERN_ERR "Can't assign a fake major twice\n"); - return(1); - } - err = 1; spin_lock(&ubd_lock); - if(!fake_major_allowed){ + if(fake_major != MAJOR_NR){ printk(KERN_ERR "Can't assign a fake major twice\n"); goto out1; } fake_major = major; - fake_major_allowed = 0; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); @@ -243,25 +291,23 @@ static int ubd_setup_common(char *str, int *index_out) return(err); } - if(n < '0'){ - printk(KERN_ERR "ubd_setup : index out of range\n"); } - - if((n >= '0') && (n <= '9')) n -= '0'; - else if((n >= 'a') && (n <= 'z')) n -= 'a'; - else { - printk(KERN_ERR "ubd_setup : device syntax invalid\n"); + n = parse_unit(&str); + if(n < 0){ + printk(KERN_ERR "ubd_setup : couldn't parse unit number " + "'%s'\n", str); return(1); } if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index out of range " - "(%d devices)\n", MAX_DEV); + printk(KERN_ERR "ubd_setup : index %d out of range " + "(%d devices)\n", n, MAX_DEV); return(1); } err = 1; spin_lock(&ubd_lock); - if(ubd_dev[n].file != NULL){ + dev = &ubd_dev[n]; + if(dev->file != NULL){ printk(KERN_ERR "ubd_setup : device already configured\n"); goto out2; } @@ -276,6 +322,11 @@ static int ubd_setup_common(char *str, int *index_out) flags.s = 1; str++; } + if (*str == 'd'){ + dev->no_cow = 1; + str++; + } + if(*str++ != '='){ printk(KERN_ERR "ubd_setup : Expected '='\n"); goto out2; @@ -284,14 +335,17 @@ static int ubd_setup_common(char *str, int *index_out) err = 0; backing_file = strchr(str, ','); if(backing_file){ - *backing_file = '\0'; - backing_file++; - } - ubd_dev[n].file = str; - if(ubd_is_dir(ubd_dev[n].file)) - ubd_dev[n].is_dir = 1; - ubd_dev[n].cow.file = backing_file; - ubd_dev[n].boot_openflags = flags; + if(dev->no_cow) + printk(KERN_ERR "Can't specify both 'd' and a " + "cow file\n"); + else { + *backing_file = '\0'; + backing_file++; + } + } + dev->file = str; + dev->cow.file = backing_file; + dev->boot_openflags = flags; out2: spin_unlock(&ubd_lock); return(err); @@ -321,8 +375,7 @@ __uml_help(ubd_setup, static int fakehd_set = 0; static int fakehd(char *str) { - printk(KERN_INFO - "fakehd : Changing ubd name to \"hd\".\n"); + printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n"); fakehd_set = 1; return 1; } @@ -368,32 +421,42 @@ static void ubd_handler(void) { struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); - int n; + int n, err; do_ubd = NULL; intr_count++; n = read_ubd_fs(thread_fd, &req, sizeof(req)); if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "errno = %d\n", os_getpid(), -n); + "err = %d\n", os_getpid(), -n); spin_lock(&ubd_io_lock); end_request(rq, 0); spin_unlock(&ubd_io_lock); return; } - if((req.offset != ((__u64) (rq->sector)) << 9) || - (req.length != (rq->current_nr_sectors) << 9)) + if((req.op != UBD_MMAP) && + ((req.offset != ((__u64) (rq->sector)) << 9) || + (req.length != (rq->current_nr_sectors) << 9))) panic("I/O op mismatch"); + if(req.map_fd != -1){ + err = physmem_subst_mapping(req.buffer, req.map_fd, + req.map_offset, 1); + if(err) + printk("ubd_handler - physmem_subst_mapping failed, " + "err = %d\n", -err); + } + ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); } -static void ubd_intr(int irq, void *dev, struct pt_regs *unused) +static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) { ubd_handler(); + return(IRQ_HANDLED); } /* Only changed by ubd_init, which is an initcall. */ @@ -417,10 +480,14 @@ static int ubd_file_size(struct ubd *dev, __u64 *size_out) static void ubd_close(struct ubd *dev) { + if(ubd_do_mmap) + physmem_forget_descriptor(dev->fd); os_close_file(dev->fd); if(dev->cow.file == NULL) return; + if(ubd_do_mmap) + physmem_forget_descriptor(dev->cow.fd); os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; @@ -429,18 +496,20 @@ static void ubd_close(struct ubd *dev) static int ubd_open_dev(struct ubd *dev) { struct openflags flags; - int err, n, create_cow, *create_ptr; + char **back_ptr; + int err, create_cow, *create_ptr; + dev->openflags = dev->boot_openflags; create_cow = 0; create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, + back_ptr = dev->no_cow ? NULL : &dev->cow.file; + dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset, create_ptr); if((dev->fd == -ENOENT) && create_cow){ - n = dev - ubd_dev; dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, + dev->openflags, 1 << 9, PAGE_SIZE, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset); @@ -455,13 +524,17 @@ static int ubd_open_dev(struct ubd *dev) if(dev->cow.file != NULL){ err = -ENOMEM; dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL) goto error; + if(dev->cow.bitmap == NULL){ + printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); + goto error; + } flush_tlb_kernel_vm(); err = read_cow_bitmap(dev->fd, dev->cow.bitmap, dev->cow.bitmap_offset, dev->cow.bitmap_len); - if(err) goto error; + if(err < 0) + goto error; flags = dev->openflags; flags.w = 0; @@ -481,17 +554,31 @@ static int ubd_new_disk(int major, u64 size, int unit, { struct gendisk *disk; + char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; + int err; disk = alloc_disk(1 << UBD_SHIFT); - if (!disk) - return -ENOMEM; + if(disk == NULL) + return(-ENOMEM); disk->major = major; disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - sprintf(disk->disk_name, "ubd"); - sprintf(disk->devfs_name, "ubd/disc%d", unit); + if(major == MAJOR_NR){ + sprintf(disk->disk_name, "ubd%c", 'a' + unit); + sprintf(disk->devfs_name, "ubd/disc%d", unit); + sprintf(from, "ubd/%d", unit); + sprintf(to, "disc%d/disc", unit); + err = devfs_mk_symlink(from, to); + if(err) + printk("ubd_new_disk failed to make link from %s to " + "%s, error = %d\n", from, to, err); + } + else { + sprintf(disk->disk_name, "ubd_fake%d", unit); + sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); + } disk->private_data = &ubd_dev[unit]; disk->queue = ubd_queue; @@ -506,24 +593,21 @@ static int ubd_add(int n) struct ubd *dev = &ubd_dev[n]; int err; - if(dev->is_dir) - return(-EISDIR); - - if (!dev->file) + if(dev->file == NULL) return(-ENODEV); if (ubd_open_dev(dev)) return(-ENODEV); err = ubd_file_size(dev, &dev->size); - if(err) + if(err < 0) return(err); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); if(err) return(err); - if(fake_major) + if(fake_major != MAJOR_NR) ubd_new_disk(fake_major, dev->size, n, &fake_gendisk[n]); @@ -561,42 +645,42 @@ static int ubd_config(char *str) return(err); } -static int ubd_get_config(char *dev, char *str, int size, char **error_out) +static int ubd_get_config(char *name, char *str, int size, char **error_out) { - struct ubd *ubd; + struct ubd *dev; char *end; - int major, n = 0; + int n, len = 0; - major = simple_strtoul(dev, &end, 0); - if((*end != '\0') || (end == dev)){ - *error_out = "ubd_get_config : didn't parse major number"; + n = simple_strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + *error_out = "ubd_get_config : didn't parse device number"; return(-1); } - if((major >= MAX_DEV) || (major < 0)){ - *error_out = "ubd_get_config : major number out of range"; + if((n >= MAX_DEV) || (n < 0)){ + *error_out = "ubd_get_config : device number out of range"; return(-1); } - ubd = &ubd_dev[major]; + dev = &ubd_dev[n]; spin_lock(&ubd_lock); - if(ubd->file == NULL){ - CONFIG_CHUNK(str, size, n, "", 1); + if(dev->file == NULL){ + CONFIG_CHUNK(str, size, len, "", 1); goto out; } - CONFIG_CHUNK(str, size, n, ubd->file, 0); + CONFIG_CHUNK(str, size, len, dev->file, 0); - if(ubd->cow.file != NULL){ - CONFIG_CHUNK(str, size, n, ",", 0); - CONFIG_CHUNK(str, size, n, ubd->cow.file, 1); + if(dev->cow.file != NULL){ + CONFIG_CHUNK(str, size, len, ",", 0); + CONFIG_CHUNK(str, size, len, dev->cow.file, 1); } - else CONFIG_CHUNK(str, size, n, "", 1); + else CONFIG_CHUNK(str, size, len, "", 1); out: spin_unlock(&ubd_lock); - return(n); + return(len); } static int ubd_remove(char *str) @@ -604,11 +688,9 @@ static int ubd_remove(char *str) struct ubd *dev; int n, err = -ENODEV; - if(!isdigit(*str)) - return(err); /* it should be a number 0-7/a-h */ + n = parse_unit(&str); - n = *str - '0'; - if(n >= MAX_DEV) + if((n < 0) || (n >= MAX_DEV)) return(err); dev = &ubd_dev[n]; @@ -669,7 +751,7 @@ int ubd_init(void) elevator_init(ubd_queue, &elevator_noop); - if (fake_major != 0) { + if (fake_major != MAJOR_NR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); @@ -696,6 +778,7 @@ int ubd_driver_init(void){ io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ + io_pid = -1; printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); @@ -703,8 +786,8 @@ int ubd_driver_init(void){ } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, SA_INTERRUPT, "ubd", ubd_dev); - if(err != 0) printk(KERN_ERR - "um_request_irq failed - errno = %d\n", -err); + if(err != 0) + printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return(err); } @@ -714,15 +797,9 @@ static int ubd_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - int err = -EISDIR; - - if(dev->is_dir == 1) - goto out; + int err = 0; - err = 0; if(dev->count == 0){ - dev->openflags = dev->boot_openflags; - err = ubd_open_dev(dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", @@ -749,62 +826,156 @@ static int ubd_release(struct inode * inode, struct file * file) return(0); } -void cowify_req(struct io_thread_req *req, struct ubd *dev) +static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, + __u64 *cow_offset, unsigned long *bitmap, + __u64 bitmap_offset, unsigned long *bitmap_words, + __u64 bitmap_len) { - int i, update_bitmap, sector = req->offset >> 9; + __u64 sector = io_offset >> 9; + int i, update_bitmap = 0; + + for(i = 0; i < length >> 9; i++){ + if(cow_mask != NULL) + ubd_set_bit(i, (unsigned char *) cow_mask); + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) + continue; + + update_bitmap = 1; + ubd_set_bit(sector + i, (unsigned char *) bitmap); + } + + if(!update_bitmap) + return; + + *cow_offset = sector / (sizeof(unsigned long) * 8); + + /* This takes care of the case where we're exactly at the end of the + * device, and *cow_offset + 1 is off the end. So, just back it up + * by one word. Thanks to Lynn Kerby for the fix and James McMechan + * for the original diagnosis. + */ + if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / + sizeof(unsigned long) - 1)) + (*cow_offset)--; + + bitmap_words[0] = bitmap[*cow_offset]; + bitmap_words[1] = bitmap[*cow_offset + 1]; + + *cow_offset *= sizeof(unsigned long); + *cow_offset += bitmap_offset; +} + +static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, + __u64 bitmap_offset, __u64 bitmap_len) +{ + __u64 sector = req->offset >> 9; + int i; if(req->length > (sizeof(req->sector_mask) * 8) << 9) panic("Operation too long"); + if(req->op == UBD_READ) { for(i = 0; i < req->length >> 9; i++){ - if(ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)){ + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) ubd_set_bit(i, (unsigned char *) &req->sector_mask); - } } - } - else { - update_bitmap = 0; - for(i = 0; i < req->length >> 9; i++){ - ubd_set_bit(i, (unsigned char *) - &req->sector_mask); - if(!ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)) - update_bitmap = 1; - ubd_set_bit(sector + i, (unsigned char *) - dev->cow.bitmap); - } - if(update_bitmap){ - req->cow_offset = sector / (sizeof(unsigned long) * 8); - req->bitmap_words[0] = - dev->cow.bitmap[req->cow_offset]; - req->bitmap_words[1] = - dev->cow.bitmap[req->cow_offset + 1]; - req->cow_offset *= sizeof(unsigned long); - req->cow_offset += dev->cow.bitmap_offset; + } + else cowify_bitmap(req->offset, req->length, &req->sector_mask, + &req->cow_offset, bitmap, bitmap_offset, + req->bitmap_words, bitmap_len); +} + +static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) +{ + __u64 sector; + unsigned char *bitmap; + int bit, i; + + /* mmap must have been requested on the command line */ + if(!ubd_do_mmap) + return(-1); + + /* The buffer must be page aligned */ + if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + /* The request must be a page long */ + if((req->current_nr_sectors << 9) != PAGE_SIZE) + return(-1); + + if(dev->cow.file == NULL) + return(dev->fd); + + sector = offset >> 9; + bitmap = (unsigned char *) dev->cow.bitmap; + bit = ubd_test_bit(sector, bitmap); + + for(i = 1; i < req->current_nr_sectors; i++){ + if(ubd_test_bit(sector + i, bitmap) != bit) + return(-1); + } + + if(bit || (rq_data_dir(req) == WRITE)) + offset += dev->cow.data_offset; + + /* The data on disk must be page aligned */ + if((offset % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + return(bit ? dev->fd : dev->cow.fd); +} + +static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, + struct request *req, + struct io_thread_req *io_req) +{ + int err; + + if(rq_data_dir(req) == WRITE){ + /* Writes are almost no-ops since the new data is already in the + * host page cache + */ + dev->map_writes++; + if(dev->cow.file != NULL) + cowify_bitmap(io_req->offset, io_req->length, + &io_req->sector_mask, &io_req->cow_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + io_req->bitmap_words, + dev->cow.bitmap_len); + } + else { + int w; + + if((dev->cow.file != NULL) && (fd == dev->cow.fd)) + w = 0; + else w = dev->openflags.w; + + if((dev->cow.file != NULL) && (fd == dev->fd)) + offset += dev->cow.data_offset; + + err = physmem_subst_mapping(req->buffer, fd, offset, w); + if(err){ + printk("physmem_subst_mapping failed, err = %d\n", + -err); + return(1); } + dev->map_reads++; } + io_req->op = UBD_MMAP; + io_req->buffer = req->buffer; + return(0); } static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; struct ubd *dev = disk->private_data; - __u64 block; - int nsect; + __u64 offset; + int len, fd; if(req->rq_status == RQ_INACTIVE) return(1); - if(dev->is_dir){ - strcpy(req->buffer, "HOSTFS:"); - strcat(req->buffer, dev->file); - spin_lock(&ubd_io_lock); - end_request(req, 1); - spin_unlock(&ubd_io_lock); - return(1); - } - if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %s\n", disk->disk_name); @@ -814,23 +985,49 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) return(1); } - block = req->sector; - nsect = req->current_nr_sectors; + offset = ((__u64) req->sector) << 9; + len = req->current_nr_sectors << 9; - io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE; io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; io_req->fds[1] = dev->fd; + io_req->map_fd = -1; + io_req->cow_offset = -1; + io_req->offset = offset; + io_req->length = len; + io_req->error = 0; + io_req->sector_mask = 0; + + fd = mmap_fd(req, dev, io_req->offset); + if(fd > 0){ + /* If mmapping is otherwise OK, but the first access to the + * page is a write, then it's not mapped in yet. So we have + * to write the data to disk first, then we can map the disk + * page in and continue normally from there. + */ + if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ + io_req->map_fd = dev->fd; + io_req->map_offset = io_req->offset + + dev->cow.data_offset; + dev->write_maps++; + } + else return(prepare_mmap_request(dev, fd, io_req->offset, req, + io_req)); + } + + if(rq_data_dir(req) == READ) + dev->nomap_reads++; + else dev->nomap_writes++; + + io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = dev->cow.data_offset; - io_req->offset = ((__u64) block) << 9; - io_req->length = nsect << 9; io_req->buffer = req->buffer; io_req->sectorsize = 1 << 9; - io_req->sector_mask = 0; - io_req->cow_offset = -1; - io_req->error = 0; - if(dev->cow.file != NULL) cowify_req(io_req, dev); + if(dev->cow.file != NULL) + cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, + dev->cow.bitmap_len); + return(0); } @@ -841,7 +1038,7 @@ static void do_ubd_request(request_queue_t *q) int err, n; if(thread_fd == -1){ - while(!list_empty(&q->queue_head)){ + while(!elv_queue_empty(q)){ req = elv_next_request(q); err = prepare_request(req, &io_req); if(!err){ @@ -851,7 +1048,8 @@ static void do_ubd_request(request_queue_t *q) } } else { - if(do_ubd || list_empty(&q->queue_head)) return; + if(do_ubd || elv_queue_empty(q)) + return; req = elv_next_request(q); err = prepare_request(req, &io_req); if(!err){ @@ -885,7 +1083,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file, g.heads = 128; g.sectors = 32; g.cylinders = dev->size / (128 * 32 * 512); - g.start = 2; + g.start = get_start_sect(inode->i_bdev); return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); case HDIO_SET_UNMASKINTR: @@ -935,6 +1133,142 @@ static int ubd_ioctl(struct inode * inode, struct file * file, return(-EINVAL); } +static int ubd_check_remapped(int fd, unsigned long address, int is_write, + __u64 offset) +{ + __u64 bitmap_offset; + unsigned long new_bitmap[2]; + int i, err, n; + + /* If it's not a write access, we can't do anything about it */ + if(!is_write) + return(0); + + /* We have a write */ + for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ + struct ubd *dev = &ubd_dev[i]; + + if((dev->fd != fd) && (dev->cow.fd != fd)) + continue; + + /* It's a write to a ubd device */ + + if(!dev->openflags.w){ + /* It's a write access on a read-only device - probably + * shouldn't happen. If the kernel is trying to change + * something with no intention of writing it back out, + * then this message will clue us in that this needs + * fixing + */ + printk("Write access to mapped page from readonly ubd " + "device %d\n", i); + return(0); + } + + /* It's a write to a writeable ubd device - it must be COWed + * because, otherwise, the page would have been mapped in + * writeable + */ + + if(!dev->cow.file) + panic("Write fault on writeable non-COW ubd device %d", + i); + + /* It should also be an access to the backing file since the + * COW pages should be mapped in read-write + */ + + if(fd == dev->fd) + panic("Write fault on a backing page of ubd " + "device %d\n", i); + + /* So, we do the write, copying the backing data to the COW + * file... + */ + + err = os_seek_file(dev->fd, offset + dev->cow.data_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", + offset + dev->cow.data_offset, i, -err); + + n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Couldn't copy data to COW file of ubd " + "device %d, err = %d", i, -n); + + /* ... updating the COW bitmap... */ + + cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + new_bitmap, dev->cow.bitmap_len); + + err = os_seek_file(dev->fd, bitmap_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", bitmap_offset, i, -err); + + n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); + if(n != sizeof(new_bitmap)) + panic("Couldn't update bitmap of ubd device %d, " + "err = %d", i, -n); + + /* Maybe we can map the COW page in, and maybe we can't. If + * it is a pre-V3 COW file, we can't, since the alignment will + * be wrong. If it is a V3 or later COW file which has been + * moved to a system with a larger page size, then maybe we + * can't, depending on the exact location of the page. + */ + + offset += dev->cow.data_offset; + + /* Remove the remapping, putting the original anonymous page + * back. If the COW file can be mapped in, that is done. + * Otherwise, the COW page is read in. + */ + + if(!physmem_remove_mapping((void *) address)) + panic("Address 0x%lx not remapped by ubd device %d", + address, i); + if((offset % UBD_MMAP_BLOCK_SIZE) == 0) + physmem_subst_mapping((void *) address, dev->fd, + offset, 1); + else { + err = os_seek_file(dev->fd, offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of " + "ubd device %d, err = %d", offset, i, + -err); + + n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Failed to read page from offset %llx of " + "COW file of ubd device %d, err = %d", + offset, i, -n); + } + + return(1); + } + + /* It's not a write on a ubd device */ + return(0); +} + +static struct remapper ubd_remapper = { + .list = LIST_HEAD_INIT(ubd_remapper.list), + .proc = ubd_check_remapped, +}; + +static int ubd_remapper_setup(void) +{ + if(ubd_do_mmap) + register_remapper(&ubd_remapper); + + return(0); +} + +__initcall(ubd_remapper_setup); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 93b6f3e90..28458a6e6 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -11,11 +11,8 @@ #include #include #include -#include #include -#include #include -#include #include #include #include "asm/types.h" @@ -24,146 +21,30 @@ #include "user.h" #include "ubd_user.h" #include "os.h" +#include "cow.h" #include #include -#if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -#else -#error "__BYTE_ORDER not defined" -#endif - -#define PATH_LEN_V1 256 - -struct cow_header_v1 { - int magic; - int version; - char backing_file[PATH_LEN_V1]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -#define PATH_LEN_V2 MAXPATHLEN - -struct cow_header_v2 { - unsigned long magic; - unsigned long version; - char backing_file[PATH_LEN_V2]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -union cow_header { - struct cow_header_v1 v1; - struct cow_header_v2 v2; -}; - -#define COW_MAGIC 0x4f4f4f4d /* MOOO */ -#define COW_VERSION 2 - -static void sizes(__u64 size, int sectorsize, int bitmap_offset, - unsigned long *bitmap_len_out, int *data_offset_out) -{ - *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); - - *data_offset_out = bitmap_offset + *bitmap_len_out; - *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; - *data_offset_out *= sectorsize; -} - -static int read_cow_header(int fd, int *magic_out, char **backing_file_out, - time_t *mtime_out, __u64 *size_out, - int *sectorsize_out, int *bitmap_offset_out) -{ - union cow_header *header; - char *file; - int err, n; - unsigned long version, magic; - - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("read_cow_header - Failed to allocate header\n"); - return(-ENOMEM); - } - err = -EINVAL; - n = read(fd, header, sizeof(*header)); - if(n < offsetof(typeof(header->v1), backing_file)){ - printk("read_cow_header - short header\n"); - goto out; - } - - magic = header->v1.magic; - if(magic == COW_MAGIC) { - version = header->v1.version; - } - else if(magic == ntohl(COW_MAGIC)){ - version = ntohl(header->v1.version); - } - else goto out; - - *magic_out = COW_MAGIC; - - if(version == 1){ - if(n < sizeof(header->v1)){ - printk("read_cow_header - failed to read V1 header\n"); - goto out; - } - *mtime_out = header->v1.mtime; - *size_out = header->v1.size; - *sectorsize_out = header->v1.sectorsize; - *bitmap_offset_out = sizeof(header->v1); - file = header->v1.backing_file; - } - else if(version == 2){ - if(n < sizeof(header->v2)){ - printk("read_cow_header - failed to read V2 header\n"); - goto out; - } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); - *bitmap_offset_out = sizeof(header->v2); - file = header->v2.backing_file; - } - else { - printk("read_cow_header - invalid COW version\n"); - goto out; - } - err = -ENOMEM; - *backing_file_out = uml_strdup(file); - if(*backing_file_out == NULL){ - printk("read_cow_header - failed to allocate backing file\n"); - goto out; - } - err = 0; - out: - kfree(header); - return(err); -} static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { - struct stat buf1, buf2; + struct uml_stat buf1, buf2; + int err; if(from_cmdline == NULL) return(1); if(!strcmp(from_cmdline, from_cow)) return(1); - if(stat(from_cmdline, &buf1) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cmdline, - errno); + err = os_stat_file(from_cmdline, &buf1); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); return(1); } - if(stat(from_cow, &buf2) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cow, errno); + err = os_stat_file(from_cow, &buf2); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cow, -err); return(1); } - if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino)) + if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) return(1); printk("Backing file mismatch - \"%s\" requested,\n" @@ -174,20 +55,21 @@ static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) static int backing_file_mismatch(char *file, __u64 size, time_t mtime) { - struct stat64 buf; + unsigned long modtime; long long actual; int err; - if(stat64(file, &buf) < 0){ - printk("Failed to stat backing file \"%s\", errno = %d\n", - file, errno); - return(-errno); + err = os_file_modtime(file, &modtime); + if(err < 0){ + printk("Failed to get modification time of backing file " + "\"%s\", err = %d\n", file, -err); + return(err); } err = os_file_size(file, &actual); - if(err){ + if(err < 0){ printk("Failed to get size of backing file \"%s\", " - "errno = %d\n", file, -err); + "err = %d\n", file, -err); return(err); } @@ -196,9 +78,9 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime) "file\n", size, actual); return(-EINVAL); } - if(buf.st_mtime != mtime){ + if(modtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", mtime, buf.st_mtime); + "file\n", mtime, modtime); return(-EINVAL); } return(0); @@ -209,124 +91,16 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len) int err; err = os_seek_file(fd, offset); - if(err != 0) return(-errno); - err = read(fd, buf, len); - if(err < 0) return(-errno); - return(0); -} + if(err < 0) + return(err); -static int absolutize(char *to, int size, char *from) -{ - char save_cwd[256], *slash; - int remaining; + err = os_read_file(fd, buf, len); + if(err < 0) + return(err); - if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { - printk("absolutize : unable to get cwd - errno = %d\n", errno); - return(-1); - } - slash = strrchr(from, '/'); - if(slash != NULL){ - *slash = '\0'; - if(chdir(from)){ - *slash = '/'; - printk("absolutize : Can't cd to '%s' - errno = %d\n", - from, errno); - return(-1); - } - *slash = '/'; - if(getcwd(to, size) == NULL){ - printk("absolutize : unable to get cwd of '%s' - " - "errno = %d\n", from, errno); - return(-1); - } - remaining = size - strlen(to); - if(strlen(slash) + 1 > remaining){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcat(to, slash); - } - else { - if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcpy(to, save_cwd); - strcat(to, "/"); - strcat(to, from); - } - chdir(save_cwd); return(0); } -static int write_cow_header(char *cow_file, int fd, char *backing_file, - int sectorsize, long long *size) -{ - struct cow_header_v2 *header; - struct stat64 buf; - int err; - - err = os_seek_file(fd, 0); - if(err != 0){ - printk("write_cow_header - lseek failed, errno = %d\n", errno); - return(-errno); - } - - err = -ENOMEM; - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("Failed to allocate COW V2 header\n"); - goto out; - } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); - - err = -EINVAL; - if(strlen(backing_file) > sizeof(header->backing_file) - 1){ - printk("Backing file name \"%s\" is too long - names are " - "limited to %d characters\n", backing_file, - sizeof(header->backing_file) - 1); - goto out_free; - } - - if(absolutize(header->backing_file, sizeof(header->backing_file), - backing_file)) - goto out_free; - - err = stat64(header->backing_file, &buf); - if(err < 0){ - printk("Stat of backing file '%s' failed, errno = %d\n", - header->backing_file, errno); - err = -errno; - goto out_free; - } - - err = os_file_size(header->backing_file, size); - if(err){ - printk("Couldn't get size of backing file '%s', errno = %d\n", - header->backing_file, -*size); - goto out_free; - } - - header->mtime = htonl(buf.st_mtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - - err = write(fd, header, sizeof(*header)); - if(err != sizeof(*header)){ - printk("Write of header to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_free; - } - err = 0; - out_free: - kfree(header); - out: - return(err); -} - int open_ubd_file(char *file, struct openflags *openflags, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, @@ -334,26 +108,36 @@ int open_ubd_file(char *file, struct openflags *openflags, { time_t mtime; __u64 size; + __u32 version, align; char *backing_file; - int fd, err, sectorsize, magic, same, mode = 0644; + int fd, err, sectorsize, same, mode = 0644; - if((fd = os_open_file(file, *openflags, mode)) < 0){ + fd = os_open_file(file, *openflags, mode); + if(fd < 0){ if((fd == -ENOENT) && (create_cow_out != NULL)) *create_cow_out = 1; if(!openflags->w || ((errno != EROFS) && (errno != EACCES))) return(-errno); openflags->w = 0; - if((fd = os_open_file(file, *openflags, mode)) < 0) + fd = os_open_file(file, *openflags, mode); + if(fd < 0) return(fd); } + + err = os_lock_file(fd, openflags->w); + if(err < 0){ + printk("Failed to lock '%s', err = %d\n", file, -err); + goto out_close; + } + if(backing_file_out == NULL) return(fd); - err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, - §orsize, bitmap_offset_out); + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &align, bitmap_offset_out); if(err && (*backing_file_out != NULL)){ printk("Failed to read COW header from COW file \"%s\", " - "errno = %d\n", file, err); - goto error; + "errno = %d\n", file, -err); + goto out_close; } if(err) return(fd); @@ -363,36 +147,33 @@ int open_ubd_file(char *file, struct openflags *openflags, if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ printk("Switching backing file to '%s'\n", *backing_file_out); - err = write_cow_header(file, fd, *backing_file_out, - sectorsize, &size); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); if(err){ - printk("Switch failed, errno = %d\n", err); + printk("Switch failed, errno = %d\n", -err); return(err); } } else { *backing_file_out = backing_file; err = backing_file_mismatch(*backing_file_out, size, mtime); - if(err) goto error; + if(err) goto out_close; } - sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, - data_offset_out); + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); return(fd); - error: - close(fd); + out_close: + os_close_file(fd); return(err); } int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int *bitmap_offset_out, + int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out) { - __u64 blocks; - long zero; - int err, fd, i; - long long size; + int err, fd; flags.c = 1; fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); @@ -403,57 +184,49 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, goto out; } - err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size); - if(err) goto out_close; - - blocks = (size + sectorsize - 1) / sectorsize; - blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8); - zero = 0; - for(i = 0; i < blocks; i++){ - err = write(fd, &zero, sizeof(zero)); - if(err != sizeof(zero)){ - printk("Write of bitmap to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_close; - } - } - - sizes(size, sectorsize, sizeof(struct cow_header_v2), - bitmap_len_out, data_offset_out); - *bitmap_offset_out = sizeof(struct cow_header_v2); - - return(fd); - - out_close: - close(fd); + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, + bitmap_offset_out, bitmap_len_out, + data_offset_out); + if(!err) + return(fd); + os_close_file(fd); out: return(err); } +/* XXX Just trivial wrappers around os_read_file and os_write_file */ int read_ubd_fs(int fd, void *buffer, int len) { - int n; - - n = read(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_read_file(fd, buffer, len)); } int write_ubd_fs(int fd, char *buffer, int len) { - int n; - - n = write(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_write_file(fd, buffer, len)); } -int ubd_is_dir(char *file) +static int update_bitmap(struct io_thread_req *req) { - struct stat64 buf; + int n; + + if(req->cow_offset == -1) + return(0); + + n = os_seek_file(req->fds[1], req->cow_offset); + if(n < 0){ + printk("do_io - bitmap lseek failed : err = %d\n", -n); + return(1); + } + + n = os_write_file(req->fds[1], &req->bitmap_words, + sizeof(req->bitmap_words)); + if(n != sizeof(req->bitmap_words)){ + printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, + req->fds[1]); + return(1); + } - if(stat64(file, &buf) < 0) return(0); - return(S_ISDIR(buf.st_mode)); + return(0); } void do_io(struct io_thread_req *req) @@ -461,8 +234,18 @@ void do_io(struct io_thread_req *req) char *buf; unsigned long len; int n, nsectors, start, end, bit; + int err; __u64 off; + if(req->op == UBD_MMAP){ + /* Touch the page to force the host to do any necessary IO to + * get it into memory + */ + n = *((volatile int *) req->buffer); + req->error = update_bitmap(req); + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -473,15 +256,14 @@ void do_io(struct io_thread_req *req) &req->sector_mask) == bit)) end++; - if(end != nsectors) - printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; buf = &req->buffer[start * req->sectorsize]; - if(os_seek_file(req->fds[bit], off) != 0){ - printk("do_io - lseek failed : errno = %d\n", errno); + err = os_seek_file(req->fds[bit], off); + if(err < 0){ + printk("do_io - lseek failed : err = %d\n", -err); req->error = 1; return; } @@ -490,11 +272,10 @@ void do_io(struct io_thread_req *req) do { buf = &buf[n]; len -= n; - n = read(req->fds[bit], buf, len); + n = os_read_file(req->fds[bit], buf, len); if (n < 0) { - printk("do_io - read returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - read failed, err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -502,11 +283,10 @@ void do_io(struct io_thread_req *req) if (n < len) memset(&buf[n], 0, len - n); } else { - n = write(req->fds[bit], buf, len); + n = os_write_file(req->fds[bit], buf, len); if(n != len){ - printk("do_io - write returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - write failed err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -515,24 +295,7 @@ void do_io(struct io_thread_req *req) start = end; } while(start < nsectors); - if(req->cow_offset != -1){ - if(os_seek_file(req->fds[1], req->cow_offset) != 0){ - printk("do_io - bitmap lseek failed : errno = %d\n", - errno); - req->error = 1; - return; - } - n = write(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); - if(n != sizeof(req->bitmap_words)){ - printk("do_io - bitmap update returned %d : " - "errno = %d fd = %d\n", n, errno, req->fds[1]); - req->error = 1; - return; - } - } - req->error = 0; - return; + req->error = update_bitmap(req); } /* Changed in start_io_thread, which is serialized by being called only @@ -550,19 +313,23 @@ int io_thread(void *arg) signal(SIGWINCH, SIG_IGN); while(1){ - n = read(kernel_fd, &req, sizeof(req)); - if(n < 0) printk("io_thread - read returned %d, errno = %d\n", - n, errno); - else if(n < sizeof(req)){ - printk("io_thread - short read : length = %d\n", n); + n = os_read_file(kernel_fd, &req, sizeof(req)); + if(n != sizeof(req)){ + if(n < 0) + printk("io_thread - read failed, fd = %d, " + "err = %d\n", kernel_fd, -n); + else { + printk("io_thread - short read, fd = %d, " + "length = %d\n", kernel_fd, n); + } continue; } io_count++; do_io(&req); - n = write(kernel_fd, &req, sizeof(req)); + n = os_write_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)) - printk("io_thread - write failed, errno = %d\n", - errno); + printk("io_thread - write failed, fd = %d, err = %d\n", + kernel_fd, -n); } } @@ -571,10 +338,11 @@ int start_io_thread(unsigned long sp, int *fd_out) int pid, fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("start_io_thread - os_pipe failed, errno = %d\n", -err); - return(-1); + if(err < 0){ + printk("start_io_thread - os_pipe failed, err = %d\n", -err); + goto out; } + kernel_fd = fds[0]; *fd_out = fds[1]; @@ -582,32 +350,19 @@ int start_io_thread(unsigned long sp, int *fd_out) NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } - return(pid); -} - -#ifdef notdef -int start_io_thread(unsigned long sp, int *fd_out) -{ - int pid; - - if((kernel_fd = get_pty()) < 0) return(-1); - raw(kernel_fd, 0); - if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){ - printk("Couldn't open tty for IO\n"); - return(-1); + goto out_close; } - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); - if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } return(pid); + + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + kernel_fd = -1; + *fd_out = -1; + out: + return(err); } -#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 59c4ba89f..dccdf3e90 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,8 @@ void *xterm_init(char *str, int device, struct chan_opts *opts) { struct xterm_chan *data; - if((data = malloc(sizeof(*data))) == NULL) return(NULL); + data = malloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct xterm_chan) { .pid = -1, .helper_pid = -1, .device = device, @@ -93,7 +93,7 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; - if(access(argv[4], X_OK)) + if(os_access(argv[4], OS_ACC_X_OK) < 0) argv[4] = "port-helper"; fd = mkstemp(file); @@ -106,13 +106,13 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) printk("xterm_open : unlink failed, errno = %d\n", errno); return(-errno); } - close(fd); + os_close_file(fd); - fd = create_unix_socket(file, sizeof(file)); + fd = os_create_unix_socket(file, sizeof(file), 1); if(fd < 0){ printk("xterm_open : create_unix_socket failed, errno = %d\n", -fd); - return(-fd); + return(fd); } sprintf(title, data->title, data->device); @@ -128,15 +128,16 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) if(data->direct_rcv) new = os_rcv_fd(fd, &data->helper_pid); else { - if((err = os_set_fd_block(fd, 0)) != 0){ + err = os_set_fd_block(fd, 0); + if(err < 0){ printk("xterm_open : failed to set descriptor " - "non-blocking, errno = %d\n", err); + "non-blocking, err = %d\n", -err); return(err); } new = xterm_fd(fd, &data->helper_pid); } if(new < 0){ - printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new); + printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); goto out; } @@ -160,7 +161,7 @@ void xterm_close(int fd, void *d) if(data->helper_pid != -1) os_kill_process(data->helper_pid, 0); data->helper_pid = -1; - close(fd); + os_close_file(fd); } void xterm_free(void *d) diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index 1b4683fe3..a94813fce 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -5,9 +5,12 @@ #include "linux/errno.h" #include "linux/slab.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "asm/irq.h" #include "irq_user.h" +#include "irq_kern.h" #include "kern_util.h" #include "os.h" #include "xterm.h" @@ -19,17 +22,18 @@ struct xterm_wait { int new_fd; }; -static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs) { struct xterm_wait *xterm = data; int fd; fd = os_rcv_fd(xterm->fd, &xterm->pid); if(fd == -EAGAIN) - return; + return(IRQ_NONE); xterm->new_fd = fd; up(&xterm->sem); + return(IRQ_HANDLED); } int xterm_fd(int socket, int *pid_out) @@ -54,7 +58,8 @@ int xterm_fd(int socket, int *pid_out) if(err){ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); - return(err); + ret = err; + goto out; } down(&data->sem); @@ -62,6 +67,7 @@ int xterm_fd(int socket, int *pid_out) ret = data->new_fd; *pid_out = data->pid; + out: kfree(data); return(ret); diff --git a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S index 361d9305a..f1df3485f 100644 --- a/arch/um/dyn.lds.S +++ b/arch/um/dyn.lds.S @@ -1,3 +1,5 @@ +#include + OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) ENTRY(_start) @@ -10,12 +12,15 @@ SECTIONS { . = START + SIZEOF_HEADERS; .interp : { *(.interp) } - . = ALIGN(4096); __binary_start = .; . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); @@ -55,7 +60,9 @@ SECTIONS } =0x90909090 .plt : { *(.plt) } .text : { - *(.text .stub .text.* .gnu.linkonce.t.*) + *(.text) + SCHED_TEXT + *(.stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0x90909090 @@ -67,7 +74,7 @@ SECTIONS #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(.init.data) } /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but diff --git a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h index 6d36d9c30..abdb015a4 100644 --- a/arch/um/include/2_5compat.h +++ b/arch/um/include/2_5compat.h @@ -6,20 +6,6 @@ #ifndef __2_5_COMPAT_H__ #define __2_5_COMPAT_H__ -#include "linux/version.h" - -#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \ - name : dev_name, \ - write : write_proc, \ - read : NULL, \ - device : device_proc, \ - setup : setup_proc, \ - flags : f, \ - index : -1, \ - cflag : 0, \ - next : NULL \ -} - #define INIT_HARDSECT(arr, maj, sizes) #define SET_PRI(task) do ; while(0) diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 09e76a308..eace6b208 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -60,12 +60,11 @@ extern void finish_fork(void); extern void paging_init(void); extern void init_flush_vm(void); extern void *syscall_sp(void *t); -extern void syscall_trace(void); +extern void syscall_trace(union uml_pt_regs *regs, int entryexit); extern int hz(void); -extern void idle_timer(void); +extern void uml_idle_timer(void); extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); extern int external_pid(void *t); -extern int pid_to_processor_id(int pid); extern void boot_timer_handler(int sig); extern void interrupt_end(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); @@ -89,9 +88,7 @@ extern int remove_gdb(void); extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); -extern void set_kmem_end(unsigned long); extern void uml_cleanup(void); -extern int pid_to_processor_id(int pid); extern void set_current(void *t); extern void lock_signalled_task(void *t); extern void IPI_handler(int cpu); @@ -100,7 +97,9 @@ extern void *get_init_task(void); extern int clear_user_proc(void *buf, int size); extern int copy_to_user_proc(void *to, void *from, int size); extern int copy_from_user_proc(void *to, void *from, int size); +extern int strlen_user_proc(char *str); extern void bus_handler(int sig, union uml_pt_regs *regs); +extern void winch(int sig, union uml_pt_regs *regs); extern long execute_syscall(void *r); extern int smp_sigio_handler(void); extern void *get_current(void); @@ -111,6 +110,8 @@ extern void arch_switch(void); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); +extern unsigned long long time_stamp(void); + #endif /* diff --git a/arch/um/include/line.h b/arch/um/include/line.h index e9783dc16..31911329f 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -9,12 +9,14 @@ #include "linux/list.h" #include "linux/workqueue.h" #include "linux/tty.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "chan_user.h" #include "mconsole_kern.h" struct line_driver { char *name; + char *device_name; char *devfs_name; short major; short minor_start; @@ -67,8 +69,6 @@ struct lines { #define LINES_INIT(n) { num : n } -extern void line_interrupt(int irq, void *data, struct pt_regs *unused); -extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h index 7eea2fac0..9fbe3083f 100644 --- a/arch/um/include/mconsole.h +++ b/arch/um/include/mconsole.h @@ -41,11 +41,13 @@ struct mconsole_notify { struct mc_request; +enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC }; + struct mconsole_command { char *command; void (*handler)(struct mc_request *req); - int as_interrupt; + enum mc_context context; }; struct mc_request @@ -77,6 +79,8 @@ extern void mconsole_sysrq(struct mc_request *req); extern void mconsole_cad(struct mc_request *req); extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); +extern void mconsole_log(struct mc_request *req); +extern void mconsole_proc(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); extern int mconsole_notify(char *sock_name, int type, const void *data, diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index bad6b30b8..10c46c389 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -1,19 +1,18 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #ifndef __MEM_H__ #define __MEM_H__ -struct vm_reserved { - struct list_head list; - unsigned long start; - unsigned long end; -}; +#include "linux/types.h" -extern void set_usable_vm(unsigned long start, unsigned long end); -extern void set_kmem_end(unsigned long new); +extern int phys_mapping(unsigned long phys, __u64 *offset_out); +extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); +extern int is_remapped(void *virt); +extern int physmem_remove_mapping(void *virt); +extern void physmem_forget_descriptor(int fd); #endif diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index d80ac354b..fe0c298c2 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -32,43 +32,38 @@ #ifndef _MEM_USER_H #define _MEM_USER_H -struct mem_region { +struct iomem_region { + struct iomem_region *next; char *driver; - unsigned long start_pfn; - unsigned long start; - unsigned long len; - void *mem_map; int fd; + int size; + unsigned long phys; + unsigned long virt; }; -extern struct mem_region *regions[]; -extern struct mem_region physmem_region; +extern struct iomem_region *iomem_regions; +extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) extern unsigned long host_task_size; extern unsigned long task_size; +extern void check_devanon(void); extern int init_mem_user(void); extern int create_mem_file(unsigned long len); -extern void setup_range(int fd, char *driver, unsigned long start, - unsigned long pfn, unsigned long total, int need_vm, - struct mem_region *region, void *reserved); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern int init_maps(struct mem_region *region); -extern int nregions(void); -extern int reserve_vm(unsigned long start, unsigned long end, void *e); +extern int init_maps(unsigned long physmem, unsigned long iomem, + unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len); -extern int setup_region(struct mem_region *region, void *entry); + unsigned long len, unsigned long highmem); extern void add_iomem(char *name, int fd, unsigned long size); -extern struct mem_region *phys_region(unsigned long phys); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); -extern int map_memory(unsigned long virt, unsigned long phys, - unsigned long len, int r, int w, int x); +extern void map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); extern int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed); extern unsigned long get_kmem_end(void); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index b9b1f0c1d..269156ede 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -17,6 +17,32 @@ #define OS_TYPE_FIFO 6 #define OS_TYPE_SOCK 7 +/* os_access() flags */ +#define OS_ACC_F_OK 0 /* Test for existence. */ +#define OS_ACC_X_OK 1 /* Test for execute permission. */ +#define OS_ACC_W_OK 2 /* Test for write permission. */ +#define OS_ACC_R_OK 4 /* Test for read permission. */ +#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ + +/* + * types taken from stat_file() in hostfs_user.c + * (if they are wrong here, they are wrong there...). + */ +struct uml_stat { + int ust_dev; /* device */ + unsigned long long ust_ino; /* inode */ + int ust_mode; /* protection */ + int ust_nlink; /* number of hard links */ + int ust_uid; /* user ID of owner */ + int ust_gid; /* group ID of owner */ + unsigned long long ust_size; /* total size, in bytes */ + int ust_blksize; /* blocksize for filesystem I/O */ + unsigned long long ust_blocks; /* number of blocks allocated */ + unsigned long ust_atime; /* time of last access */ + unsigned long ust_mtime; /* time of last modification */ + unsigned long ust_ctime; /* time of last change */ +}; + struct openflags { unsigned int r : 1; unsigned int w : 1; @@ -84,29 +110,47 @@ static inline struct openflags of_excl(struct openflags flags) flags.e = 1; return(flags); } - + static inline struct openflags of_cloexec(struct openflags flags) { flags.cl = 1; return(flags); } +extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_stat_fd(const int fd, struct uml_stat *buf); +extern int os_access(const char *file, int mode); +extern void os_print_error(int error, const char* str); +extern int os_get_exec_close(int fd, int *close_on_exec); +extern int os_set_exec_close(int fd, int close_on_exec); +extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); +extern int os_window_size(int fd, int *rows, int *cols); +extern int os_new_tty_pgrp(int fd, int pid); +extern int os_get_ifname(int fd, char *namebuf); +extern int os_set_slip(int fd); +extern int os_set_owner(int fd, int pid); +extern int os_sigio_async(int master, int slave); +extern int os_mode_fd(int fd, int mode); + extern int os_seek_file(int fd, __u64 offset); extern int os_open_file(char *file, struct openflags flags, int mode); extern int os_read_file(int fd, void *buf, int len); -extern int os_write_file(int fd, void *buf, int count); +extern int os_write_file(int fd, const void *buf, int count); extern int os_file_size(char *file, long long *size_out); +extern int os_file_modtime(char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); extern int os_set_fd_async(int fd, int owner); extern int os_set_fd_block(int fd, int blocking); extern int os_accept_connection(int fd); +extern int os_create_unix_socket(char *file, int len, int close_on_exec); extern int os_shutdown_socket(int fd, int r, int w); extern void os_close_file(int fd); extern int os_rcv_fd(int fd, int *helper_pid_out); -extern int create_unix_socket(char *file, int len); +extern int create_unix_socket(char *file, int len, int close_on_exec); extern int os_connect_socket(char *name); extern int os_file_type(char *file); extern int os_file_mode(char *file, struct openflags *mode_out); +extern int os_lock_file(int fd, int excl); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); @@ -115,11 +159,12 @@ extern void os_kill_process(int pid, int reap_child); extern void os_usr1_process(int pid); extern int os_getpid(void); -extern int os_map_memory(void *virt, int fd, unsigned long off, +extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); extern int os_protect_memory(void *addr, unsigned long len, int r, int w, int x); extern int os_unmap_memory(void *addr, int len); +extern void os_flush_stdout(void); #endif diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h index adaea4d5a..b075e543d 100644 --- a/arch/um/include/signal_user.h +++ b/arch/um/include/signal_user.h @@ -11,6 +11,8 @@ extern int signal_stack_size; extern int change_sig(int signal, int on); extern void set_sigstack(void *stack, int size); extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern int set_signals(int enable); +extern int get_signals(void); #endif diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h index 7cd983d88..cfb5fb4f5 100644 --- a/arch/um/include/skas_ptrace.h +++ b/arch/um/include/skas_ptrace.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ diff --git a/arch/um/include/sysdep-i386/frame_user.h b/arch/um/include/sysdep-i386/frame_user.h index b4065b235..13faf079a 100644 --- a/arch/um/include/sysdep-i386/frame_user.h +++ b/arch/um/include/sysdep-i386/frame_user.h @@ -56,26 +56,26 @@ static inline void setup_arch_frame(struct arch_frame_data_raw *in, * it would have to be __builtin_frame_address(1). */ -static inline unsigned long frame_restorer(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_restorer() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) /* Similarly, this returns the value of sp when the handler was first * entered. This is used to calculate the proper sp when delivering * signals. */ -static inline unsigned long frame_sp(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_sp() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) #endif diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h index 26c70cf8b..887fdb61e 100644 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ b/arch/um/include/sysdep-i386/sigcontext.h @@ -28,8 +28,8 @@ */ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) -/* These are General Protection and Page Fault */ -#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14)) +/* This is Page Fault */ +#define SEGV_IS_FIXABLE(trap) (trap == 14) #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h index 08d7c1323..4ab66ae85 100644 --- a/arch/um/include/sysdep-i386/syscalls.h +++ b/arch/um/include/sysdep-i386/syscalls.h @@ -11,39 +11,34 @@ typedef long syscall_handler_t(struct pt_regs); #define EXECUTE_SYSCALL(syscall, regs) \ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t old_mmap_i386; -extern syscall_handler_t old_select; -extern syscall_handler_t sys_ni_syscall; - #define ARCH_SYSCALLS \ - [ __NR_mmap ] = old_mmap_i386, \ - [ __NR_select ] = old_select, \ - [ __NR_vm86old ] = sys_ni_syscall, \ - [ __NR_modify_ldt ] = sys_modify_ldt, \ - [ __NR_lchown32 ] = sys_lchown, \ - [ __NR_getuid32 ] = sys_getuid, \ - [ __NR_getgid32 ] = sys_getgid, \ - [ __NR_geteuid32 ] = sys_geteuid, \ - [ __NR_getegid32 ] = sys_getegid, \ - [ __NR_setreuid32 ] = sys_setreuid, \ - [ __NR_setregid32 ] = sys_setregid, \ - [ __NR_getgroups32 ] = sys_getgroups, \ - [ __NR_setgroups32 ] = sys_setgroups, \ - [ __NR_fchown32 ] = sys_fchown, \ - [ __NR_setresuid32 ] = sys_setresuid, \ - [ __NR_getresuid32 ] = sys_getresuid, \ - [ __NR_setresgid32 ] = sys_setresgid, \ - [ __NR_getresgid32 ] = sys_getresgid, \ - [ __NR_chown32 ] = sys_chown, \ - [ __NR_setuid32 ] = sys_setuid, \ - [ __NR_setgid32 ] = sys_setgid, \ - [ __NR_setfsuid32 ] = sys_setfsuid, \ - [ __NR_setfsgid32 ] = sys_setfsgid, \ - [ __NR_pivot_root ] = sys_pivot_root, \ - [ __NR_mincore ] = sys_mincore, \ - [ __NR_madvise ] = sys_madvise, \ - [ 222 ] = sys_ni_syscall, + [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \ + [ __NR_select ] = (syscall_handler_t *) old_select, \ + [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \ + [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \ + [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \ + [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \ + [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \ + [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \ + [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \ + [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \ + [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \ + [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \ + [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \ + [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \ + [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \ + [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \ + [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \ + [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \ + [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \ + [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \ + [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \ + [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \ + [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \ + [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \ + [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \ + [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \ + [ 222 ] = (syscall_handler_t *) sys_ni_syscall, /* 222 doesn't yet have a name in include/asm-i386/unistd.h */ diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h index b28beaf58..bddccc0e3 100644 --- a/arch/um/include/ubd_user.h +++ b/arch/um/include/ubd_user.h @@ -9,7 +9,7 @@ #include "os.h" -enum ubd_req { UBD_READ, UBD_WRITE }; +enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; struct io_thread_req { enum ubd_req op; @@ -20,8 +20,10 @@ struct io_thread_req { char *buffer; int sectorsize; unsigned long sector_mask; - unsigned long cow_offset; + unsigned long long cow_offset; unsigned long bitmap_words[2]; + int map_fd; + unsigned long long map_offset; int error; }; @@ -31,7 +33,7 @@ extern int open_ubd_file(char *file, struct openflags *openflags, int *create_cow_out); extern int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, int sectorsize, - int *bitmap_offset_out, + int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); extern int read_cow_bitmap(int fd, void *buf, int offset, int len); @@ -39,7 +41,6 @@ extern int read_ubd_fs(int fd, void *buffer, int len); extern int write_ubd_fs(int fd, char *buffer, int len); extern int start_io_thread(unsigned long sp, int *fds_out); extern void do_io(struct io_thread_req *req); -extern int ubd_is_dir(char *file); static inline int ubd_test_bit(__u64 bit, unsigned char *data) { diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index 41afa3a8f..8b36a5464 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h @@ -38,22 +38,73 @@ static inline int copy_to_user(void *to, const void *from, int n) from, n)); } +/* + * strncpy_from_user: - Copy a NUL terminated string from userspace. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Source address, in user space. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from userspace to kernel space. + * + * On success, returns the length of the string (not including the trailing + * NUL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * + * If @count is smaller than the length of the string, copies @count bytes + * and returns @count. + */ + static inline int strncpy_from_user(char *dst, const char *src, int count) { return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, dst, src, count)); } +/* + * __clear_user: - Zero a block of memory in user space, with less checking. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int __clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); } +/* + * clear_user: - Zero a block of memory in user space. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); } +/* + * strlen_user: - Get the size of a string in user space. + * @str: The string to measure. + * @n: The maximum valid length + * + * Get the size of a NUL-terminated string in user space. + * + * Returns the size of the string INCLUDING the terminating NUL. + * On exception, returns 0. + * If the string is too long, returns a value greater than @n. + */ static inline int strnlen_user(const void *str, int len) { return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 6f009be0f..e9cf19eb1 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -14,6 +14,7 @@ extern void *um_kmalloc_atomic(int size); extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); +extern int strlcpy(char *, const char *, int); #endif diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index e87b8fcb0..588012843 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -14,8 +14,6 @@ extern int grantpt(int __fd); extern int unlockpt(int __fd); extern char *ptsname(int __fd); -enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; - struct cpu_task { int pid; void *task; @@ -59,7 +57,6 @@ extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern void *add_signal_handler(int sig, void (*handler)(int)); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); -extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); extern int linux_main(int argc, char **argv); extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); @@ -86,11 +83,13 @@ extern void check_sigio(void); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); extern void write_sigio_workaround(void); extern void arch_check_bugs(void); +extern int cpu_feature(char *what, char *buf, int len); extern int arch_handle_signal(int sig, union uml_pt_regs *regs); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); extern int can_do_skas(void); - +extern void arch_init_thread(void); + #endif /* diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 0f13dd4c7..70da5fa16 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -7,11 +7,11 @@ extra-y := vmlinux.lds.s obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ - sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ - syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ - umid.o user_syms.o user_util.o + physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ + sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ + syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ + time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ + um_arch.o umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -24,43 +24,27 @@ obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ - process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o + process.o tempfile.o time.o tty_log.o umid.o user_util.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ -DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ - - -CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ - -I/usr/include -I../include - CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - # This has to be separate because it needs be compiled with frame pointers # regardless of how the rest of the kernel is built. $(obj)/frame.o: $(src)/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< -QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< -$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config - $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ +QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' $(obj)/config.o : $(obj)/config.c -clean: - rm -f config.c - for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done - -modules: - -fastdep: - -dep: - -archmrproper: clean +quiet_cmd_quote = QUOTE $@ +cmd_quote = $(PERL) -e $(QUOTE) < $< > $@ +targets += config.c +$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config FORCE + $(call if_changed,quote) diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in index f6c96b955..c062cbfe3 100644 --- a/arch/um/kernel/config.c.in +++ b/arch/um/kernel/config.c.in @@ -7,9 +7,7 @@ #include #include "init.h" -static __initdata char *config = " -CONFIG -"; +static __initdata char *config = "CONFIG"; static int __init print_config(char *line, int *add) { diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index a6be6b542..a5f21283d 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -32,10 +32,15 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } +extern void log_exec(char **argv, void *tty); + static int execve1(char *file, char **argv, char **env) { int error; +#ifdef CONFIG_TTY_LOG + log_exec(argv, current->tty); +#endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ current->ptrace &= ~PT_DTRACE; diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c index d8993f293..c18386af5 100644 --- a/arch/um/kernel/frame.c +++ b/arch/um/kernel/frame.c @@ -279,7 +279,7 @@ void capture_signal_stack(void) struct sc_frame_raw raw_sc; struct si_frame_raw raw_si; void *stack, *sigstack; - unsigned long top, sig_top, base; + unsigned long top, base; stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -292,7 +292,6 @@ void capture_signal_stack(void) } top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - sig_top = (unsigned long) sigstack + PAGE_SIZE; /* Get the sigcontext, no sigrestorer layout */ raw_sc.restorer = 0; diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index 9ff437466..24fa89383 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -6,7 +6,6 @@ #include "asm/ptrace.h" #include "asm/uaccess.h" #include "asm/signal.h" -#include "asm/uaccess.h" #include "asm/ucontext.h" #include "frame_kern.h" #include "sigcontext.h" @@ -29,12 +28,15 @@ static int copy_restorer(void (*restorer)(void), unsigned long start, sizeof(restorer))); } +extern int userspace_pid[]; + static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, struct arch_frame_data *arch) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), arch), - copy_sc_to_user_skas(to, fp, &from->regs, + copy_sc_to_user_skas(userspace_pid[0], to, fp, + &from->regs, current->thread.cr2, current->thread.err))); } diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index 5c4b27942..6d0a1f969 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -33,6 +32,7 @@ static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; + int errval; if(helper_pause){ signal(SIGHUP, helper_hup); @@ -41,8 +41,9 @@ static int helper_child(void *arg) if(data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); + errval = errno; printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); - write(data->fd, &errno, sizeof(errno)); + os_write_file(data->fd, &errval, sizeof(errval)); os_kill_process(os_getpid(), 0); return(0); } @@ -59,17 +60,20 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, if((stack_out != NULL) && (*stack_out != 0)) stack = *stack_out; else stack = alloc_stack(0, um_in_interrupt()); - if(stack == 0) return(-ENOMEM); + if(stack == 0) + return(-ENOMEM); err = os_pipe(fds, 1, 0); - if(err){ - printk("run_helper : pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("run_helper : pipe failed, err = %d\n", -err); + goto out_free; } - if(fcntl(fds[1], F_SETFD, 1) != 0){ - printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n", - errno); - return(-errno); + + err = os_set_exec_close(fds[1], 1); + if(err < 0){ + printk("run_helper : setting FD_CLOEXEC failed, err = %d\n", + -err); + goto out_close; } sp = stack + page_size() - sizeof(void *); @@ -80,23 +84,34 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if(pid < 0){ printk("run_helper : clone failed, errno = %d\n", errno); - return(-errno); + err = -errno; + goto out_close; } - close(fds[1]); - n = read(fds[0], &err, sizeof(err)); + + os_close_file(fds[1]); + n = os_read_file(fds[0], &err, sizeof(err)); if(n < 0){ - printk("run_helper : read on pipe failed, errno = %d\n", - errno); - return(-errno); + printk("run_helper : read on pipe failed, err = %d\n", -n); + err = n; + goto out_kill; } else if(n != 0){ waitpid(pid, NULL, 0); - pid = -err; + pid = -errno; } if(stack_out == NULL) free_stack(stack, 0); else *stack_out = stack; return(pid); + + out_kill: + os_kill_process(pid, 1); + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + out_free: + free_stack(stack, 0); + return(err); } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, @@ -117,9 +132,11 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, } if(stack_out == NULL){ pid = waitpid(pid, &status, 0); - if(pid < 0) + if(pid < 0){ printk("run_helper_thread - wait failed, errno = %d\n", - pid); + errno); + pid = -errno; + } if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index 7d6bb961d..f805768ea 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -8,7 +8,6 @@ #include "linux/module.h" #include "linux/sched.h" #include "linux/init_task.h" -#include "linux/version.h" #include "asm/uaccess.h" #include "asm/pgtable.h" #include "user_util.h" @@ -18,7 +17,7 @@ static struct fs_struct init_fs = INIT_FS; struct mm_struct init_mm = INIT_MM(init_mm); static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); - +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); EXPORT_SYMBOL(init_mm); /* @@ -43,26 +42,12 @@ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = { INIT_THREAD_INFO(init_task) }; -struct task_struct *alloc_task_struct(void) -{ - return((struct task_struct *) - __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER)); -} - void unprotect_stack(unsigned long stack) { protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 1, 1, 0, 1); } -void free_task_struct(struct task_struct *task) -{ - /* free_pages decrements the page counter and only actually frees - * the pages if they are now not accessed by anything. - */ - free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c index 944c734ca..265cbab78 100644 --- a/arch/um/kernel/initrd_user.c +++ b/arch/um/kernel/initrd_user.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "user_util.h" @@ -19,13 +18,15 @@ int load_initrd(char *filename, void *buf, int size) { int fd, n; - if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){ - printk("Opening '%s' failed - errno = %d\n", filename, errno); + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); return(-1); } - if((n = read(fd, buf, size)) != size){ - printk("Read of %d bytes from '%s' returned %d, errno = %d\n", - size, filename, n, errno); + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); return(-1); } return(0); diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 5f6c8502a..ed3be38cd 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -29,6 +29,7 @@ #include "user_util.h" #include "kern_util.h" #include "irq_user.h" +#include "irq_kern.h" static void register_irq_proc (unsigned int irq); @@ -83,65 +84,55 @@ struct hw_interrupt_type no_irq_type = { end_none }; -/* Not changed */ -volatile unsigned long irq_err_count; - /* * Generic, controller-independent functions: */ -int get_irq_list(char *buf) +int show_interrupts(struct seq_file *p, void *v) { - int i, j; - unsigned long flags; + int i = *(loff_t *) v, j; struct irqaction * action; - char *p = buf; + unsigned long flags; - p += sprintf(p, " "); - for (j=0; jtypename); - p += sprintf(p, " %s", action->name); + seq_printf(p, " %14s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); - *p++ = '\n'; - end: + seq_printf(p, ", %s", action->name); + + seq_putc(p, '\n'); +skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); } - p += sprintf(p, "\n"); -#ifdef notdef -#ifdef CONFIG_SMP - p += sprintf(p, "LOC: "); - for (j = 0; j < num_online_cpus(); j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); -#endif -#endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); - return p - buf; -} - -int show_interrupts(struct seq_file *p, void *v) -{ - return(0); + return 0; } /* @@ -282,13 +273,12 @@ unsigned int do_IRQ(int irq, union uml_pt_regs *regs) * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* @@ -385,7 +375,7 @@ out: */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -433,15 +423,19 @@ int request_irq(unsigned int irq, EXPORT_SYMBOL(request_irq); int um_request_irq(unsigned int irq, int fd, int type, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { - int retval; + int err; + + err = request_irq(irq, handler, irqflags, devname, dev_id); + if(err) + return(err); - retval = request_irq(irq, handler, irqflags, devname, dev_id); - if(retval) return(retval); - return(activate_fd(irq, fd, type, dev_id)); + if(fd != -1) + err = activate_fd(irq, fd, type, dev_id); + return(err); } /* this was setup_x86_irq but it seems pretty generic */ @@ -474,7 +468,8 @@ int setup_irq(unsigned int irq, struct irqaction * new) */ spin_lock_irqsave(&desc->lock,flags); p = &desc->action; - if ((old = *p) != NULL) { + old = *p; + if (old != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { spin_unlock_irqrestore(&desc->lock,flags); @@ -586,12 +581,14 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { int irq = (long) data, full_count = count, err; - cpumask_t new_value, tmp; + cpumask_t new_value; if (!irq_desc[irq].handler->set_affinity) return -EIO; err = cpumask_parse(buffer, count, new_value); + if(err) + return(err); #ifdef CONFIG_SMP /* @@ -599,9 +596,11 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) - return -EINVAL; + { cpumask_t tmp; + cpus_and(tmp, new_value, cpu_online_map); + if (cpus_empty(tmp)) + return -EINVAL; + } #endif irq_affinity[irq] = new_value; diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 57fe9bb72..87ac2b038 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,8 @@ void sigio_handler(int sig, union uml_pt_regs *regs) if(smp_sigio_handler()) return; while(1){ - if((n = poll(pollfds, pollfds_num, 0)) < 0){ + n = poll(pollfds, pollfds_num, 0); + if(n < 0){ if(errno == EINTR) continue; printk("sigio_handler : poll returned %d, " "errno = %d\n", n, errno); @@ -366,34 +366,31 @@ void deactivate_fd(int fd, int irqnum) void forward_ipi(int fd, int pid) { - if(fcntl(fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(fd, F_GETOWN, 0) != pid){ - printk("forward_ipi: F_SETOWN failed, fd = %d, " - "me = %d, target = %d, errno = %d\n", fd, - os_getpid(), pid, save_errno); - } - } + int err; + + err = os_set_owner(fd, pid); + if(err < 0) + printk("forward_ipi: set_owner failed, fd = %d, me = %d, " + "target = %d, err = %d\n", fd, os_getpid(), pid, -err); } void forward_interrupts(int pid) { struct irq_fd *irq; unsigned long flags; + int err; flags = irq_lock(); for(irq=active_fds;irq != NULL;irq = irq->next){ - if(fcntl(irq->fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(irq->fd, F_GETOWN, 0) != pid){ - /* XXX Just remove the irq rather than - * print out an infinite stream of these - */ - printk("Failed to forward %d to pid %d, " - "errno = %d\n", irq->fd, pid, - save_errno); - } + err = os_set_owner(irq->fd, pid); + if(err < 0){ + /* XXX Just remove the irq rather than + * print out an infinite stream of these + */ + printk("Failed to forward %d to pid %d, err = %d\n", + irq->fd, pid, -err); } + irq->pid = pid; } irq_unlock(flags); diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 1f82ad73a..4ed2807bc 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -8,7 +8,7 @@ #include "linux/string.h" #include "linux/smp_lock.h" #include "linux/spinlock.h" -#include +#include "linux/highmem.h" #include "asm/current.h" #include "asm/delay.h" #include "asm/processor.h" @@ -19,6 +19,7 @@ #include "asm/tlbflush.h" #include "kern_util.h" #include "user_util.h" +#include "mem_user.h" #include "os.h" #include "helper.h" @@ -34,34 +35,64 @@ EXPORT_SYMBOL(task_size); EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); +EXPORT_SYMBOL(get_kmem_end); -EXPORT_SYMBOL(region_pa); -EXPORT_SYMBOL(region_va); -EXPORT_SYMBOL(phys_mem_map); -EXPORT_SYMBOL(page_mem_map); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(um_virt_to_phys); +EXPORT_SYMBOL(__virt_to_page); +EXPORT_SYMBOL(to_phys); +EXPORT_SYMBOL(to_virt); EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); +EXPORT_SYMBOL(find_iomem); +#ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(copy_from_user_tt); +EXPORT_SYMBOL(copy_to_user_tt); +#endif + +#ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(copy_to_user_skas); +EXPORT_SYMBOL(copy_from_user_skas); +#endif + +EXPORT_SYMBOL(os_stat_fd); +EXPORT_SYMBOL(os_stat_file); +EXPORT_SYMBOL(os_access); +EXPORT_SYMBOL(os_print_error); +EXPORT_SYMBOL(os_get_exec_close); +EXPORT_SYMBOL(os_set_exec_close); EXPORT_SYMBOL(os_getpid); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); EXPORT_SYMBOL(os_write_file); EXPORT_SYMBOL(os_seek_file); +EXPORT_SYMBOL(os_lock_file); +EXPORT_SYMBOL(os_ioctl_generic); EXPORT_SYMBOL(os_pipe); EXPORT_SYMBOL(os_file_type); +EXPORT_SYMBOL(os_file_mode); +EXPORT_SYMBOL(os_file_size); +EXPORT_SYMBOL(os_flush_stdout); EXPORT_SYMBOL(os_close_file); +EXPORT_SYMBOL(os_set_fd_async); +EXPORT_SYMBOL(os_set_fd_block); EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); +EXPORT_SYMBOL(os_create_unix_socket); EXPORT_SYMBOL(os_connect_socket); +EXPORT_SYMBOL(os_accept_connection); +EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(do_gettimeofday); +EXPORT_SYMBOL(do_settimeofday); + /* This is here because UML expands open to sys_open, not to a system * call instruction. */ @@ -90,3 +121,13 @@ EXPORT_SYMBOL(kunmap_atomic); EXPORT_SYMBOL(kmap_atomic_to_page); #endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index ec2be14be..b6cd97ebe 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -1,74 +1,66 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/module.h" -#include "linux/types.h" +#include "linux/stddef.h" +#include "linux/kernel.h" #include "linux/mm.h" -#include "linux/fs.h" -#include "linux/init.h" #include "linux/bootmem.h" #include "linux/swap.h" -#include "linux/slab.h" -#include "linux/vmalloc.h" #include "linux/highmem.h" +#include "linux/gfp.h" #include "asm/page.h" -#include "asm/pgtable.h" +#include "asm/fixmap.h" #include "asm/pgalloc.h" -#include "asm/bitops.h" -#include "asm/uaccess.h" -#include "asm/tlb.h" #include "user_util.h" #include "kern_util.h" -#include "mem_user.h" -#include "mem.h" #include "kern.h" -#include "init.h" -#include "os.h" -#include "mode_kern.h" +#include "mem_user.h" #include "uml_uaccess.h" +#include "os.h" + +extern char __binary_start; /* Changed during early boot */ -pgd_t swapper_pg_dir[1024]; -unsigned long high_physmem; -unsigned long vm_start; -unsigned long vm_end; -unsigned long highmem; unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; - -/* Not modified */ -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; - -extern char __init_begin, __init_end; -extern long physmem_size; - -/* Not changed by UML */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); - -/* Changed during early boot */ +pgd_t swapper_pg_dir[1024]; +unsigned long highmem; int kmalloc_ok = 0; -#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1) -struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL }; -#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1) - -/* Changed during early boot */ static unsigned long brk_end; +void unmap_physmem(void) +{ + os_unmap_memory((void *) brk_end, uml_reserved - brk_end); +} + static void map_cb(void *unused) { map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } -void unmap_physmem(void) +#ifdef CONFIG_HIGHMEM +static void setup_highmem(unsigned long highmem_start, + unsigned long highmem_len) { - os_unmap_memory((void *) brk_end, uml_reserved - brk_end); -} + struct page *page; + unsigned long highmem_pfn; + int i; -extern char __binary_start; + highmem_start_page = virt_to_page(highmem_start); + + highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; + for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ + page = &mem_map[highmem_pfn + i]; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + set_page_count(page, 1); + __free_page(page); + } +} +#endif void mem_init(void) { @@ -103,50 +95,15 @@ void mem_init(void) totalhigh_pages = highmem >> PAGE_SHIFT; totalram_pages += totalhigh_pages; num_physpages = totalram_pages; - max_mapnr = totalram_pages; max_pfn = totalram_pages; printk(KERN_INFO "Memory: %luk available\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); kmalloc_ok = 1; -} - -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) - kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); - return(kmem_top); -} - -void set_kmem_end(unsigned long new) -{ - kmem_top = new; -} #ifdef CONFIG_HIGHMEM -/* Changed during early boot */ -pte_t *kmap_pte; -pgprot_t kmap_prot; - -EXPORT_SYMBOL(kmap_prot); -EXPORT_SYMBOL(kmap_pte); - -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) - -void __init kmap_init(void) -{ - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; + setup_highmem(end_iomem, highmem); +#endif } -#endif /* CONFIG_HIGHMEM */ static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) @@ -178,76 +135,24 @@ static void __init fixrange_init(unsigned long start, unsigned long end, } } -int init_maps(struct mem_region *region) -{ - struct page *p, *map; - int i, n, len; - - if(region == &physmem_region){ - region->mem_map = mem_map; - return(0); - } - else if(region->mem_map != NULL) return(0); - - n = region->len >> PAGE_SHIFT; - len = n * sizeof(struct page); - if(kmalloc_ok){ - map = kmalloc(len, GFP_KERNEL); - if(map == NULL) map = vmalloc(len); - } - else map = alloc_bootmem_low_pages(len); - - if(map == NULL) - return(-ENOMEM); - for(i = 0; i < n; i++){ - p = &map[i]; - set_page_count(p, 0); - SetPageReserved(p); - INIT_LIST_HEAD(&p->list); - } - region->mem_map = map; - return(0); -} +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; -DECLARE_MUTEX(regions_sem); +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) -static int setup_one_range(int fd, char *driver, unsigned long start, - unsigned long pfn, int len, - struct mem_region *region) +void __init kmap_init(void) { - int i; - - down(®ions_sem); - for(i = 0; i < NREGIONS; i++){ - if(regions[i] == NULL) break; - } - if(i == NREGIONS){ - printk("setup_range : no free regions\n"); - i = -1; - goto out; - } - - if(fd == -1) - fd = create_mem_file(len); + unsigned long kmap_vstart; - if(region == NULL){ - region = alloc_bootmem_low_pages(sizeof(*region)); - if(region == NULL) - panic("Failed to allocating mem_region"); - } + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - *region = ((struct mem_region) { .driver = driver, - .start_pfn = pfn, - .start = start, - .len = len, - .fd = fd } ); - regions[i] = region; - out: - up(®ions_sem); - return(i); + kmap_prot = PAGE_KERNEL; } -#ifdef CONFIG_HIGHMEM static void init_highmem(void) { pgd_t *pgd; @@ -268,63 +173,20 @@ static void init_highmem(void) kmap_init(); } - -void setup_highmem(unsigned long len) -{ - struct mem_region *region; - struct page *page, *map; - unsigned long phys; - int i, cur, index; - - phys = physmem_size; - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur, - NULL); - if(i == -1){ - printk("setup_highmem - setup_one_range failed\n"); - return; - } - region = regions[i]; - index = phys / PAGE_SIZE; - region->mem_map = &mem_map[index]; - - map = region->mem_map; - for(i = 0; i < (cur >> PAGE_SHIFT); i++){ - page = &map[i]; - ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); - set_page_count(page, 1); - __free_page(page); - } - phys += cur; - len -= cur; - } while(len > 0); -} -#endif +#endif /* CONFIG_HIGHMEM */ void paging_init(void) { - struct mem_region *region; - unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr; - int i, index; + unsigned long zones_size[MAX_NR_ZONES], vaddr; + int i; empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); for(i=0;i> PAGE_SHIFT) - - (uml_physmem >> PAGE_SHIFT); + zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); zones_size[2] = highmem >> PAGE_SHIFT; free_area_init(zones_size); - start = phys_region_index(__pa(uml_physmem)); - end = phys_region_index(__pa(high_physmem - 1)); - for(i = start; i <= end; i++){ - region = regions[i]; - index = (region->start - uml_physmem) / PAGE_SIZE; - region->mem_map = &mem_map[index]; - if(i > start) free_bootmem(__pa(region->start), region->len); - } /* * Fixed mappings, only the page table structure has to be @@ -335,15 +197,33 @@ void paging_init(void) #ifdef CONFIG_HIGHMEM init_highmem(); - setup_highmem(highmem); #endif } -pte_t __bad_page(void) +struct page *arch_validate(struct page *page, int mask, int order) { - clear_page(empty_bad_page); - return pte_mkdirty(mk_pte((struct page *) empty_bad_page, - PAGE_SHARED)); + unsigned long addr, zero = 0; + int i; + + again: + if(page == NULL) return(page); + if(PageHighMem(page)) return(page); + + addr = (unsigned long) page_address(page); + for(i = 0; i < (1 << order); i++){ + current->thread.fault_addr = (void *) addr; + if(__do_copy_to_user((void *) addr, &zero, + sizeof(zero), + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)){ + if(!(mask & __GFP_WAIT)) return(NULL); + else break; + } + addr += PAGE_SIZE; + } + if(i == (1 << order)) return(page); + page = alloc_pages(mask, order); + goto again; } /* This can't do anything because nothing in the kernel image can be freed @@ -401,395 +281,6 @@ void show_mem(void) printk("%d pages swap cached\n", cached); } -static int __init uml_mem_setup(char *line, int *add) -{ - char *retptr; - physmem_size = memparse(line,&retptr); - return 0; -} -__uml_setup("mem=", uml_mem_setup, -"mem=\n" -" This controls how much \"physical\" memory the kernel allocates\n" -" for the system. The size is specified as a number followed by\n" -" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" -" This is not related to the amount of memory in the physical\n" -" machine. It can be more, and the excess, if it's ever used, will\n" -" just be swapped out.\n Example: mem=64M\n\n" -); - -struct page *arch_validate(struct page *page, int mask, int order) -{ - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; -} - -DECLARE_MUTEX(vm_reserved_sem); -static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved); - -/* Static structures, linked in to the list in early boot */ -static struct vm_reserved head = { - .list = LIST_HEAD_INIT(head.list), - .start = 0, - .end = 0xffffffff -}; - -static struct vm_reserved tail = { - .list = LIST_HEAD_INIT(tail.list), - .start = 0, - .end = 0xffffffff -}; - -void set_usable_vm(unsigned long start, unsigned long end) -{ - list_add(&head.list, &vm_reserved); - list_add(&tail.list, &head.list); - head.end = start; - tail.start = end; -} - -int reserve_vm(unsigned long start, unsigned long end, void *e) - -{ - struct vm_reserved *entry = e, *reserved, *prev; - struct list_head *ele; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - reserved = list_entry(ele, struct vm_reserved, list); - if(reserved->start >= end) goto found; - } - panic("Reserved vm out of range"); - found: - prev = list_entry(ele->prev, struct vm_reserved, list); - if(prev->end > start) - panic("Can't reserve vm"); - if(entry == NULL) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if(entry == NULL){ - printk("reserve_vm : Failed to allocate entry\n"); - err = -ENOMEM; - goto out; - } - *entry = ((struct vm_reserved) - { .list = LIST_HEAD_INIT(entry->list), - .start = start, - .end = end }); - list_add(&entry->list, &prev->list); - err = 0; - out: - up(&vm_reserved_sem); - return(0); -} - -unsigned long get_vm(unsigned long len) -{ - struct vm_reserved *this, *next; - struct list_head *ele; - unsigned long start; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - this = list_entry(ele, struct vm_reserved, list); - next = list_entry(ele->next, struct vm_reserved, list); - if((this->start < next->start) && - (this->end + len + PAGE_SIZE <= next->start)) - goto found; - } - up(&vm_reserved_sem); - return(0); - found: - up(&vm_reserved_sem); - start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE; - err = reserve_vm(start, start + len, NULL); - if(err) return(0); - return(start); -} - -int nregions(void) -{ - return(NREGIONS); -} - -void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn, - unsigned long len, int need_vm, struct mem_region *region, - void *reserved) -{ - int i, cur; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(fd, driver, start, pfn, cur, region); - region = regions[i]; - if(need_vm && setup_region(region, reserved)){ - kfree(region); - regions[i] = NULL; - return; - } - start += cur; - if(pfn != -1) pfn += cur; - len -= cur; - } while(len > 0); -} - -struct iomem { - char *name; - int fd; - unsigned long size; -}; - -/* iomem regions can only be added on the command line at the moment. - * Locking will be needed when they can be added via mconsole. - */ - -struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = - { .name = NULL, - .fd = -1, - .size = 0 } }; - -int num_iomem_regions = 0; - -void add_iomem(char *name, int fd, unsigned long size) -{ - if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0])) - return; - size = (size + PAGE_SIZE - 1) & PAGE_MASK; - iomem_regions[num_iomem_regions++] = - ((struct iomem) { .name = name, - .fd = fd, - .size = size } ); -} - -int setup_iomem(void) -{ - struct iomem *iomem; - int i; - - for(i = 0; i < num_iomem_regions; i++){ - iomem = &iomem_regions[i]; - setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, - NULL, NULL); - } - return(0); -} - -__initcall(setup_iomem); - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) - -/* Changed during early boot */ -static struct mem_region physmem_region; -static struct vm_reserved physmem_reserved; - -void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len) -{ - struct mem_region *region = &physmem_region; - struct vm_reserved *reserved = &physmem_reserved; - unsigned long cur, pfn = 0; - int do_free = 1, bootmap_size; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - if(region == NULL) - region = alloc_bootmem_low_pages(sizeof(*region)); - if(reserved == NULL) - reserved = alloc_bootmem_low_pages(sizeof(*reserved)); - if((region == NULL) || (reserved == NULL)) - panic("Couldn't allocate physmem region or vm " - "reservation\n"); - setup_range(-1, NULL, start, pfn, cur, 1, region, reserved); - - if(do_free){ - unsigned long reserve = reserve_end - start; - int pfn = PFN_UP(__pa(reserve_end)); - int delta = (len - reserve) >> PAGE_SHIFT; - - bootmap_size = init_bootmem(pfn, pfn + delta); - free_bootmem(__pa(reserve_end) + bootmap_size, - cur - bootmap_size - reserve); - do_free = 0; - } - start += cur; - pfn += cur >> PAGE_SHIFT; - len -= cur; - region = NULL; - reserved = NULL; - } while(len > 0); -} - -struct mem_region *phys_region(unsigned long phys) -{ - unsigned int n = phys_region_index(phys); - - if(regions[n] == NULL) - panic("Physical address in uninitialized region"); - return(regions[n]); -} - -unsigned long phys_offset(unsigned long phys) -{ - return(phys_addr(phys)); -} - -struct page *phys_mem_map(unsigned long phys) -{ - return((struct page *) phys_region(phys)->mem_map); -} - -struct page *pte_mem_map(pte_t pte) -{ - return(phys_mem_map(pte_val(pte))); -} - -struct mem_region *page_region(struct page *page, int *index_out) -{ - int i; - struct mem_region *region; - struct page *map; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - map = region->mem_map; - if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){ - if(index_out != NULL) *index_out = i; - return(region); - } - } - panic("No region found for page"); - return(NULL); -} - -unsigned long page_to_pfn(struct page *page) -{ - struct mem_region *region = page_region(page, NULL); - - return(region->start_pfn + (page - (struct page *) region->mem_map)); -} - -struct mem_region *pfn_to_region(unsigned long pfn, int *index_out) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) - continue; - - if((region->start_pfn <= pfn) && - (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){ - if(index_out != NULL) - *index_out = i; - return(region); - } - } - return(NULL); -} - -struct page *pfn_to_page(unsigned long pfn) -{ - struct mem_region *region = pfn_to_region(pfn, NULL); - struct page *mem_map = (struct page *) region->mem_map; - - return(&mem_map[pfn - region->start_pfn]); -} - -unsigned long phys_to_pfn(unsigned long p) -{ - struct mem_region *region = regions[phys_region_index(p)]; - - return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT)); -} - -unsigned long pfn_to_phys(unsigned long pfn) -{ - int n; - struct mem_region *region = pfn_to_region(pfn, &n); - - return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n)); -} - -struct page *page_mem_map(struct page *page) -{ - return((struct page *) page_region(page, NULL)->mem_map); -} - -extern unsigned long region_pa(void *virt) -{ - struct mem_region *region; - unsigned long addr = (unsigned long) virt; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->start <= addr) && - (addr <= region->start + region->len)) - return(mk_phys(addr - region->start, i)); - } - panic("region_pa : no region for virtual address"); - return(0); -} - -extern void *region_va(unsigned long phys) -{ - return((void *) (phys_region(phys)->start + phys_addr(phys))); -} - -unsigned long page_to_phys(struct page *page) -{ - int n; - struct mem_region *region = page_region(page, &n); - struct page *map = region->mem_map; - return(mk_phys((page - map) << PAGE_SHIFT, n)); -} - -struct page *phys_to_page(unsigned long phys) -{ - struct page *mem_map; - - mem_map = phys_mem_map(phys); - return(mem_map + (phys_offset(phys) >> PAGE_SHIFT)); -} - -static int setup_mem_maps(void) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if((region != NULL) && (region->fd > 0)) init_maps(region); - } - return(0); -} - -__initcall(setup_mem_maps); - /* * Allocate and free page tables. */ diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c index d90345b5f..c52744b01 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -34,10 +34,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include "kern_util.h" @@ -47,105 +46,145 @@ #include "init.h" #include "os.h" #include "tempfile.h" +#include "kern_constants.h" extern struct mem_region physmem_region; #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" -int create_mem_file(unsigned long len) +static int create_tmp_file(unsigned long len) { - int fd; + int fd, err; char zero; fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); - if (fchmod(fd, 0777) < 0){ - perror("fchmod"); + if(fd < 0) { + os_print_error(fd, "make_tempfile"); + exit(1); + } + + err = os_mode_fd(fd, 0777); + if(err < 0){ + os_print_error(err, "os_mode_fd"); exit(1); } - if(os_seek_file(fd, len) < 0){ - perror("lseek"); + err = os_seek_file(fd, len); + if(err < 0){ + os_print_error(err, "os_seek_file"); exit(1); } zero = 0; - if(write(fd, &zero, 1) != 1){ - perror("write"); + err = os_write_file(fd, &zero, 1); + if(err != 1){ + os_print_error(err, "os_write_file"); exit(1); } - if(fcntl(fd, F_SETFD, 1) != 0) - perror("Setting FD_CLOEXEC failed"); + return(fd); } -int setup_region(struct mem_region *region, void *entry) +static int have_devanon = 0; + +void check_devanon(void) { - void *loc, *start; - char *driver; - int err, offset; - - if(region->start != -1){ - err = reserve_vm(region->start, - region->start + region->len, entry); - if(err){ - printk("setup_region : failed to reserve " - "0x%x - 0x%x for driver '%s'\n", - region->start, - region->start + region->len, - region->driver); - return(-1); - } - } - else region->start = get_vm(region->len); - if(region->start == 0){ - if(region->driver == NULL) driver = "physmem"; - else driver = region->driver; - printk("setup_region : failed to find vm for " - "driver '%s' (length %d)\n", driver, region->len); - return(-1); - } - if(region->start == uml_physmem){ - start = (void *) uml_reserved; - offset = uml_reserved - uml_physmem; + int fd; + + printk("Checking for /dev/anon on the host..."); + fd = open("/dev/anon", O_RDWR); + if(fd < 0){ + printk("Not available (open failed with errno %d)\n", errno); + return; } - else { - start = (void *) region->start; - offset = 0; + + printk("OK\n"); + have_devanon = 1; +} + +static int create_anon_file(unsigned long len) +{ + void *addr; + int fd; + + fd = open("/dev/anon", O_RDWR); + if(fd < 0) { + os_print_error(fd, "opening /dev/anon"); + exit(1); } - loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, region->fd, offset); - if(loc != start){ - perror("Mapping memory"); + addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + os_print_error((int) addr, "mapping physmem file"); exit(1); } - return(0); + munmap(addr, len); + + return(fd); } +int create_mem_file(unsigned long len) +{ + int err, fd; + + if(have_devanon) + fd = create_anon_file(len); + else fd = create_tmp_file(len); + + err = os_set_exec_close(fd, 1); + if(err < 0) + os_print_error(err, "exec_close"); + return(fd); +} + +struct iomem_region *iomem_regions = NULL; +int iomem_size = 0; + static int __init parse_iomem(char *str, int *add) { - struct stat buf; + struct iomem_region *new; + struct uml_stat buf; char *file, *driver; - int fd; + int fd, err; driver = str; file = strchr(str,','); if(file == NULL){ - printk("parse_iomem : failed to parse iomem\n"); - return(1); + printf("parse_iomem : failed to parse iomem\n"); + goto out; } *file = '\0'; file++; fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); if(fd < 0){ - printk("parse_iomem - Couldn't open io file, errno = %d\n", - errno); - return(1); + os_print_error(fd, "parse_iomem - Couldn't open io file"); + goto out; } - if(fstat(fd, &buf) < 0) { - printk("parse_iomem - cannot fstat file, errno = %d\n", errno); - return(1); + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; } - add_iomem(driver, fd, buf.st_size); + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; + } + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = buf.ust_size, + .phys = 0, + .virt = 0 }); + iomem_regions = new; + iomem_size += new->size + UM_KERN_PAGE_SIZE; + return(0); + out_close: + os_close_file(fd); + out: + return(1); } __uml_setup("iomem=", parse_iomem, @@ -153,73 +192,20 @@ __uml_setup("iomem=", parse_iomem, " Configure as an IO memory region named .\n\n" ); -#ifdef notdef -int logging = 0; -int logging_fd = -1; - -int logging_line = 0; -char logging_buf[256]; - -void log(char *fmt, ...) -{ - va_list ap; - struct timeval tv; - struct openflags flags; - - if(logging == 0) return; - if(logging_fd < 0){ - flags = of_create(of_trunc(of_rdrw(OPENFLAGS()))); - logging_fd = os_open_file("log", flags, 0644); - } - gettimeofday(&tv, NULL); - sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, - tv.tv_usec); - va_start(ap, fmt); - vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); - va_end(ap); - write(logging_fd, logging_buf, strlen(logging_buf)); -} -#endif - -int map_memory(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) -{ - struct mem_region *region = phys_region(phys); - - return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len, - r, w, x)); -} - int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed) { - if(os_protect_memory((void *) addr, len, r, w, x) < 0){ + int err; + + err = os_protect_memory((void *) addr, len, r, w, x); + if(err < 0){ if(must_succeed) - panic("protect failed, errno = %d", errno); - else return(-errno); + panic("protect failed, err = %d", -err); + else return(err); } return(0); } -unsigned long find_iomem(char *driver, unsigned long *len_out) -{ - struct mem_region *region; - int i, n; - - n = nregions(); - for(i = 0; i < n; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->driver != NULL) && - !strcmp(region->driver, driver)){ - *len_out = region->len; - return(region->start); - } - } - *len_out = 0; - return 0; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 4c3aa4535..01ad09884 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -9,12 +9,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -58,7 +56,11 @@ void init_new_thread_signals(int altstack) { int flags = altstack ? SA_ONSTACK : 0; - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, + /* NODEFER is set here because SEGV isn't turned back on when the + * handler is ready to receive signals. This causes any segfault + * during a copy_user to kill the process because the fault is blocked. + */ + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); @@ -72,7 +74,6 @@ void init_new_thread_signals(int altstack) SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); - (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -123,11 +124,12 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, /* Start the process and wait for it to kill itself */ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); if(new_pid < 0) return(-errno); - while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ; + while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ; if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", errno); if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) - panic("outer trampoline didn't exit with SIGKILL"); + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); return(arg.pid); } @@ -138,7 +140,7 @@ void suspend_new_thread(int fd) os_stop_process(os_getpid()); - if(read(fd, &c, sizeof(c)) != sizeof(c)) + if(os_read_file(fd, &c, sizeof(c)) != sizeof(c)) panic("read failed in suspend_new_thread"); } @@ -233,7 +235,7 @@ int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) int n; *jmp_ptr = &buf; - n = setjmp(buf); + n = sigsetjmp(buf, 1); if(n != 0) return(n); (*fn)(arg); @@ -273,7 +275,7 @@ int can_do_skas(void) stop_ptraced_child(pid, stack, 1); printf("Checking for /proc/mm..."); - if(access("/proc/mm", W_OK)){ + if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ printf("not found\n"); ret = 0; } diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index e17600a9b..ea000e6bc 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -16,6 +16,7 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -23,7 +24,6 @@ #include "asm/pgtable.h" #include "asm/processor.h" #include "asm/tlbflush.h" -#include "asm/spinlock.h" #include "asm/uaccess.h" #include "asm/user.h" #include "user_util.h" @@ -52,17 +52,12 @@ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; struct task_struct *get_task(int pid, int require) { - struct task_struct *task, *ret; + struct task_struct *ret; - ret = NULL; read_lock(&tasklist_lock); - for_each_process(task){ - if(task->pid == pid){ - ret = task; - break; - } - } + ret = find_task_by_pid(pid); read_unlock(&tasklist_lock); + if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); return(ret); } @@ -95,7 +90,8 @@ unsigned long alloc_stack(int order, int atomic) int flags = GFP_KERNEL; if(atomic) flags |= GFP_ATOMIC; - if((page = __get_free_pages(flags, order)) == 0) + page = __get_free_pages(flags, order); + if(page == 0) return(0); stack_protections(page); return(page); @@ -103,13 +99,15 @@ unsigned long alloc_stack(int order, int atomic) int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { - struct task_struct *p; + int pid; current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL); - if(IS_ERR(p)) panic("do_fork failed in kernel_thread"); - return(p->pid); + pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL, + NULL); + if(pid < 0) + panic("do_fork failed in kernel_thread, errno = %d", pid); + return(pid); } void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -129,7 +127,7 @@ void set_current(void *t) { external_pid(task), task }); } -void *switch_to(void *prev, void *next, void *last) +void *_switch_to(void *prev, void *next, void *last) { return(CHOOSE_MODE(switch_to_tt(prev, next), switch_to_skas(prev, next))); @@ -149,7 +147,7 @@ void release_thread(struct task_struct *task) void exit_thread(void) { CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); } void *get_current(void) @@ -157,6 +155,10 @@ void *get_current(void) return(current); } +void prepare_to_copy(struct task_struct *tsk) +{ +} + int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) @@ -190,7 +192,7 @@ int current_pid(void) void default_idle(void) { - idle_timer(); + uml_idle_timer(); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; @@ -367,10 +369,15 @@ int clear_user_proc(void *buf, int size) return(clear_user(buf, size)); } +int strlen_user_proc(char *str) +{ + return(strlen_user(str)); +} + int smp_sigio_handler(void) { #ifdef CONFIG_SMP - int cpu = current->thread_info->cpu; + int cpu = current_thread->cpu; IPI_handler(cpu); if(cpu != 0) return(1); @@ -385,7 +392,7 @@ int um_in_interrupt(void) int cpu(void) { - return(current->thread_info->cpu); + return(current_thread->cpu); } /* diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index c68c937f6..5ca4ef098 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -58,6 +58,8 @@ int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ @@ -302,8 +304,17 @@ int sys_ptrace(long request, long pid, long addr, long data) return ret; } -void syscall_trace(void) +void syscall_trace(union uml_pt_regs *regs, int entryexit) { + if (unlikely(current->audit_context)) { + if (!entryexit) + audit_syscall_entry(current, regs->orig_eax, + regs->ebx, regs->ecx, + regs->edx, regs->esi); + else + audit_syscall_exit(current, regs->eax); + } + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) @@ -311,11 +322,8 @@ void syscall_trace(void) /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; - notify_parent(current, SIGCHLD); - schedule(); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 3e4ab2963..207f89d74 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -15,6 +15,7 @@ #ifdef CONFIG_SMP static void kill_idlers(int me) { +#ifdef CONFIG_MODE_TT struct task_struct *p; int i; @@ -23,6 +24,7 @@ static void kill_idlers(int me) if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) os_kill_process(p->thread.mode.tt.extern_pid, 0); } +#endif } #endif diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c index 02272e623..92658eaa4 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio_kern.c @@ -6,18 +6,21 @@ #include "linux/kernel.h" #include "linux/list.h" #include "linux/slab.h" -#include "asm/irq.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "init.h" #include "sigio.h" #include "irq_user.h" +#include "irq_kern.h" /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; -void sigio_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) { read_sigio_fd(sigio_irq_fd); reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); + return(IRQ_HANDLED); } int write_sigio_irq(int fd) diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index b5ce13d55..6a9b38978 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -26,7 +25,7 @@ int pty_output_sigio = 0; int pty_close_sigio = 0; /* Used as a flag during SIGIO testing early in boot */ -static int got_sigio = 0; +static volatile int got_sigio = 0; void __init handler(int sig) { @@ -45,7 +44,7 @@ static void openpty_cb(void *arg) info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = errno; + info->err = -errno; } void __init check_one_sigio(void (*proc)(int, int)) @@ -53,11 +52,11 @@ void __init check_one_sigio(void (*proc)(int, int)) struct sigaction old, new; struct termios tt; struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, flags; + int master, slave, err; initial_thread_cb(openpty_cb, &pty); if(pty.err){ - printk("openpty failed, errno = %d\n", pty.err); + printk("openpty failed, errno = %d\n", -pty.err); return; } @@ -69,23 +68,16 @@ void __init check_one_sigio(void (*proc)(int, int)) return; } + /* XXX These can fail with EINTR */ if(tcgetattr(master, &tt) < 0) panic("check_sigio : tcgetattr failed, errno = %d\n", errno); cfmakeraw(&tt); if(tcsetattr(master, TCSADRAIN, &tt) < 0) panic("check_sigio : tcsetattr failed, errno = %d\n", errno); - if((flags = fcntl(master, F_GETFL)) < 0) - panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno); - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, " - "errno = %d\n", errno); - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", - errno); + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); if(sigaction(SIGIO, NULL, &old) < 0) panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); @@ -97,8 +89,8 @@ void __init check_one_sigio(void (*proc)(int, int)) got_sigio = 0; (*proc)(master, slave); - close(master); - close(slave); + os_close_file(master); + os_close_file(slave); if(sigaction(SIGIO, &old, NULL) < 0) panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); @@ -112,25 +104,25 @@ static void tty_output(int master, int slave) printk("Checking that host ptys support output SIGIO..."); memset(buf, 0, sizeof(buf)); - while(write(master, buf, sizeof(buf)) > 0) ; + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; if(errno != EAGAIN) panic("check_sigio : write failed, errno = %d\n", errno); - - while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; if(got_sigio){ printk("Yes\n"); pty_output_sigio = 1; } - else if(errno == EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, errno = %d\n", errno); + else if(n == -EAGAIN) printk("No, enabling workaround\n"); + else panic("check_sigio : read failed, err = %d\n", n); } static void tty_close(int master, int slave) { printk("Checking that host ptys support SIGIO on close..."); - close(slave); + os_close_file(slave); if(got_sigio){ printk("Yes\n"); pty_close_sigio = 1; @@ -140,7 +132,8 @@ static void tty_close(int master, int slave) void __init check_sigio(void) { - if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ printk("No pseudo-terminals available - skipping pty SIGIO " "check\n"); return; @@ -201,11 +194,10 @@ static int write_sigio_thread(void *unused) p = &fds->poll[i]; if(p->revents == 0) continue; if(p->fd == sigio_private[1]){ - n = read(sigio_private[1], &c, sizeof(c)); + n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, errno = %d\n", - errno); + "read failed, err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -218,10 +210,10 @@ static int write_sigio_thread(void *unused) (fds->used - i) * sizeof(*fds->poll)); } - n = write(respond_fd, &c, sizeof(c)); + n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : write failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } } } @@ -252,15 +244,15 @@ static void update_thread(void) char c; flags = set_signals(0); - n = write(sigio_private[0], &c, sizeof(c)); + n = os_write_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : write failed, errno = %d\n", errno); + printk("update_thread : write failed, err = %d\n", -n); goto fail; } - n = read(sigio_private[0], &c, sizeof(c)); + n = os_read_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : read failed, errno = %d\n", errno); + printk("update_thread : read failed, err = %d\n", -n); goto fail; } @@ -271,10 +263,10 @@ static void update_thread(void) if(write_sigio_pid != -1) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; - close(sigio_private[0]); - close(sigio_private[1]); - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); set_signals(flags); } @@ -369,15 +361,15 @@ void write_sigio_workaround(void) goto out; err = os_pipe(write_sigio_fds, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 1 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out; } err = os_pipe(sigio_private, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 2 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out_close1; } if(setup_initial_poll(sigio_private[1])) @@ -399,11 +391,11 @@ void write_sigio_workaround(void) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; out_close2: - close(sigio_private[0]); - close(sigio_private[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); out_close1: - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); } @@ -412,10 +404,16 @@ int read_sigio_fd(int fd) int n; char c; - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ - printk("read_sigio_fd - read failed, errno = %d\n", errno); - return(-errno); + if(n < 0) { + printk("read_sigio_fd - read failed, err = %d\n", -n); + return(n); + } + else { + printk("read_sigio_fd - short read, bytes = %d\n", n); + return(-EIO); + } } return(n); } diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 6e13847ed..5edb07118 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -36,7 +36,7 @@ static void force_segv(int sig) if(sig == SIGSEGV){ struct k_sigaction *ka; - ka = ¤t->sig->action[SIGSEGV - 1]; + ka = ¤t->sighand->action[SIGSEGV - 1]; ka->sa.sa_handler = SIG_DFL; } force_sig(SIGSEGV, current); @@ -60,10 +60,10 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, int err, ret; ret = 0; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; switch(error){ case -ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = - do_no_restart_syscall; case -ERESTARTNOHAND: ret = -EINTR; break; @@ -142,7 +142,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) return(0); /* Whee! Actually deliver the signal. */ - ka = ¤t->sig->action[sig -1 ]; + ka = ¤t->sighand->action[sig -1 ]; err = handle_signal(regs, sig, ka, &info, oldset, error); if(!err) return(1); @@ -201,7 +201,7 @@ int sys_sigsuspend(int history0, int history1, old_sigset_t mask) } } -int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) { sigset_t saveset, newset; @@ -227,20 +227,59 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) } } +int sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); +} + +extern int userspace_pid[]; + static int copy_sc_from_user(struct pt_regs *to, void *from, struct arch_frame_data *arch) { int ret; ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), - copy_sc_from_user_skas(&to->regs, from)); + copy_sc_from_user_skas(userspace_pid[0], + &to->regs, from)); return(ret); } int sys_sigreturn(struct pt_regs regs) { - void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); - void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); + void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); + void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -257,8 +296,8 @@ int sys_sigreturn(struct pt_regs regs) int sys_rt_sigreturn(struct pt_regs regs) { - struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs)); - void *fp; + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct ucontext __user *uc = sp_to_uc(sp); int sig_size = _NSIG_WORDS * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -266,7 +305,6 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext)); copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, &signal_frame_si.common.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 72c79956f..85f946959 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -5,20 +5,24 @@ obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ - sys-$(SUBARCH)/ + uaccess.o sys-$(SUBARCH)/ + +host-progs := util/mk_ptregs +clean-files := include/skas_ptregs.h USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include/skas_ptregs.h : util/mk_ptregs - util/mk_ptregs > $@ - -util/mk_ptregs : - $(MAKE) -C util +$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs + @echo -n ' Generating $@' + @$< > $@.tmp + @if [ -r $@ ] && cmp -s $@ $@.tmp; then \ + echo ' (unchanged)'; \ + rm -f $@.tmp; \ + else \ + echo ' (updated)'; \ + mv -f $@.tmp $@; \ + fi $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : - $(MAKE) -C util clean - $(RM) -f include/skas_ptregs.h diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h index 7516206cc..aa16dc0d8 100644 --- a/arch/um/kernel/skas/include/mode.h +++ b/arch/um/kernel/skas/include/mode.h @@ -12,14 +12,16 @@ extern unsigned long exec_fpx_regs[]; extern int have_fpx_regs; extern void user_time_init_skas(void); -extern int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr); -extern int copy_sc_to_user_skas(void *to_ptr, void *fp, +extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, + void *from_ptr); +extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, union uml_pt_regs *regs, unsigned long fault_addr, int fault_type); extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void halt_skas(void); extern void reboot_skas(void); extern void kill_off_processes_skas(void); +extern int is_skas_winch(int pid, int fd, void *data); #endif diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index d9614f6cd..0bbc97540 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -8,7 +8,7 @@ #include "sysdep/ptrace.h" -extern int userspace_pid; +extern int userspace_pid[]; extern void switch_threads(void *me, void *next); extern void thread_wait(void *sw, void *fb); @@ -32,7 +32,7 @@ extern int singlestepping_skas(void); extern int new_mm(int from); extern void save_registers(union uml_pt_regs *regs); extern void restore_registers(union uml_pt_regs *regs); -extern void start_userspace(void); +extern void start_userspace(int cpu); extern void init_registers(int pid); #endif diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h index d28c4b1de..0d6f30bf7 100644 --- a/arch/um/kernel/skas/include/uaccess.h +++ b/arch/um/kernel/skas/include/uaccess.h @@ -6,20 +6,12 @@ #ifndef __SKAS_UACCESS_H #define __SKAS_UACCESS_H -#include "linux/string.h" -#include "linux/sched.h" -#include "linux/err.h" -#include "asm/processor.h" -#include "asm/pgtable.h" #include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" -#include "kern_util.h" #define access_ok_skas(type, addr, size) \ ((segment_eq(get_fs(), KERNEL_DS)) || \ (((unsigned long) (addr) < TASK_SIZE) && \ - ((unsigned long) (addr) + (size) < TASK_SIZE))) + ((unsigned long) (addr) + (size) <= TASK_SIZE))) static inline int verify_area_skas(int type, const void * addr, unsigned long size) @@ -27,197 +19,12 @@ static inline int verify_area_skas(int type, const void * addr, return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); } -static inline unsigned long maybe_map(unsigned long virt, int is_write) -{ - pte_t pte; - - void *phys = um_virt_to_phys(current, virt, &pte); - int dummy_code; - - if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - if(handle_page_fault(virt, 0, is_write, 0, &dummy_code)) - return(0); - phys = um_virt_to_phys(current, virt, NULL); - } - return((unsigned long) __va((unsigned long) phys)); -} - -static inline int buffer_op(unsigned long addr, int len, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) -{ - int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); - int remain = len, n; - - n = (*op)(addr, size, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += size; - remain -= size; - if(remain == 0) - return(0); - - while(addr < ((addr + remain) & PAGE_MASK)){ - n = (*op)(addr, PAGE_SIZE, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += PAGE_SIZE; - remain -= PAGE_SIZE; - } - if(remain == 0) - return(0); - - n = (*op)(addr, remain, arg); - if(n != 0) - return(n < 0 ? remain : 0); - return(0); -} - -static inline int copy_chunk_from_user(unsigned long from, int len, void *arg) -{ - unsigned long *to_ptr = arg, to = *to_ptr; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *to_ptr += len; - return(0); -} - -static inline int copy_from_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_READ, from, n) ? - buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) : - n); -} - -static inline int copy_chunk_to_user(unsigned long to, int len, void *arg) -{ - unsigned long *from_ptr = arg, from = *from_ptr; - - to = maybe_map(to, 1); - if(to == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *from_ptr += len; - return(0); -} - -static inline int copy_to_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, to, n) ? - buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) : - n); -} - -static inline int strncpy_chunk_from_user(unsigned long from, int len, - void *arg) -{ - char **to_ptr = arg, *to = *to_ptr; - int n; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - strncpy(to, (void *) from, len); - n = strnlen(to, len); - *to_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strncpy_from_user_skas(char *dst, const char *src, int count) -{ - int n; - char *ptr = dst; - - if(segment_eq(get_fs(), KERNEL_DS)){ - strncpy(dst, src, count); - return(strnlen(dst, count)); - } - - if(!access_ok_skas(VERIFY_READ, src, 1)) - return(-EFAULT); - - n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, - &ptr); - if(n != 0) - return(-EFAULT); - return(strnlen(dst, count)); -} - -static inline int clear_chunk(unsigned long addr, int len, void *unused) -{ - addr = maybe_map(addr, 1); - if(addr == 0) - return(-1); - - memset((void *) addr, 0, len); - return(0); -} - -static inline int __clear_user_skas(void *mem, int len) -{ - return(buffer_op((unsigned long) mem, len, clear_chunk, NULL)); -} - -static inline int clear_user_skas(void *mem, int len) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memset(mem, 0, len); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, mem, len) ? - buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len); -} - -static inline int strnlen_chunk(unsigned long str, int len, void *arg) -{ - int *len_ptr = arg, n; - - str = maybe_map(str, 0); - if(str == 0) - return(-1); - - n = strnlen((void *) str, len); - *len_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strnlen_user_skas(const void *str, int len) -{ - int count = 0, n; - - if(segment_eq(get_fs(), KERNEL_DS)) - return(strnlen(str, len) + 1); - - n = buffer_op((unsigned long) str, len, strnlen_chunk, &count); - if(n == 0) - return(count + 1); - return(-EFAULT); -} +extern int copy_from_user_skas(void *to, const void *from, int n); +extern int copy_to_user_skas(void *to, const void *from, int n); +extern int strncpy_from_user_skas(char *dst, const char *src, int count); +extern int __clear_user_skas(void *mem, int len); +extern int clear_user_skas(void *mem, int len); +extern int strnlen_user_skas(const void *str, int len); #endif diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c index d163090c0..190912553 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/kernel/skas/mem_user.c @@ -7,6 +7,7 @@ #include #include #include "mem_user.h" +#include "mem.h" #include "user.h" #include "os.h" #include "proc_mm.h" @@ -15,12 +16,12 @@ void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x) { struct proc_mm_op map; - struct mem_region *region; - int prot, n; + __u64 offset; + int prot, n, phys_fd; prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - region = phys_region(phys); + phys_fd = phys_mapping(phys, &offset); map = ((struct proc_mm_op) { .op = MM_MMAP, .u = @@ -30,12 +31,12 @@ void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, .prot = prot, .flags = MAP_SHARED | MAP_FIXED, - .fd = region->fd, - .offset = phys_offset(phys) + .fd = phys_fd, + .offset = offset } } } ); n = os_write_file(fd, &map, sizeof(map)); if(n != sizeof(map)) - printk("map : /proc/mm map failed, errno = %d\n", errno); + printk("map : /proc/mm map failed, err = %d\n", -n); } int unmap(int fd, void *addr, int len) @@ -49,8 +50,13 @@ int unmap(int fd, void *addr, int len) { .addr = (unsigned long) addr, .len = len } } } ); n = os_write_file(fd, &unmap, sizeof(unmap)); - if((n != 0) && (n != sizeof(unmap))) - return(-errno); + if(n != sizeof(unmap)) { + if(n < 0) + return(n); + else if(n > 0) + return(-EIO); + } + return(0); } @@ -71,11 +77,15 @@ int protect(int fd, unsigned long addr, unsigned long len, int r, int w, .prot = prot } } } ); n = os_write_file(fd, &protect, sizeof(protect)); - if((n != 0) && (n != sizeof(protect))){ + if(n != sizeof(protect)) { + if(n == 0) return(0); + if(must_succeed) - panic("protect failed, errno = %d", errno); - return(-errno); + panic("protect failed, err = %d", -n); + + return(-EIO); } + return(0); } diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 5911cdd0c..6cb9a6d02 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -22,9 +22,11 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) else from = -1; mm->context.skas.mm_fd = new_mm(from); - if(mm->context.skas.mm_fd < 0) - panic("init_new_context_skas - new_mm failed, errno = %d\n", - mm->context.skas.mm_fd); + if(mm->context.skas.mm_fd < 0){ + printk("init_new_context_skas - new_mm failed, errno = %d\n", + mm->context.skas.mm_fd); + return(mm->context.skas.mm_fd); + } return(0); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index cb91f8cd1..7e489869d 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,19 @@ #include "os.h" #include "proc_mm.h" #include "skas_ptrace.h" +#include "chan_user.h" +#include "signal_user.h" + +int is_skas_winch(int pid, int fd, void *data) +{ + if(pid != getpid()) + return(0); + + register_winch_irq(-1, fd, -1, data); + return(1); +} + +/* These are set once at boot time and not changed thereafter */ unsigned long exec_regs[FRAME_SIZE]; unsigned long exec_fp_regs[HOST_FP_SIZE]; @@ -48,11 +62,11 @@ static void handle_trap(int pid, union uml_pt_regs *regs) int err, syscall_nr, status; syscall_nr = PT_SYSCALL_NR(regs->skas.regs); + UPT_SYSCALL_NR(regs) = syscall_nr; if(syscall_nr < 1){ relay_signal(SIGTRAP, regs); return; } - UPT_SYSCALL_NR(regs) = syscall_nr; err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) @@ -72,8 +86,6 @@ static void handle_trap(int pid, union uml_pt_regs *regs) handle_syscall(regs); } -int userspace_pid; - static int userspace_tramp(void *arg) { init_new_thread_signals(0); @@ -83,7 +95,11 @@ static int userspace_tramp(void *arg) return(0); } -void start_userspace(void) +/* Each element set once, and only accessed by a single processor anyway */ +#define NR_CPUS 1 +int userspace_pid[NR_CPUS]; + +void start_userspace(int cpu) { void *stack; unsigned long sp; @@ -114,21 +130,21 @@ void start_userspace(void) if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); - userspace_pid = pid; + userspace_pid[cpu] = pid; } void userspace(union uml_pt_regs *regs) { - int err, status, op; + int err, status, op, pid = userspace_pid[0]; restore_registers(regs); - err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", errno); while(1){ - err = waitpid(userspace_pid, &status, WUNTRACED); + err = waitpid(pid, &status, WUNTRACED); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); @@ -139,16 +155,17 @@ void userspace(union uml_pt_regs *regs) if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: - handle_segv(userspace_pid); + handle_segv(pid); break; case SIGTRAP: - handle_trap(userspace_pid, regs); + handle_trap(pid, regs); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: + case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: @@ -162,7 +179,7 @@ void userspace(union uml_pt_regs *regs) op = singlestepping_skas() ? PTRACE_SINGLESTEP : PTRACE_SYSCALL; - err = ptrace(op, userspace_pid, 0, 0); + err = ptrace(op, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, " "errno = %d\n", errno); @@ -172,13 +189,25 @@ void userspace(union uml_pt_regs *regs) void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { + unsigned long flags; jmp_buf switch_buf, fork_buf; *switch_buf_ptr = &switch_buf; *fork_buf_ptr = &fork_buf; - if(setjmp(fork_buf) == 0) + /* Somewhat subtle - siglongjmp restores the signal mask before doing + * the longjmp. This means that when jumping from one stack to another + * when the target stack has interrupts enabled, an interrupt may occur + * on the source stack. This is bad when starting up a process because + * it's not supposed to get timer ticks until it has been scheduled. + * So, we disable interrupts around the sigsetjmp to ensure that + * they can't happen until we get back here where they are safe. + */ + flags = get_signals(); + block_signals(); + if(sigsetjmp(fork_buf, 1) == 0) new_thread_proc(stack, handler); + set_signals(flags); remove_sigstack(); } @@ -189,16 +218,16 @@ void thread_wait(void *sw, void *fb) *switch_buf = &buf; fork_buf = fb; - if(setjmp(buf) == 0) - longjmp(*fork_buf, 1); + if(sigsetjmp(buf, 1) == 0) + siglongjmp(*fork_buf, 1); } -static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs, - unsigned long *fp_regs) +static int move_registers(int pid, int int_op, int fp_op, + union uml_pt_regs *regs, unsigned long *fp_regs) { - if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0) + if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) return(-errno); - if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) + if(ptrace(fp_op, pid, 0, fp_regs) < 0) return(-errno); return(0); } @@ -217,10 +246,11 @@ void save_registers(union uml_pt_regs *regs) fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs, + fp_regs); if(err) panic("save_registers - saving registers failed, errno = %d\n", - err); + -err); } void restore_registers(union uml_pt_regs *regs) @@ -237,10 +267,11 @@ void restore_registers(union uml_pt_regs *regs) fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs, + fp_regs); if(err) panic("restore_registers - saving registers failed, " - "errno = %d\n", err); + "errno = %d\n", -err); } void switch_threads(void *me, void *next) @@ -248,8 +279,8 @@ void switch_threads(void *me, void *next) jmp_buf my_buf, **me_ptr = me, *next_buf = next; *me_ptr = &my_buf; - if(setjmp(my_buf) == 0) - longjmp(*next_buf, 1); + if(sigsetjmp(my_buf, 1) == 0) + siglongjmp(*next_buf, 1); } static jmp_buf initial_jmpbuf; @@ -265,14 +296,14 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) int n; *fork_buf_ptr = &initial_jmpbuf; - n = setjmp(initial_jmpbuf); + n = sigsetjmp(initial_jmpbuf, 1); if(n == 0) new_thread_proc((void *) stack, new_thread_handler); else if(n == 1) remove_sigstack(); else if(n == 2){ (*cb_proc)(cb_arg); - longjmp(*cb_back, 1); + siglongjmp(*cb_back, 1); } else if(n == 3){ kmalloc_ok = 0; @@ -282,7 +313,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) kmalloc_ok = 0; return(1); } - longjmp(**switch_buf, 1); + siglongjmp(**switch_buf, 1); } void remove_sigstack(void) @@ -304,8 +335,8 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) cb_back = &here; block_signals(); - if(setjmp(here) == 0) - longjmp(initial_jmpbuf, 2); + if(sigsetjmp(here, 1) == 0) + siglongjmp(initial_jmpbuf, 2); unblock_signals(); cb_proc = NULL; @@ -316,22 +347,23 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) void halt_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 3); + siglongjmp(initial_jmpbuf, 3); } void reboot_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 4); + siglongjmp(initial_jmpbuf, 4); } int new_mm(int from) { struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + int n, fd = os_open_file("/proc/mm", + of_cloexec(of_write(OPENFLAGS())), 0); if(fd < 0) - return(-errno); + return(fd); if(from != -1){ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, @@ -340,8 +372,9 @@ int new_mm(int from) n = os_write_file(fd, ©, sizeof(copy)); if(n != sizeof(copy)) printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } + return(fd); } @@ -349,7 +382,8 @@ void switch_mm_skas(int mm_fd) { int err; - err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); +#warning need cpu pid in switch_mm_skas + err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); if(err) panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", errno); @@ -357,7 +391,8 @@ void switch_mm_skas(int mm_fd) void kill_off_processes_skas(void) { - os_kill_process(userspace_pid, 1); +#warning need to loop over userspace_pids in kill_off_processes_skas + os_kill_process(userspace_pid[0], 1); } void init_registers(int pid) diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 128146c80..ec62366ac 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -61,11 +61,13 @@ void new_thread_handler(int sig) thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + /* The return value is 1 if the kernel thread execs a process, + * 0 if it just exits + */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); if(n == 1) userspace(¤t->thread.regs.regs); @@ -93,11 +95,11 @@ void fork_handler(int sig) current->thread.mode.skas.fork_buf); force_flush_all(); -#ifdef CONFIG_SMP + if(current->thread.prev_sched == NULL) + panic("blech"); + schedule_tail(current->thread.prev_sched); -#endif current->thread.prev_sched = NULL; - unblock_signals(); userspace(¤t->thread.regs.regs); } @@ -136,7 +138,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, void init_idle_skas(void) { - cpu_tasks[current->thread_info->cpu].pid = os_getpid(); + cpu_tasks[current_thread->cpu].pid = os_getpid(); default_idle(); } @@ -160,11 +162,11 @@ static int start_kernel_proc(void *unused) int start_uml_skas(void) { - start_userspace(); + start_userspace(0); capture_signal_stack(); + uml_idle_timer(); init_new_thread_signals(1); - idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; @@ -175,12 +177,14 @@ int start_uml_skas(void) int external_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } int thread_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } /* diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile index 2ad8271c6..3eeea057c 100644 --- a/arch/um/kernel/skas/sys-i386/Makefile +++ b/arch/um/kernel/skas/sys-i386/Makefile @@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : diff --git a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c index 5f340e102..895d34cf4 100644 --- a/arch/um/kernel/skas/sys-i386/sigcontext.c +++ b/arch/um/kernel/skas/sys-i386/sigcontext.c @@ -12,10 +12,9 @@ #include "kern_util.h" #include "user.h" #include "sigcontext.h" +#include "mode.h" -extern int userspace_pid; - -int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr) +int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr) { struct sigcontext sc, *from = from_ptr; unsigned long fpregs[FP_FRAME_SIZE]; @@ -41,13 +40,12 @@ int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr) regs->skas.regs[EIP] = sc.eip; regs->skas.regs[CS] = sc.cs; regs->skas.regs[EFL] = sc.eflags; - regs->skas.regs[UESP] = sc.esp_at_signal; regs->skas.regs[SS] = sc.ss; regs->skas.fault_addr = sc.cr2; regs->skas.fault_type = FAULT_WRITE(sc.err); regs->skas.trap_type = sc.trapno; - err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " "errno = %d\n", errno); @@ -57,8 +55,9 @@ int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr) return(0); } -int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs, - unsigned long fault_addr, int fault_type) +int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, + union uml_pt_regs *regs, unsigned long fault_addr, + int fault_type) { struct sigcontext sc, *to = to_ptr; struct _fpstate *to_fp; @@ -86,7 +85,7 @@ int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs, sc.err = TO_SC_ERR(fault_type); sc.trapno = regs->skas.trap_type; - err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " "errno = %d\n", errno); diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c index bc837a77e..1d7eca5a8 100644 --- a/arch/um/kernel/skas/syscall_kern.c +++ b/arch/um/kernel/skas/syscall_kern.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c index caccb772b..34fd5f94e 100644 --- a/arch/um/kernel/skas/syscall_user.c +++ b/arch/um/kernel/skas/syscall_user.c @@ -22,7 +22,7 @@ void handle_syscall(union uml_pt_regs *regs) index = record_syscall_start(UPT_SYSCALL_NR(regs)); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); @@ -30,7 +30,7 @@ void handle_syscall(union uml_pt_regs *regs) (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 0906f65b8..2c47e78c1 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -35,14 +35,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr) errno = save_errno; } -extern int missed_ticks[]; - void user_signal(int sig, union uml_pt_regs *regs) { struct signal_info *info; - if(sig == SIGVTALRM) - missed_ticks[cpu()]++; regs->skas.is_user = 1; regs->skas.fault_addr = 0; regs->skas.fault_type = 0; diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile index e62dc253e..5ba1d68d6 100644 --- a/arch/um/kernel/skas/util/Makefile +++ b/arch/um/kernel/skas/util/Makefile @@ -1,10 +1,9 @@ all: mk_ptregs mk_ptregs : mk_ptregs.o - $(CC) -o mk_ptregs mk_ptregs.o + $(HOSTCC) -o mk_ptregs mk_ptregs.o mk_ptregs.o : mk_ptregs.c - $(CC) -c $< + $(HOSTCC) -c $< -clean : - $(RM) -f mk_ptregs *.o *~ +clean-files := mk_ptregs *.o *~ diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c index 658791017..116f74d2c 100644 --- a/arch/um/kernel/skas/util/mk_ptregs.c +++ b/arch/um/kernel/skas/util/mk_ptregs.c @@ -1,3 +1,4 @@ +#include #include #include diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index b8158556c..7c9737c74 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -1,9 +1,15 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #include "linux/config.h" +#include "linux/percpu.h" +#include "asm/pgalloc.h" +#include "asm/tlb.h" + +/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); #ifdef CONFIG_SMP @@ -23,7 +29,7 @@ #include "os.h" /* CPU online map, set by smp_boot_cpus */ -unsigned long cpu_online_map = cpumask_of_cpu(0); +unsigned long cpu_online_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); @@ -55,7 +61,7 @@ struct task_struct *idle_threads[NR_CPUS]; void smp_send_reschedule(int cpu) { - write(cpu_data[cpu].ipi_pipe[1], "R", 1); + os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1); num_reschedules_sent++; } @@ -100,35 +106,34 @@ void smp_send_stop(void) printk(KERN_INFO "Stopping all CPUs..."); for(i = 0; i < num_online_cpus(); i++){ - if(i == current->thread_info->cpu) + if(i == current_thread->cpu) continue; - write(cpu_data[i].ipi_pipe[1], "S", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); } printk("done\n"); } -static cpumask_t smp_commenced_mask; -static cpumask_t smp_callin_map = CPU_MASK_NONE; +static cpumask_t smp_commenced_mask = CPU_MASK_NONE; +static cpumask_t cpu_callin_map = CPU_MASK_NONE; static int idle_proc(void *cpup) { int cpu = (int) cpup, err; err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); - if(err) - panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, - -err); + if(err < 0) + panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.mode.tt.extern_pid); wmb(); - if (cpu_test_and_set(cpu, &smp_callin_map)) { + if (cpu_test_and_set(cpu, cpu_callin_map)) { printk("huh, CPU#%d already present??\n", cpu); BUG(); } - while (!cpu_isset(cpu, &smp_commenced_mask)) + while (!cpu_isset(cpu, smp_commenced_mask)) cpu_relax(); cpu_set(cpu, cpu_online_map); @@ -143,16 +148,20 @@ static struct task_struct *idle_thread(int cpu) current->thread.request.u.thread.proc = idle_proc; current->thread.request.u.thread.arg = (void *) cpu; - new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL); - if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); + new_task = copy_process(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, + NULL); + if(IS_ERR(new_task)) + panic("copy_process failed in idle_thread, error = %ld", + PTR_ERR(new_task)); cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, sizeof(c)), ({ panic("skas mode doesn't support SMP"); })); + wake_up_forked_process(new_task); return(new_task); } @@ -160,15 +169,17 @@ void smp_prepare_cpus(unsigned int maxcpus) { struct task_struct *idle; unsigned long waittime; - int err, cpu; + int err, cpu, me = smp_processor_id(); - cpu_set(0, cpu_online_map); - cpu_set(0, smp_callin_map); + cpu_clear(me, cpu_online_map); + cpu_set(me, cpu_online_map); + cpu_set(me, cpu_callin_map); - err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); - if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); + err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); + if(err < 0) + panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[0].ipi_pipe[0], + activate_ipi(cpu_data[me].ipi_pipe[0], current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ @@ -180,10 +191,10 @@ void smp_prepare_cpus(unsigned int maxcpus) unhash_process(idle); waittime = 200000000; - while (waittime-- && !cpu_isset(cpu, smp_callin_map)) + while (waittime-- && !cpu_isset(cpu, cpu_callin_map)) cpu_relax(); - if (cpu_isset(cpu, smp_callin_map)) + if (cpu_isset(cpu, cpu_callin_map)) printk("done\n"); else printk("failed\n"); } @@ -216,7 +227,7 @@ void IPI_handler(int cpu) int fd; fd = cpu_data[cpu].ipi_pipe[0]; - while (read(fd, &c, 1) == 1) { + while (os_read_file(fd, &c, 1) == 1) { switch (c) { case 'C': smp_call_function_slave(cpu); @@ -276,9 +287,9 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, info = _info; for (i=0;ithread_info->cpu) && + if((i != current_thread->cpu) && cpu_isset(i, cpu_online_map)) - write(cpu_data[i].ipi_pipe[1], "C", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "C", 1); while (atomic_read(&scf_started) != cpus) barrier(); diff --git a/arch/um/kernel/smp.c.orig b/arch/um/kernel/smp.c.orig new file mode 100644 index 000000000..34f826c08 --- /dev/null +++ b/arch/um/kernel/smp.c.orig @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/config.h" + +#ifdef CONFIG_SMP + +#include "linux/sched.h" +#include "linux/module.h" +#include "linux/threads.h" +#include "linux/interrupt.h" +#include "linux/err.h" +#include "asm/smp.h" +#include "asm/processor.h" +#include "asm/spinlock.h" +#include "asm/hardirq.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" +#include "irq_user.h" +#include "os.h" + +/* CPU online map, set by smp_boot_cpus */ +unsigned long cpu_online_map = cpumask_of_cpu(0); + +EXPORT_SYMBOL(cpu_online_map); + +/* Per CPU bogomips and other parameters + * The only piece used here is the ipi pipe, which is set before SMP is + * started and never changed. + */ +struct cpuinfo_um cpu_data[NR_CPUS]; + +spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED; + +atomic_t global_bh_count; + +/* Not used by UML */ +unsigned char global_irq_holder = NO_PROC_ID; +unsigned volatile long global_irq_lock; + +/* Set when the idlers are all forked */ +int smp_threads_ready = 0; + +/* A statistic, can be a little off */ +int num_reschedules_sent = 0; + +/* Small, random number, never changed */ +unsigned long cache_decay_ticks = 5; + +/* Not changed after boot */ +struct task_struct *idle_threads[NR_CPUS]; + +void smp_send_reschedule(int cpu) +{ + write(cpu_data[cpu].ipi_pipe[1], "R", 1); + num_reschedules_sent++; +} + +static void show(char * str) +{ + int cpu = smp_processor_id(); + + printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu); +} + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + +void smp_send_stop(void) +{ + int i; + + printk(KERN_INFO "Stopping all CPUs..."); + for(i = 0; i < num_online_cpus(); i++){ + if(i == current->thread_info->cpu) + continue; + write(cpu_data[i].ipi_pipe[1], "S", 1); + } + printk("done\n"); +} + +static cpumask_t smp_commenced_mask; +static cpumask_t smp_callin_map = CPU_MASK_NONE; + +static int idle_proc(void *cpup) +{ + int cpu = (int) cpup, err; + + err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); + if(err) + panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, + -err); + + activate_ipi(cpu_data[cpu].ipi_pipe[0], + current->thread.mode.tt.extern_pid); + + wmb(); + if (cpu_test_and_set(cpu, &smp_callin_map)) { + printk("huh, CPU#%d already present??\n", cpu); + BUG(); + } + + while (!cpu_isset(cpu, &smp_commenced_mask)) + cpu_relax(); + + cpu_set(cpu, cpu_online_map); + default_idle(); + return(0); +} + +static struct task_struct *idle_thread(int cpu) +{ + struct task_struct *new_task; + unsigned char c; + + current->thread.request.u.thread.proc = idle_proc; + current->thread.request.u.thread.arg = (void *) cpu; + new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL); + if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); + + cpu_tasks[cpu] = ((struct cpu_task) + { .pid = new_task->thread.mode.tt.extern_pid, + .task = new_task } ); + idle_threads[cpu] = new_task; + CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + sizeof(c)), + ({ panic("skas mode doesn't support SMP"); })); + return(new_task); +} + +void smp_prepare_cpus(unsigned int maxcpus) +{ + struct task_struct *idle; + unsigned long waittime; + int err, cpu; + + cpu_set(0, cpu_online_map); + cpu_set(0, smp_callin_map); + + err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); + if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); + + activate_ipi(cpu_data[0].ipi_pipe[0], + current->thread.mode.tt.extern_pid); + + for(cpu = 1; cpu < ncpus; cpu++){ + printk("Booting processor %d...\n", cpu); + + idle = idle_thread(cpu); + + init_idle(idle, cpu); + unhash_process(idle); + + waittime = 200000000; + while (waittime-- && !cpu_isset(cpu, smp_callin_map)) + cpu_relax(); + + if (cpu_isset(cpu, smp_callin_map)) + printk("done\n"); + else printk("failed\n"); + } +} + +void smp_prepare_boot_cpu(void) +{ + cpu_set(smp_processor_id(), cpu_online_map); +} + +int __cpu_up(unsigned int cpu) +{ + cpu_set(cpu, smp_commenced_mask); + while (!cpu_isset(cpu, cpu_online_map)) + mb(); + return(0); +} + +int setup_profiling_timer(unsigned int multiplier) +{ + printk(KERN_INFO "setup_profiling_timer\n"); + return(0); +} + +void smp_call_function_slave(int cpu); + +void IPI_handler(int cpu) +{ + unsigned char c; + int fd; + + fd = cpu_data[cpu].ipi_pipe[0]; + while (read(fd, &c, 1) == 1) { + switch (c) { + case 'C': + smp_call_function_slave(cpu); + break; + + case 'R': + set_tsk_need_resched(current); + break; + + case 'S': + printk("CPU#%d stopping\n", cpu); + while(1) + pause(); + break; + + default: + printk("CPU#%d received unknown IPI [%c]!\n", cpu, c); + break; + } + } +} + +int hard_smp_processor_id(void) +{ + return(pid_to_processor_id(os_getpid())); +} + +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; +static atomic_t scf_started; +static atomic_t scf_finished; +static void (*func)(void *info); +static void *info; + +void smp_call_function_slave(int cpu) +{ + atomic_inc(&scf_started); + (*func)(info); + atomic_inc(&scf_finished); +} + +int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, + int wait) +{ + int cpus = num_online_cpus() - 1; + int i; + + if (!cpus) + return 0; + + spin_lock_bh(&call_lock); + atomic_set(&scf_started, 0); + atomic_set(&scf_finished, 0); + func = _func; + info = _info; + + for (i=0;ithread_info->cpu) && + cpu_isset(i, cpu_online_map)) + write(cpu_data[i].ipi_pipe[1], "C", 1); + + while (atomic_read(&scf_started) != cpus) + barrier(); + + if (wait) + while (atomic_read(&scf_finished) != cpus) + barrier(); + + spin_unlock_bh(&call_lock); + return 0; +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index 77a7d922e..597d5683a 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -5,7 +5,6 @@ #include "linux/config.h" #include "linux/unistd.h" -#include "linux/version.h" #include "linux/sys.h" #include "linux/swap.h" #include "linux/syscalls.h" @@ -14,251 +13,51 @@ #include "sysdep/syscalls.h" #include "kern_util.h" -extern syscall_handler_t sys_restart_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_exit; +#ifdef CONFIG_NFSD +#define NFSSERVCTL sys_nfsservctl +#else +#define NFSSERVCTL sys_ni_syscall +#endif + +#define LAST_GENERIC_SYSCALL __NR_vserver + +#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL +#define LAST_SYSCALL LAST_GENERIC_SYSCALL +#else +#define LAST_SYSCALL LAST_ARCH_SYSCALL +#endif + extern syscall_handler_t sys_fork; -extern syscall_handler_t sys_creat; -extern syscall_handler_t sys_link; -extern syscall_handler_t sys_unlink; -extern syscall_handler_t sys_chdir; -extern syscall_handler_t sys_mknod; -extern syscall_handler_t sys_chmod; -extern syscall_handler_t sys_lchown16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_stat; -extern syscall_handler_t sys_getpid; -extern syscall_handler_t sys_oldumount; -extern syscall_handler_t sys_setuid16; -extern syscall_handler_t sys_getuid16; +extern syscall_handler_t sys_execve; +extern syscall_handler_t um_time; +extern syscall_handler_t um_mount; +extern syscall_handler_t um_stime; extern syscall_handler_t sys_ptrace; -extern syscall_handler_t sys_alarm; -extern syscall_handler_t sys_fstat; -extern syscall_handler_t sys_pause; -extern syscall_handler_t sys_utime; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_access; -extern syscall_handler_t sys_nice; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_sync; -extern syscall_handler_t sys_kill; -extern syscall_handler_t sys_rename; -extern syscall_handler_t sys_mkdir; -extern syscall_handler_t sys_rmdir; extern syscall_handler_t sys_pipe; -extern syscall_handler_t sys_times; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_brk; -extern syscall_handler_t sys_setgid16; -extern syscall_handler_t sys_getgid16; -extern syscall_handler_t sys_signal; -extern syscall_handler_t sys_geteuid16; -extern syscall_handler_t sys_getegid16; -extern syscall_handler_t sys_acct; -extern syscall_handler_t sys_umount; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ioctl; -extern syscall_handler_t sys_fcntl; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setpgid; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_olduname; -extern syscall_handler_t sys_umask; -extern syscall_handler_t sys_chroot; -extern syscall_handler_t sys_ustat; -extern syscall_handler_t sys_dup2; -extern syscall_handler_t sys_getppid; -extern syscall_handler_t sys_getpgrp; extern syscall_handler_t sys_sigaction; -extern syscall_handler_t sys_sgetmask; -extern syscall_handler_t sys_ssetmask; -extern syscall_handler_t sys_setreuid16; -extern syscall_handler_t sys_setregid16; extern syscall_handler_t sys_sigsuspend; -extern syscall_handler_t sys_sigpending; -extern syscall_handler_t sys_sethostname; -extern syscall_handler_t sys_setrlimit; -extern syscall_handler_t sys_old_getrlimit; -extern syscall_handler_t sys_getrusage; -extern syscall_handler_t sys_gettimeofday; -extern syscall_handler_t sys_settimeofday; -extern syscall_handler_t sys_getgroups16; -extern syscall_handler_t sys_setgroups16; -extern syscall_handler_t sys_symlink; -extern syscall_handler_t sys_lstat; -extern syscall_handler_t sys_readlink; -extern syscall_handler_t sys_swapon; -extern syscall_handler_t sys_uselib; -extern syscall_handler_t sys_reboot; extern syscall_handler_t old_readdir; -extern syscall_handler_t sys_munmap; -extern syscall_handler_t sys_truncate; -extern syscall_handler_t sys_ftruncate; -extern syscall_handler_t sys_fchmod; -extern syscall_handler_t sys_fchown16; -extern syscall_handler_t sys_getpriority; -extern syscall_handler_t sys_setpriority; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_statfs; -extern syscall_handler_t sys_fstatfs; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_socketcall; -extern syscall_handler_t sys_syslog; -extern syscall_handler_t sys_setitimer; -extern syscall_handler_t sys_getitimer; -extern syscall_handler_t sys_newstat; -extern syscall_handler_t sys_newlstat; -extern syscall_handler_t sys_newfstat; extern syscall_handler_t sys_uname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_vhangup; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_swapoff; -extern syscall_handler_t sys_sysinfo; extern syscall_handler_t sys_ipc; -extern syscall_handler_t sys_fsync; extern syscall_handler_t sys_sigreturn; -extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_clone; -extern syscall_handler_t sys_setdomainname; -extern syscall_handler_t sys_newuname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_adjtimex; -extern syscall_handler_t sys_mprotect; -extern syscall_handler_t sys_sigprocmask; -extern syscall_handler_t sys_init_module; -extern syscall_handler_t sys_delete_module; -extern syscall_handler_t sys_quotactl; -extern syscall_handler_t sys_getpgid; -extern syscall_handler_t sys_fchdir; -extern syscall_handler_t sys_bdflush; -extern syscall_handler_t sys_sysfs; -extern syscall_handler_t sys_personality; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setfsuid16; -extern syscall_handler_t sys_setfsgid16; -extern syscall_handler_t sys_llseek; -extern syscall_handler_t sys_getdents; -extern syscall_handler_t sys_flock; -extern syscall_handler_t sys_msync; -extern syscall_handler_t sys_readv; -extern syscall_handler_t sys_writev; -extern syscall_handler_t sys_getsid; -extern syscall_handler_t sys_fdatasync; -extern syscall_handler_t sys_mlock; -extern syscall_handler_t sys_munlock; -extern syscall_handler_t sys_mlockall; -extern syscall_handler_t sys_munlockall; -extern syscall_handler_t sys_sched_setparam; -extern syscall_handler_t sys_sched_getparam; -extern syscall_handler_t sys_sched_setscheduler; -extern syscall_handler_t sys_sched_getscheduler; -extern syscall_handler_t sys_sched_get_priority_max; -extern syscall_handler_t sys_sched_get_priority_min; -extern syscall_handler_t sys_sched_rr_get_interval; -extern syscall_handler_t sys_nanosleep; -extern syscall_handler_t sys_mremap; -extern syscall_handler_t sys_setresuid16; -extern syscall_handler_t sys_getresuid16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_poll; -extern syscall_handler_t sys_nfsservctl; -extern syscall_handler_t sys_setresgid16; -extern syscall_handler_t sys_getresgid16; -extern syscall_handler_t sys_prctl; -extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_rt_sigaction; -extern syscall_handler_t sys_rt_sigprocmask; -extern syscall_handler_t sys_rt_sigpending; -extern syscall_handler_t sys_rt_sigtimedwait; -extern syscall_handler_t sys_rt_sigqueueinfo; -extern syscall_handler_t sys_rt_sigsuspend; -extern syscall_handler_t sys_pread64; -extern syscall_handler_t sys_pwrite64; -extern syscall_handler_t sys_chown16; -extern syscall_handler_t sys_getcwd; -extern syscall_handler_t sys_capget; -extern syscall_handler_t sys_capset; extern syscall_handler_t sys_sigaltstack; -extern syscall_handler_t sys_sendfile; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_vfork; -extern syscall_handler_t sys_getrlimit; extern syscall_handler_t sys_mmap2; -extern syscall_handler_t sys_truncate64; -extern syscall_handler_t sys_ftruncate64; -extern syscall_handler_t sys_stat64; -extern syscall_handler_t sys_lstat64; -extern syscall_handler_t sys_fstat64; -extern syscall_handler_t sys_lchown; -extern syscall_handler_t sys_getuid; -extern syscall_handler_t sys_getgid; -extern syscall_handler_t sys_geteuid; -extern syscall_handler_t sys_getegid; -extern syscall_handler_t sys_setreuid; -extern syscall_handler_t sys_setregid; -extern syscall_handler_t sys_getgroups; -extern syscall_handler_t sys_setgroups; -extern syscall_handler_t sys_fchown; -extern syscall_handler_t sys_setresuid; -extern syscall_handler_t sys_getresuid; -extern syscall_handler_t sys_setresgid; -extern syscall_handler_t sys_getresgid; -extern syscall_handler_t sys_chown; -extern syscall_handler_t sys_setuid; -extern syscall_handler_t sys_setgid; -extern syscall_handler_t sys_setfsuid; -extern syscall_handler_t sys_setfsgid; -extern syscall_handler_t sys_pivot_root; -extern syscall_handler_t sys_mincore; -extern syscall_handler_t sys_madvise; -extern syscall_handler_t sys_fcntl64; -extern syscall_handler_t sys_getdents64; -extern syscall_handler_t sys_gettid; -extern syscall_handler_t sys_readahead; -extern syscall_handler_t sys_tkill; -extern syscall_handler_t sys_sendfile64; -extern syscall_handler_t sys_futex; -extern syscall_handler_t sys_sched_setaffinity; -extern syscall_handler_t sys_sched_getaffinity; -extern syscall_handler_t sys_io_setup; -extern syscall_handler_t sys_io_destroy; -extern syscall_handler_t sys_io_getevents; -extern syscall_handler_t sys_io_submit; -extern syscall_handler_t sys_io_cancel; -extern syscall_handler_t sys_exit_group; -extern syscall_handler_t sys_lookup_dcookie; -extern syscall_handler_t sys_epoll_create; -extern syscall_handler_t sys_epoll_ctl; -extern syscall_handler_t sys_epoll_wait; -extern syscall_handler_t sys_remap_file_pages; -extern syscall_handler_t sys_set_tid_address; - -#ifdef CONFIG_NFSD -#define NFSSERVCTL sys_nfsservctl -#else -#define NFSSERVCTL sys_ni_syscall -#endif - -extern syscall_handler_t um_mount; -extern syscall_handler_t um_time; -extern syscall_handler_t um_stime; - -#define LAST_GENERIC_SYSCALL __NR_set_tid_address - -#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL -#define LAST_SYSCALL LAST_GENERIC_SYSCALL -#else -#define LAST_SYSCALL LAST_ARCH_SYSCALL -#endif +extern syscall_handler_t sys_timer_create; +extern syscall_handler_t old_mmap_i386; +extern syscall_handler_t old_select; +extern syscall_handler_t sys_modify_ldt; +extern syscall_handler_t sys_rt_sigsuspend; +extern syscall_handler_t sys_vserver; syscall_handler_t *sys_call_table[] = { - [ __NR_restart_syscall ] = sys_restart_syscall, - [ __NR_exit ] = sys_exit, - [ __NR_fork ] = sys_fork, + [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, + [ __NR_exit ] (syscall_handler_t *) sys_exit, + [ __NR_fork ] (syscall_handler_t *) sys_fork, [ __NR_read ] = (syscall_handler_t *) sys_read, [ __NR_write ] = (syscall_handler_t *) sys_write, @@ -266,229 +65,249 @@ syscall_handler_t *sys_call_table[] = { [ __NR_open ] = (syscall_handler_t *) sys_open, [ __NR_close ] = (syscall_handler_t *) sys_close, [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, - [ __NR_creat ] = sys_creat, - [ __NR_link ] = sys_link, - [ __NR_unlink ] = sys_unlink, + [ __NR_creat ] (syscall_handler_t *) sys_creat, + [ __NR_link ] (syscall_handler_t *) sys_link, + [ __NR_unlink ] (syscall_handler_t *) sys_unlink, [ __NR_execve ] = (syscall_handler_t *) sys_execve, /* declared differently in kern_util.h */ - [ __NR_chdir ] = sys_chdir, + [ __NR_chdir ] (syscall_handler_t *) sys_chdir, [ __NR_time ] = um_time, - [ __NR_mknod ] = sys_mknod, - [ __NR_chmod ] = sys_chmod, - [ __NR_lchown ] = sys_lchown16, - [ __NR_break ] = sys_ni_syscall, - [ __NR_oldstat ] = sys_stat, + [ __NR_mknod ] (syscall_handler_t *) sys_mknod, + [ __NR_chmod ] (syscall_handler_t *) sys_chmod, + [ __NR_lchown ] (syscall_handler_t *) sys_lchown16, + [ __NR_break ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldstat ] (syscall_handler_t *) sys_stat, [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, - [ __NR_getpid ] = sys_getpid, + [ __NR_getpid ] (syscall_handler_t *) sys_getpid, [ __NR_mount ] = um_mount, - [ __NR_umount ] = sys_oldumount, - [ __NR_setuid ] = sys_setuid16, - [ __NR_getuid ] = sys_getuid16, + [ __NR_umount ] (syscall_handler_t *) sys_oldumount, + [ __NR_setuid ] (syscall_handler_t *) sys_setuid16, + [ __NR_getuid ] (syscall_handler_t *) sys_getuid16, [ __NR_stime ] = um_stime, - [ __NR_ptrace ] = sys_ptrace, - [ __NR_alarm ] = sys_alarm, - [ __NR_oldfstat ] = sys_fstat, - [ __NR_pause ] = sys_pause, - [ __NR_utime ] = sys_utime, - [ __NR_stty ] = sys_ni_syscall, - [ __NR_gtty ] = sys_ni_syscall, - [ __NR_access ] = sys_access, - [ __NR_nice ] = sys_nice, - [ __NR_ftime ] = sys_ni_syscall, - [ __NR_sync ] = sys_sync, - [ __NR_kill ] = sys_kill, - [ __NR_rename ] = sys_rename, - [ __NR_mkdir ] = sys_mkdir, - [ __NR_rmdir ] = sys_rmdir, + [ __NR_ptrace ] (syscall_handler_t *) sys_ptrace, + [ __NR_alarm ] (syscall_handler_t *) sys_alarm, + [ __NR_oldfstat ] (syscall_handler_t *) sys_fstat, + [ __NR_pause ] (syscall_handler_t *) sys_pause, + [ __NR_utime ] (syscall_handler_t *) sys_utime, + [ __NR_stty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gtty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_access ] (syscall_handler_t *) sys_access, + [ __NR_nice ] (syscall_handler_t *) sys_nice, + [ __NR_ftime ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_sync ] (syscall_handler_t *) sys_sync, + [ __NR_kill ] (syscall_handler_t *) sys_kill, + [ __NR_rename ] (syscall_handler_t *) sys_rename, + [ __NR_mkdir ] (syscall_handler_t *) sys_mkdir, + [ __NR_rmdir ] (syscall_handler_t *) sys_rmdir, /* Declared differently in asm/unistd.h */ [ __NR_dup ] = (syscall_handler_t *) sys_dup, - [ __NR_pipe ] = sys_pipe, - [ __NR_times ] = sys_times, - [ __NR_prof ] = sys_ni_syscall, - [ __NR_brk ] = sys_brk, - [ __NR_setgid ] = sys_setgid16, - [ __NR_getgid ] = sys_getgid16, - [ __NR_signal ] = sys_signal, - [ __NR_geteuid ] = sys_geteuid16, - [ __NR_getegid ] = sys_getegid16, - [ __NR_acct ] = sys_acct, - [ __NR_umount2 ] = sys_umount, - [ __NR_lock ] = sys_ni_syscall, - [ __NR_ioctl ] = sys_ioctl, - [ __NR_fcntl ] = sys_fcntl, - [ __NR_mpx ] = sys_ni_syscall, - [ __NR_setpgid ] = sys_setpgid, - [ __NR_ulimit ] = sys_ni_syscall, - [ __NR_oldolduname ] = sys_olduname, - [ __NR_umask ] = sys_umask, - [ __NR_chroot ] = sys_chroot, - [ __NR_ustat ] = sys_ustat, - [ __NR_dup2 ] = sys_dup2, - [ __NR_getppid ] = sys_getppid, - [ __NR_getpgrp ] = sys_getpgrp, + [ __NR_pipe ] (syscall_handler_t *) sys_pipe, + [ __NR_times ] (syscall_handler_t *) sys_times, + [ __NR_prof ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_brk ] (syscall_handler_t *) sys_brk, + [ __NR_setgid ] (syscall_handler_t *) sys_setgid16, + [ __NR_getgid ] (syscall_handler_t *) sys_getgid16, + [ __NR_signal ] (syscall_handler_t *) sys_signal, + [ __NR_geteuid ] (syscall_handler_t *) sys_geteuid16, + [ __NR_getegid ] (syscall_handler_t *) sys_getegid16, + [ __NR_acct ] (syscall_handler_t *) sys_acct, + [ __NR_umount2 ] (syscall_handler_t *) sys_umount, + [ __NR_lock ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_ioctl ] (syscall_handler_t *) sys_ioctl, + [ __NR_fcntl ] (syscall_handler_t *) sys_fcntl, + [ __NR_mpx ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setpgid ] (syscall_handler_t *) sys_setpgid, + [ __NR_ulimit ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldolduname ] (syscall_handler_t *) sys_olduname, + [ __NR_umask ] (syscall_handler_t *) sys_umask, + [ __NR_chroot ] (syscall_handler_t *) sys_chroot, + [ __NR_ustat ] (syscall_handler_t *) sys_ustat, + [ __NR_dup2 ] (syscall_handler_t *) sys_dup2, + [ __NR_getppid ] (syscall_handler_t *) sys_getppid, + [ __NR_getpgrp ] (syscall_handler_t *) sys_getpgrp, [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_sigaction ] = sys_sigaction, - [ __NR_sgetmask ] = sys_sgetmask, - [ __NR_ssetmask ] = sys_ssetmask, - [ __NR_setreuid ] = sys_setreuid16, - [ __NR_setregid ] = sys_setregid16, - [ __NR_sigsuspend ] = sys_sigsuspend, - [ __NR_sigpending ] = sys_sigpending, - [ __NR_sethostname ] = sys_sethostname, - [ __NR_setrlimit ] = sys_setrlimit, - [ __NR_getrlimit ] = sys_old_getrlimit, - [ __NR_getrusage ] = sys_getrusage, - [ __NR_gettimeofday ] = sys_gettimeofday, - [ __NR_settimeofday ] = sys_settimeofday, - [ __NR_getgroups ] = sys_getgroups16, - [ __NR_setgroups ] = sys_setgroups16, - [ __NR_symlink ] = sys_symlink, - [ __NR_oldlstat ] = sys_lstat, - [ __NR_readlink ] = sys_readlink, - [ __NR_uselib ] = sys_uselib, + [ __NR_sigaction ] (syscall_handler_t *) sys_sigaction, + [ __NR_sgetmask ] (syscall_handler_t *) sys_sgetmask, + [ __NR_ssetmask ] (syscall_handler_t *) sys_ssetmask, + [ __NR_setreuid ] (syscall_handler_t *) sys_setreuid16, + [ __NR_setregid ] (syscall_handler_t *) sys_setregid16, + [ __NR_sigsuspend ] (syscall_handler_t *) sys_sigsuspend, + [ __NR_sigpending ] (syscall_handler_t *) sys_sigpending, + [ __NR_sethostname ] (syscall_handler_t *) sys_sethostname, + [ __NR_setrlimit ] (syscall_handler_t *) sys_setrlimit, + [ __NR_getrlimit ] (syscall_handler_t *) sys_old_getrlimit, + [ __NR_getrusage ] (syscall_handler_t *) sys_getrusage, + [ __NR_gettimeofday ] (syscall_handler_t *) sys_gettimeofday, + [ __NR_settimeofday ] (syscall_handler_t *) sys_settimeofday, + [ __NR_getgroups ] (syscall_handler_t *) sys_getgroups16, + [ __NR_setgroups ] (syscall_handler_t *) sys_setgroups16, + [ __NR_symlink ] (syscall_handler_t *) sys_symlink, + [ __NR_oldlstat ] (syscall_handler_t *) sys_lstat, + [ __NR_readlink ] (syscall_handler_t *) sys_readlink, + [ __NR_uselib ] (syscall_handler_t *) sys_uselib, [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, - [ __NR_reboot ] = sys_reboot, + [ __NR_reboot ] (syscall_handler_t *) sys_reboot, [ __NR_readdir ] = old_readdir, - [ __NR_munmap ] = sys_munmap, - [ __NR_truncate ] = sys_truncate, - [ __NR_ftruncate ] = sys_ftruncate, - [ __NR_fchmod ] = sys_fchmod, - [ __NR_fchown ] = sys_fchown16, - [ __NR_getpriority ] = sys_getpriority, - [ __NR_setpriority ] = sys_setpriority, - [ __NR_profil ] = sys_ni_syscall, - [ __NR_statfs ] = sys_statfs, - [ __NR_fstatfs ] = sys_fstatfs, - [ __NR_ioperm ] = sys_ni_syscall, - [ __NR_socketcall ] = sys_socketcall, - [ __NR_syslog ] = sys_syslog, - [ __NR_setitimer ] = sys_setitimer, - [ __NR_getitimer ] = sys_getitimer, - [ __NR_stat ] = sys_newstat, - [ __NR_lstat ] = sys_newlstat, - [ __NR_fstat ] = sys_newfstat, - [ __NR_olduname ] = sys_uname, - [ __NR_iopl ] = sys_ni_syscall, - [ __NR_vhangup ] = sys_vhangup, - [ __NR_idle ] = sys_ni_syscall, + [ __NR_munmap ] (syscall_handler_t *) sys_munmap, + [ __NR_truncate ] (syscall_handler_t *) sys_truncate, + [ __NR_ftruncate ] (syscall_handler_t *) sys_ftruncate, + [ __NR_fchmod ] (syscall_handler_t *) sys_fchmod, + [ __NR_fchown ] (syscall_handler_t *) sys_fchown16, + [ __NR_getpriority ] (syscall_handler_t *) sys_getpriority, + [ __NR_setpriority ] (syscall_handler_t *) sys_setpriority, + [ __NR_profil ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_statfs ] (syscall_handler_t *) sys_statfs, + [ __NR_fstatfs ] (syscall_handler_t *) sys_fstatfs, + [ __NR_ioperm ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_socketcall ] (syscall_handler_t *) sys_socketcall, + [ __NR_syslog ] (syscall_handler_t *) sys_syslog, + [ __NR_setitimer ] (syscall_handler_t *) sys_setitimer, + [ __NR_getitimer ] (syscall_handler_t *) sys_getitimer, + [ __NR_stat ] (syscall_handler_t *) sys_newstat, + [ __NR_lstat ] (syscall_handler_t *) sys_newlstat, + [ __NR_fstat ] (syscall_handler_t *) sys_newfstat, + [ __NR_olduname ] (syscall_handler_t *) sys_uname, + [ __NR_iopl ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vhangup ] (syscall_handler_t *) sys_vhangup, + [ __NR_idle ] (syscall_handler_t *) sys_ni_syscall, [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, - [ __NR_sysinfo ] = sys_sysinfo, - [ __NR_ipc ] = sys_ipc, - [ __NR_fsync ] = sys_fsync, - [ __NR_sigreturn ] = sys_sigreturn, - [ __NR_clone ] = sys_clone, - [ __NR_setdomainname ] = sys_setdomainname, - [ __NR_uname ] = sys_newuname, - [ __NR_adjtimex ] = sys_adjtimex, - [ __NR_mprotect ] = sys_mprotect, - [ __NR_sigprocmask ] = sys_sigprocmask, - [ __NR_create_module ] = sys_ni_syscall, - [ __NR_init_module ] = sys_init_module, - [ __NR_delete_module ] = sys_delete_module, - [ __NR_get_kernel_syms ] = sys_ni_syscall, - [ __NR_quotactl ] = sys_quotactl, - [ __NR_getpgid ] = sys_getpgid, - [ __NR_fchdir ] = sys_fchdir, - [ __NR_bdflush ] = sys_bdflush, - [ __NR_sysfs ] = sys_sysfs, - [ __NR_personality ] = sys_personality, - [ __NR_afs_syscall ] = sys_ni_syscall, - [ __NR_setfsuid ] = sys_setfsuid16, - [ __NR_setfsgid ] = sys_setfsgid16, - [ __NR__llseek ] = sys_llseek, - [ __NR_getdents ] = sys_getdents, + [ __NR_sysinfo ] (syscall_handler_t *) sys_sysinfo, + [ __NR_ipc ] (syscall_handler_t *) sys_ipc, + [ __NR_fsync ] (syscall_handler_t *) sys_fsync, + [ __NR_sigreturn ] (syscall_handler_t *) sys_sigreturn, + [ __NR_clone ] (syscall_handler_t *) sys_clone, + [ __NR_setdomainname ] (syscall_handler_t *) sys_setdomainname, + [ __NR_uname ] (syscall_handler_t *) sys_newuname, + [ __NR_adjtimex ] (syscall_handler_t *) sys_adjtimex, + [ __NR_mprotect ] (syscall_handler_t *) sys_mprotect, + [ __NR_sigprocmask ] (syscall_handler_t *) sys_sigprocmask, + [ __NR_create_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_init_module ] (syscall_handler_t *) sys_init_module, + [ __NR_delete_module ] (syscall_handler_t *) sys_delete_module, + [ __NR_get_kernel_syms ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_quotactl ] (syscall_handler_t *) sys_quotactl, + [ __NR_getpgid ] (syscall_handler_t *) sys_getpgid, + [ __NR_fchdir ] (syscall_handler_t *) sys_fchdir, + [ __NR_bdflush ] (syscall_handler_t *) sys_bdflush, + [ __NR_sysfs ] (syscall_handler_t *) sys_sysfs, + [ __NR_personality ] (syscall_handler_t *) sys_personality, + [ __NR_afs_syscall ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setfsuid ] (syscall_handler_t *) sys_setfsuid16, + [ __NR_setfsgid ] (syscall_handler_t *) sys_setfsgid16, + [ __NR__llseek ] (syscall_handler_t *) sys_llseek, + [ __NR_getdents ] (syscall_handler_t *) sys_getdents, [ __NR__newselect ] = (syscall_handler_t *) sys_select, - [ __NR_flock ] = sys_flock, - [ __NR_msync ] = sys_msync, - [ __NR_readv ] = sys_readv, - [ __NR_writev ] = sys_writev, - [ __NR_getsid ] = sys_getsid, - [ __NR_fdatasync ] = sys_fdatasync, + [ __NR_flock ] (syscall_handler_t *) sys_flock, + [ __NR_msync ] (syscall_handler_t *) sys_msync, + [ __NR_readv ] (syscall_handler_t *) sys_readv, + [ __NR_writev ] (syscall_handler_t *) sys_writev, + [ __NR_getsid ] (syscall_handler_t *) sys_getsid, + [ __NR_fdatasync ] (syscall_handler_t *) sys_fdatasync, [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, - [ __NR_mlock ] = sys_mlock, - [ __NR_munlock ] = sys_munlock, - [ __NR_mlockall ] = sys_mlockall, - [ __NR_munlockall ] = sys_munlockall, - [ __NR_sched_setparam ] = sys_sched_setparam, - [ __NR_sched_getparam ] = sys_sched_getparam, - [ __NR_sched_setscheduler ] = sys_sched_setscheduler, - [ __NR_sched_getscheduler ] = sys_sched_getscheduler, + [ __NR_mlock ] (syscall_handler_t *) sys_mlock, + [ __NR_munlock ] (syscall_handler_t *) sys_munlock, + [ __NR_mlockall ] (syscall_handler_t *) sys_mlockall, + [ __NR_munlockall ] (syscall_handler_t *) sys_munlockall, + [ __NR_sched_setparam ] (syscall_handler_t *) sys_sched_setparam, + [ __NR_sched_getparam ] (syscall_handler_t *) sys_sched_getparam, + [ __NR_sched_setscheduler ] (syscall_handler_t *) sys_sched_setscheduler, + [ __NR_sched_getscheduler ] (syscall_handler_t *) sys_sched_getscheduler, [ __NR_sched_yield ] = (syscall_handler_t *) yield, - [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, - [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min, - [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval, - [ __NR_nanosleep ] = sys_nanosleep, - [ __NR_mremap ] = sys_mremap, - [ __NR_setresuid ] = sys_setresuid16, - [ __NR_getresuid ] = sys_getresuid16, - [ __NR_vm86 ] = sys_ni_syscall, - [ __NR_query_module ] = sys_ni_syscall, - [ __NR_poll ] = sys_poll, - [ __NR_nfsservctl ] = NFSSERVCTL, - [ __NR_setresgid ] = sys_setresgid16, - [ __NR_getresgid ] = sys_getresgid16, - [ __NR_prctl ] = sys_prctl, - [ __NR_rt_sigreturn ] = sys_rt_sigreturn, - [ __NR_rt_sigaction ] = sys_rt_sigaction, - [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask, - [ __NR_rt_sigpending ] = sys_rt_sigpending, - [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait, - [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo, - [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend, - [ __NR_pread64 ] = sys_pread64, - [ __NR_pwrite64 ] = sys_pwrite64, - [ __NR_chown ] = sys_chown16, - [ __NR_getcwd ] = sys_getcwd, - [ __NR_capget ] = sys_capget, - [ __NR_capset ] = sys_capset, - [ __NR_sigaltstack ] = sys_sigaltstack, - [ __NR_sendfile ] = sys_sendfile, - [ __NR_getpmsg ] = sys_ni_syscall, - [ __NR_putpmsg ] = sys_ni_syscall, - [ __NR_vfork ] = sys_vfork, - [ __NR_ugetrlimit ] = sys_getrlimit, - [ __NR_mmap2 ] = sys_mmap2, - [ __NR_truncate64 ] = sys_truncate64, - [ __NR_ftruncate64 ] = sys_ftruncate64, - [ __NR_stat64 ] = sys_stat64, - [ __NR_lstat64 ] = sys_lstat64, - [ __NR_fstat64 ] = sys_fstat64, - [ __NR_fcntl64 ] = sys_fcntl64, - [ __NR_getdents64 ] = sys_getdents64, - [ __NR_gettid ] = sys_gettid, - [ __NR_readahead ] = sys_readahead, - [ __NR_setxattr ] = sys_ni_syscall, - [ __NR_lsetxattr ] = sys_ni_syscall, - [ __NR_fsetxattr ] = sys_ni_syscall, - [ __NR_getxattr ] = sys_ni_syscall, - [ __NR_lgetxattr ] = sys_ni_syscall, - [ __NR_fgetxattr ] = sys_ni_syscall, - [ __NR_listxattr ] = sys_ni_syscall, - [ __NR_llistxattr ] = sys_ni_syscall, - [ __NR_flistxattr ] = sys_ni_syscall, - [ __NR_removexattr ] = sys_ni_syscall, - [ __NR_lremovexattr ] = sys_ni_syscall, - [ __NR_fremovexattr ] = sys_ni_syscall, - [ __NR_tkill ] = sys_tkill, - [ __NR_sendfile64 ] = sys_sendfile64, - [ __NR_futex ] = sys_futex, - [ __NR_sched_setaffinity ] = sys_sched_setaffinity, - [ __NR_sched_getaffinity ] = sys_sched_getaffinity, - [ __NR_io_setup ] = sys_io_setup, - [ __NR_io_destroy ] = sys_io_destroy, - [ __NR_io_getevents ] = sys_io_getevents, - [ __NR_io_submit ] = sys_io_submit, - [ __NR_io_cancel ] = sys_io_cancel, - [ __NR_exit_group ] = sys_exit_group, - [ __NR_lookup_dcookie ] = sys_lookup_dcookie, - [ __NR_epoll_create ] = sys_epoll_create, - [ __NR_epoll_ctl ] = sys_epoll_ctl, - [ __NR_epoll_wait ] = sys_epoll_wait, - [ __NR_remap_file_pages ] = sys_remap_file_pages, - [ __NR_set_tid_address ] = sys_set_tid_address, + [ __NR_sched_get_priority_max ] (syscall_handler_t *) sys_sched_get_priority_max, + [ __NR_sched_get_priority_min ] (syscall_handler_t *) sys_sched_get_priority_min, + [ __NR_sched_rr_get_interval ] (syscall_handler_t *) sys_sched_rr_get_interval, + [ __NR_nanosleep ] (syscall_handler_t *) sys_nanosleep, + [ __NR_mremap ] (syscall_handler_t *) sys_mremap, + [ __NR_setresuid ] (syscall_handler_t *) sys_setresuid16, + [ __NR_getresuid ] (syscall_handler_t *) sys_getresuid16, + [ __NR_vm86 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_query_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_poll ] (syscall_handler_t *) sys_poll, + [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, + [ __NR_setresgid ] (syscall_handler_t *) sys_setresgid16, + [ __NR_getresgid ] (syscall_handler_t *) sys_getresgid16, + [ __NR_prctl ] (syscall_handler_t *) sys_prctl, + [ __NR_rt_sigreturn ] (syscall_handler_t *) sys_rt_sigreturn, + [ __NR_rt_sigaction ] (syscall_handler_t *) sys_rt_sigaction, + [ __NR_rt_sigprocmask ] (syscall_handler_t *) sys_rt_sigprocmask, + [ __NR_rt_sigpending ] (syscall_handler_t *) sys_rt_sigpending, + [ __NR_rt_sigtimedwait ] (syscall_handler_t *) sys_rt_sigtimedwait, + [ __NR_rt_sigqueueinfo ] (syscall_handler_t *) sys_rt_sigqueueinfo, + [ __NR_rt_sigsuspend ] (syscall_handler_t *) sys_rt_sigsuspend, + [ __NR_pread64 ] (syscall_handler_t *) sys_pread64, + [ __NR_pwrite64 ] (syscall_handler_t *) sys_pwrite64, + [ __NR_chown ] (syscall_handler_t *) sys_chown16, + [ __NR_getcwd ] (syscall_handler_t *) sys_getcwd, + [ __NR_capget ] (syscall_handler_t *) sys_capget, + [ __NR_capset ] (syscall_handler_t *) sys_capset, + [ __NR_sigaltstack ] (syscall_handler_t *) sys_sigaltstack, + [ __NR_sendfile ] (syscall_handler_t *) sys_sendfile, + [ __NR_getpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_putpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vfork ] (syscall_handler_t *) sys_vfork, + [ __NR_ugetrlimit ] (syscall_handler_t *) sys_getrlimit, + [ __NR_mmap2 ] (syscall_handler_t *) sys_mmap2, + [ __NR_truncate64 ] (syscall_handler_t *) sys_truncate64, + [ __NR_ftruncate64 ] (syscall_handler_t *) sys_ftruncate64, + [ __NR_stat64 ] (syscall_handler_t *) sys_stat64, + [ __NR_lstat64 ] (syscall_handler_t *) sys_lstat64, + [ __NR_fstat64 ] (syscall_handler_t *) sys_fstat64, + [ __NR_getdents64 ] (syscall_handler_t *) sys_getdents64, + [ __NR_fcntl64 ] (syscall_handler_t *) sys_fcntl64, + [ 223 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gettid ] (syscall_handler_t *) sys_gettid, + [ __NR_readahead ] (syscall_handler_t *) sys_readahead, + [ __NR_setxattr ] (syscall_handler_t *) sys_setxattr, + [ __NR_lsetxattr ] (syscall_handler_t *) sys_lsetxattr, + [ __NR_fsetxattr ] (syscall_handler_t *) sys_fsetxattr, + [ __NR_getxattr ] (syscall_handler_t *) sys_getxattr, + [ __NR_lgetxattr ] (syscall_handler_t *) sys_lgetxattr, + [ __NR_fgetxattr ] (syscall_handler_t *) sys_fgetxattr, + [ __NR_listxattr ] (syscall_handler_t *) sys_listxattr, + [ __NR_llistxattr ] (syscall_handler_t *) sys_llistxattr, + [ __NR_flistxattr ] (syscall_handler_t *) sys_flistxattr, + [ __NR_removexattr ] (syscall_handler_t *) sys_removexattr, + [ __NR_lremovexattr ] (syscall_handler_t *) sys_lremovexattr, + [ __NR_fremovexattr ] (syscall_handler_t *) sys_fremovexattr, + [ __NR_tkill ] (syscall_handler_t *) sys_tkill, + [ __NR_sendfile64 ] (syscall_handler_t *) sys_sendfile64, + [ __NR_futex ] (syscall_handler_t *) sys_futex, + [ __NR_sched_setaffinity ] (syscall_handler_t *) sys_sched_setaffinity, + [ __NR_sched_getaffinity ] (syscall_handler_t *) sys_sched_getaffinity, + [ __NR_set_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_get_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_io_setup ] (syscall_handler_t *) sys_io_setup, + [ __NR_io_destroy ] (syscall_handler_t *) sys_io_destroy, + [ __NR_io_getevents ] (syscall_handler_t *) sys_io_getevents, + [ __NR_io_submit ] (syscall_handler_t *) sys_io_submit, + [ __NR_io_cancel ] (syscall_handler_t *) sys_io_cancel, + [ __NR_fadvise64 ] (syscall_handler_t *) sys_fadvise64, + [ 251 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_exit_group ] (syscall_handler_t *) sys_exit_group, + [ __NR_lookup_dcookie ] (syscall_handler_t *) sys_lookup_dcookie, + [ __NR_epoll_create ] (syscall_handler_t *) sys_epoll_create, + [ __NR_epoll_ctl ] (syscall_handler_t *) sys_epoll_ctl, + [ __NR_epoll_wait ] (syscall_handler_t *) sys_epoll_wait, + [ __NR_remap_file_pages ] (syscall_handler_t *) sys_remap_file_pages, + [ __NR_set_tid_address ] (syscall_handler_t *) sys_set_tid_address, + [ __NR_timer_create ] (syscall_handler_t *) sys_timer_create, + [ __NR_timer_settime ] (syscall_handler_t *) sys_timer_settime, + [ __NR_timer_gettime ] (syscall_handler_t *) sys_timer_gettime, + [ __NR_timer_getoverrun ] (syscall_handler_t *) sys_timer_getoverrun, + [ __NR_timer_delete ] (syscall_handler_t *) sys_timer_delete, + [ __NR_clock_settime ] (syscall_handler_t *) sys_clock_settime, + [ __NR_clock_gettime ] (syscall_handler_t *) sys_clock_gettime, + [ __NR_clock_getres ] (syscall_handler_t *) sys_clock_getres, + [ __NR_clock_nanosleep ] (syscall_handler_t *) sys_clock_nanosleep, + [ __NR_statfs64 ] (syscall_handler_t *) sys_statfs64, + [ __NR_fstatfs64 ] (syscall_handler_t *) sys_fstatfs64, + [ __NR_tgkill ] (syscall_handler_t *) sys_tgkill, + [ __NR_utimes ] (syscall_handler_t *) sys_utimes, + [ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64, + [ __NR_vserver ] (syscall_handler_t *) sys_vserver, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index 2af5fc2e5..801e66e1c 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -36,39 +36,40 @@ long um_mount(char * dev_name, char * dir_name, char * type, long sys_fork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } -long sys_clone(unsigned long clone_flags, unsigned long newsp) +long sys_clone(unsigned long clone_flags, unsigned long newsp, + int *parent_tid, int *child_tid) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } long sys_vfork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, + NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } /* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) +long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long pgoff) { int error = -EBADF; struct file * file = NULL; @@ -80,9 +81,9 @@ static inline long do_mmap2( goto out; } - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); + error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); + up_write(&mm->mmap_sem); if (file) fput(file); @@ -94,7 +95,7 @@ long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); } /* @@ -121,7 +122,8 @@ int old_mmap(unsigned long addr, unsigned long len, if (offset & ~PAGE_MASK) goto out; - err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + err = do_mmap2(current->mm, addr, len, prot, flags, fd, + offset >> PAGE_SHIFT); out: return err; } @@ -136,43 +138,12 @@ int sys_pipe(unsigned long * fildes) error = do_pipe(fd); if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) + if (copy_to_user(fildes, fd, sizeof(fd))) error = -EFAULT; } return error; } -int sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * @@ -254,7 +225,7 @@ int sys_ipc (uint call, int first, int second, return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: - return -EINVAL; + return -ENOSYS; } } @@ -264,7 +235,7 @@ int sys_uname(struct old_utsname * name) if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -272,6 +243,7 @@ int sys_uname(struct old_utsname * name) int sys_olduname(struct oldold_utsname * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -280,19 +252,20 @@ int sys_olduname(struct oldold_utsname * name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname, + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname, __OLD_UTS_LEN); error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + error |= __copy_to_user(&name->nodename,ptr->nodename, __OLD_UTS_LEN); error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, + error |= __copy_to_user(&name->release,ptr->release, __OLD_UTS_LEN); error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, + error |= __copy_to_user(&name->version,ptr->version, __OLD_UTS_LEN); error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, + error |= __copy_to_user(&name->machine,ptr->machine, __OLD_UTS_LEN); error |= __put_user(0,name->machine+__OLD_UTS_LEN); @@ -303,11 +276,6 @@ int sys_olduname(struct oldold_utsname * name) return error; } -int sys_sigaltstack(const stack_t *uss, stack_t *uoss) -{ - return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); -} - long execute_syscall(void *r) { return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index ce108f7d6..7537de1ad 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -44,6 +44,11 @@ void dump_stack(void) } EXPORT_SYMBOL(dump_stack); +void show_stack(struct task_struct *task, unsigned long *sp) +{ + show_trace(sp); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c index 3fd42081d..b1674bc13 100644 --- a/arch/um/kernel/tempfile.c +++ b/arch/um/kernel/tempfile.c @@ -28,6 +28,7 @@ static void __init find_tempdir(void) } if((dir == NULL) || (*dir == '\0')) dir = "/tmp"; + tempdir = malloc(strlen(dir) + 2); if(tempdir == NULL){ fprintf(stderr, "Failed to malloc tempdir, " @@ -49,7 +50,8 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink) else *tempname = 0; strcat(tempname, template); - if((fd = mkstemp(tempname)) < 0){ + fd = mkstemp(tempname); + if(fd < 0){ fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); return -1; @@ -59,7 +61,8 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink) return -1; } if(out_tempname){ - if((*out_tempname = strdup(tempname)) == NULL){ + *out_tempname = strdup(tempname); + if(*out_tempname == NULL){ perror("strdup"); return -1; } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 6f0d7573e..fa0b710b5 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -4,24 +4,33 @@ */ #include +#include #include #include #include #include #include -#include "linux/module.h" #include "user_util.h" #include "kern_util.h" #include "user.h" #include "process.h" #include "signal_user.h" #include "time_user.h" +#include "kern_constants.h" + +/* XXX This really needs to be declared and initialized in a kernel file since + * it's in + */ +extern struct timespec wall_to_monotonic; extern struct timeval xtime; +struct timeval local_offset = { 0, 0 }; + void timer(void) { gettimeofday(&xtime, NULL); + timeradd(&xtime, &local_offset, &xtime); } void set_interval(int timer_type) @@ -66,7 +75,7 @@ void switch_timers(int to_real) errno); } -void idle_timer(void) +void uml_idle_timer(void) { if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) panic("Couldn't unset SIGVTALRM handler"); @@ -76,14 +85,60 @@ void idle_timer(void) set_interval(ITIMER_REAL); } +static unsigned long long get_host_hz(void) +{ + char mhzline[16], *end; + unsigned long long mhz; + int ret, mult, rest, len; + + ret = cpu_feature("cpu MHz", mhzline, + sizeof(mhzline) / sizeof(mhzline[0])); + if(!ret) + panic ("Could not get host MHZ"); + + mhz = strtoul(mhzline, &end, 10); + + /* This business is to parse a floating point number without using + * floating types. + */ + + rest = 0; + mult = 0; + if(*end == '.'){ + end++; + len = strlen(end); + if(len < 6) + mult = 6 - len; + else if(len > 6) + end[6] = '\0'; + rest = strtoul(end, NULL, 10); + while(mult-- > 0) + rest *= 10; + } + + return(1000000 * mhz + rest); +} + +unsigned long long host_hz = 0; + +extern int do_posix_clock_monotonic_gettime(struct timespec *tp); + void time_init(void) { + struct timespec now; + + host_hz = get_host_hz(); if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) panic("Couldn't set SIGVTALRM handler"); set_interval(ITIMER_VIRTUAL); + + do_posix_clock_monotonic_gettime(&now); + wall_to_monotonic.tv_sec = -now.tv_sec; + wall_to_monotonic.tv_nsec = -now.tv_nsec; } -struct timeval local_offset = { 0, 0 }; +/* Declared in linux/time.h, which can't be included here */ +extern void clock_was_set(void); void do_gettimeofday(struct timeval *tv) { @@ -96,15 +151,13 @@ void do_gettimeofday(struct timeval *tv) clock_was_set(); } -EXPORT_SYMBOL(do_gettimeofday); - int do_settimeofday(struct timespec *tv) { struct timeval now; unsigned long flags; struct timeval tv_in; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) return -EINVAL; tv_in.tv_sec = tv->tv_sec; @@ -114,9 +167,9 @@ int do_settimeofday(struct timespec *tv) gettimeofday(&now, NULL); timersub(&tv_in, &now, &local_offset); time_unlock(flags); -} -EXPORT_SYMBOL(do_settimeofday); + return(0); +} void idle_sleep(int secs) { diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 752fd03f2..7209ba578 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -30,22 +30,58 @@ int hz(void) return(HZ); } +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies_64 * (1000000000 / HZ); +} + /* Changed at early boot */ int timer_irq_inited = 0; -/* missed_ticks will be modified after kernel memory has been - * write-protected, so this puts it in a section which will be left - * write-enabled. - */ -int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; +static int first_tick; +static unsigned long long prev_tsc; +static long long delta; /* Deviation per interval */ + +extern unsigned long long host_hz; void timer_irq(union uml_pt_regs *regs) { - int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu]; + unsigned long long ticks = 0; + + if(!timer_irq_inited){ + /* This is to ensure that ticks don't pile up when + * the timer handler is suspended */ + first_tick = 0; + return; + } + + if(first_tick){ +#if defined(CONFIG_UML_REAL_TIME_CLOCK) + unsigned long long tsc; + /* We've had 1 tick */ + tsc = time_stamp(); - if(!timer_irq_inited) return; - missed_ticks[cpu] = 0; - while(ticks--) do_IRQ(TIMER_IRQ, regs); + delta += tsc - prev_tsc; + prev_tsc = tsc; + + ticks += (delta * HZ) / host_hz; + delta -= (ticks * host_hz) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_tsc = time_stamp(); + first_tick = 1; + } + + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } void boot_timer_handler(int sig) @@ -58,12 +94,15 @@ void boot_timer_handler(int sig) do_timer(®s); } -void um_timer(int irq, void *dev, struct pt_regs *regs) +irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) { + unsigned long flags; + do_timer(regs); - write_seqlock(&xtime_lock); + write_seqlock_irqsave(&xtime_lock, flags); timer(); - write_sequnlock(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); + return(IRQ_HANDLED); } long um_time(int * tloc) @@ -81,12 +120,12 @@ long um_time(int * tloc) long um_stime(int * tptr) { int value; - struct timeval new; + struct timespec new; if (get_user(value, tptr)) return -EFAULT; new.tv_sec = value; - new.tv_usec = 0; + new.tv_nsec = 0; do_settimeofday(&new); return 0; } @@ -125,9 +164,11 @@ void __const_udelay(um_udelay_t usecs) void timer_handler(int sig, union uml_pt_regs *regs) { #ifdef CONFIG_SMP + local_irq_disable(); update_process_times(user_context(UPT_SP(regs))); + local_irq_enable(); #endif - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) timer_irq(regs); } @@ -136,6 +177,7 @@ static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED; unsigned long time_lock(void) { unsigned long flags; + spin_lock_irqsave(&timer_spinlock, flags); return(flags); } @@ -150,8 +192,8 @@ int __init timer_init(void) int err; CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); - if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", - NULL)) != 0) + err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); + if(err != 0) printk(KERN_ERR "timer_init : request_irq failed - " "errno = %d\n", -err); timer_irq_inited = 1; @@ -160,7 +202,6 @@ int __init timer_init(void) __initcall(timer_init); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 7925dc459..7b9fac0ca 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -16,12 +16,15 @@ #include "asm/tlbflush.h" #include "asm/a.out.h" #include "asm/current.h" +#include "asm/irq.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" #include "2_5compat.h" +#include "mem.h" +#include "mem_kern.h" int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out) @@ -51,12 +54,12 @@ int handle_page_fault(unsigned long address, unsigned long ip, if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - if(page == (unsigned long) current->thread_info + PAGE_SIZE) + if(page == (unsigned long) current_thread + PAGE_SIZE) panic("Kernel stack overflow"); pgd = pgd_offset(mm, page); pmd = pmd_offset(pgd, page); - survive: do { + survive: switch (handle_mm_fault(mm, vma, address, is_write)){ case VM_FAULT_MINOR: current->min_flt++; @@ -71,14 +74,20 @@ int handle_page_fault(unsigned long address, unsigned long ip, err = -ENOMEM; goto out_of_memory; default: - BUG(); + if (current->pid == 1) { + up_read(&mm->mmap_sem); + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + goto out; } pte = pte_offset_kernel(pmd, page); } while(!pte_present(*pte)); + err = 0; *pte = pte_mkyoung(*pte); if(pte_write(*pte)) *pte = pte_mkdirty(*pte); flush_tlb_page(vma, page); - err = 0; out: up_read(&mm->mmap_sem); return(err); @@ -98,6 +107,33 @@ out_of_memory: goto out; } +LIST_HEAD(physmem_remappers); + +void register_remapper(struct remapper *info) +{ + list_add(&info->list, &physmem_remappers); +} + +static int check_remapped_addr(unsigned long address, int is_write) +{ + struct remapper *remapper; + struct list_head *ele; + __u64 offset; + int fd; + + fd = phys_mapping(__pa(address), &offset); + if(fd == -1) + return(0); + + list_for_each(ele, &physmem_remappers){ + remapper = list_entry(ele, struct remapper, list); + if((*remapper->proc)(fd, address, is_write, offset)) + return(1); + } + + return(0); +} + unsigned long segv(unsigned long address, unsigned long ip, int is_write, int is_user, void *sc) { @@ -109,7 +145,9 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, flush_tlb_kernel_vm(); return(0); } - if(current->mm == NULL) + else if(check_remapped_addr(address & PAGE_MASK, is_write)) + return(0); + else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); @@ -120,9 +158,8 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); } - else if(current->thread.fault_addr != NULL){ + else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); - } else if(arch_fixup(ip, sc)) return(0); @@ -155,8 +192,6 @@ void bad_segv(unsigned long address, unsigned long ip, int is_write) { struct siginfo si; - printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx " - "(ip 0x%lx)\n", current->comm, current->pid, address, ip); si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; si.si_addr = (void *) address; @@ -180,6 +215,11 @@ void bus_handler(int sig, union uml_pt_regs *regs) else relay_signal(sig, regs); } +void winch(int sig, union uml_pt_regs *regs) +{ + do_IRQ(WINCH_IRQ, regs); +} + void trap_init(void) { } diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 63812e597..6744ca60d 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -5,11 +5,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -82,6 +80,8 @@ struct signal_info sig_info[] = { .is_irq = 0 }, [ SIGILL ] { .handler = relay_signal, .is_irq = 0 }, + [ SIGWINCH ] { .handler = winch, + .is_irq = 1 }, [ SIGBUS ] { .handler = bus_handler, .is_irq = 0 }, [ SIGSEGV] { .handler = segv_handler, @@ -102,12 +102,11 @@ void sig_handler(int sig, struct sigcontext sc) sig, &sc); } -extern int timer_irq_inited, missed_ticks[]; +extern int timer_irq_inited; void alarm_handler(int sig, struct sigcontext sc) { if(!timer_irq_inited) return; - missed_ticks[cpu()]++; if(sig == SIGALRM) switch_timers(0); @@ -123,7 +122,7 @@ void do_longjmp(void *b, int val) { jmp_buf *buf = b; - longjmp(*buf, val); + siglongjmp(*buf, val); } /* diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 439688b0d..33416e889 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) # Licensed under the GPL # @@ -7,7 +7,7 @@ extra-y := unmap_fin.o obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ - uaccess_user.o sys-$(SUBARCH)/ + uaccess.o uaccess_user.o sys-$(SUBARCH)/ obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ @@ -27,5 +27,3 @@ $(obj)/unmap.o: $(src)/unmap.c $(obj)/unmap_fin.o : $(src)/unmap.o ld -r -o $@ $< -lc -L/usr/lib - -clean : diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index afd94713d..d8e3bfe6b 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -17,6 +17,7 @@ #include "mem_user.h" #include "os.h" #include "tlb.h" +#include "mode.h" static int exec_tramp(void *sig_stack) { @@ -47,17 +48,17 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) forward_interrupts(new_pid); current->thread.request.op = OP_EXEC; current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); os_usr1_process(os_getpid()); enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); + task_protections((unsigned long) current_thread); force_flush_all(); unblock_signals(); } diff --git a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h index 83d94abb9..1a64e753e 100644 --- a/arch/um/kernel/tt/include/mode.h +++ b/arch/um/kernel/tt/include/mode.h @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; + extern int tracing_pid; extern int tracer(int (*init_proc)(void *), void *sp); diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h index 42425a225..7399836cb 100644 --- a/arch/um/kernel/tt/include/uaccess.h +++ b/arch/um/kernel/tt/include/uaccess.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -43,65 +43,19 @@ extern unsigned long get_fault_addr(void); extern int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher); - -static inline int copy_from_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - -static inline int copy_to_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, void **fault_addr, void **fault_catcher); - -static inline int strncpy_from_user_tt(char *dst, const char *src, int count) -{ - int n; - - if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - extern int __do_clear_user(void *mem, size_t len, void **fault_addr, void **fault_catcher); - -static inline int __clear_user_tt(void *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user_tt(void *mem, int len) -{ - return(access_ok_tt(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); -} - extern int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher); -static inline int strnlen_user_tt(const void *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} +extern int copy_from_user_tt(void *to, const void *from, int n); +extern int copy_to_user_tt(void *to, const void *from, int n); +extern int strncpy_from_user_tt(char *dst, const char *src, int count); +extern int __clear_user_tt(void *mem, int len); +extern int clear_user_tt(void *mem, int len); +extern int strnlen_user_tt(const void *str, int len); #endif diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c index e10db3f1f..308526745 100644 --- a/arch/um/kernel/tt/mem_user.c +++ b/arch/um/kernel/tt/mem_user.c @@ -25,14 +25,13 @@ void remap_data(void *segment_start, void *segment_end, int w) size = (unsigned long) segment_end - (unsigned long) segment_start; data = create_mem_file(size); - if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, - MAP_SHARED, data, 0)) == MAP_FAILED){ + addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); + if(addr == MAP_FAILED){ perror("mapping new data segment"); exit(1); } memcpy(addr, segment_start, size); - if(switcheroo(data, prot, addr, segment_start, - size) < 0){ + if(switcheroo(data, prot, addr, segment_start, size) < 0){ printf("switcheroo failed\n"); exit(1); } diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 7a2f330a3..2bdbdab87 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -62,7 +62,7 @@ void *switch_to_tt(void *prev, void *next, void *last) reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) - panic("write of switch_pipe failed, errno = %d", -err); + panic("write of switch_pipe failed, err = %d", -err); reading = 1; if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) @@ -104,48 +104,72 @@ void *switch_to_tt(void *prev, void *next, void *last) void release_thread_tt(struct task_struct *task) { - os_kill_process(task->thread.mode.tt.extern_pid, 0); + int pid = task->thread.mode.tt.extern_pid; + + if(os_getpid() != pid) + os_kill_process(pid, 0); } void exit_thread_tt(void) { - close(current->thread.mode.tt.switch_pipe[0]); - close(current->thread.mode.tt.switch_pipe[1]); + os_close_file(current->thread.mode.tt.switch_pipe[0]); + os_close_file(current->thread.mode.tt.switch_pipe[1]); } void schedule_tail(task_t *prev); static void new_thread_handler(int sig) { + unsigned long disable; int (*fn)(void *); void *arg; fn = current->thread.request.u.thread.proc; arg = current->thread.request.u.thread.arg; + UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); + disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | + (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); + SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); - block_signals(); + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + init_new_thread_signals(1); -#ifdef CONFIG_SMP - schedule_tail(current->thread.prev_sched); -#endif enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); - force_flush_all(); - current->thread.prev_sched = NULL; change_sig(SIGUSR1, 1); change_sig(SIGVTALRM, 1); change_sig(SIGPROF, 1); - unblock_signals(); + local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) do_exit(0); } static int new_thread_proc(void *stack) { + /* local_irq_disable is needed to block out signals until this thread is + * properly scheduled. Otherwise, the tracing thread will get mighty + * upset about any signals that arrive before that. + * This has the complication that it sets the saved signal mask in + * the sigcontext to block signals. This gets restored when this + * thread (or a descendant, since they get a copy of this sigcontext) + * returns to userspace. + * So, this is compensated for elsewhere. + * XXX There is still a small window until local_irq_disable() actually + * finishes where signals are possible - shouldn't be a problem in + * practice since SIGIO hasn't been forwarded here yet, and the + * local_irq_disable should finish before a SIGVTALRM has time to be + * delivered. + */ + + local_irq_disable(); init_new_thread_stack(stack, new_thread_handler); os_usr1_process(os_getpid()); return(0); @@ -156,7 +180,7 @@ static int new_thread_proc(void *stack) * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, * so it is blocked before it's called. They are re-enabled on sigreturn * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's signcontext, including the signal mask + * copy_thread copies the parent's sigcontext, including the signal mask * onto the signal frame. */ @@ -165,35 +189,32 @@ void finish_fork_handler(int sig) UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + enable_timer(); change_sig(SIGVTALRM, 1); local_irq_enable(); - force_flush_all(); if(current->mm != current->parent->mm) protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - - current->thread.prev_sched = NULL; + task_protections((unsigned long) current_thread); free_page(current->thread.temp_stack); + local_irq_disable(); change_sig(SIGUSR1, 0); set_user_mode(current); } -static int sigusr1 = SIGUSR1; - int fork_tramp(void *stack) { - int sig = sigusr1; - local_irq_disable(); + arch_init_thread(); init_new_thread_stack(stack, finish_fork_handler); - kill(os_getpid(), sig); + os_usr1_process(os_getpid()); return(0); } @@ -213,8 +234,8 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, } err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); - if(err){ - printk("copy_thread : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("copy_thread : pipe failed, err = %d\n", -err); return(err); } @@ -377,8 +398,8 @@ static void mprotect_kernel_mem(int w) pages = (1 << CONFIG_KERNEL_STACK_ORDER); - start = (unsigned long) current->thread_info + PAGE_SIZE; - end = (unsigned long) current + PAGE_SIZE * pages; + start = (unsigned long) current_thread + PAGE_SIZE; + end = (unsigned long) current_thread + PAGE_SIZE * pages; protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); protect_memory(end, high_physmem - end, 1, w, 1, 1); @@ -454,8 +475,9 @@ void set_init_pid(int pid) init_task.thread.mode.tt.extern_pid = pid; err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); - if(err) panic("Can't create switch pipe for init_task, errno = %d", - err); + if(err) + panic("Can't create switch pipe for init_task, errno = %d", + -err); } int singlestepping_tt(void *t) diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile index 97d4f0bc1..9f9daf5c1 100644 --- a/arch/um/kernel/tt/ptproxy/Makefile +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -9,5 +9,3 @@ USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean: diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c index 65504f8c6..de417c49d 100644 --- a/arch/um/kernel/tt/ptproxy/proxy.c +++ b/arch/um/kernel/tt/ptproxy/proxy.c @@ -15,7 +15,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml #include #include #include -#include #include #include #include @@ -293,10 +292,10 @@ void fake_child_exit(void) } char gdb_init_string[] = -"att 1 -b panic -b stop -handle SIGWINCH nostop noprint pass +"att 1 \n\ +b panic \n\ +b stop \n\ +handle SIGWINCH nostop noprint pass \n\ "; int start_debugger(char *prog, int startup, int stop, int *fd_out) @@ -304,7 +303,8 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out) int slave, child; slave = open_gdb_chan(); - if((child = fork()) == 0){ + child = fork(); + if(child == 0){ char *tempname = NULL; int fd; @@ -327,18 +327,19 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out) exit(1); #endif } - if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){ - printk("start_debugger : make_tempfile failed, errno = %d\n", - errno); + fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); + if(fd < 0){ + printk("start_debugger : make_tempfile failed," + "err = %d\n", -fd); exit(1); } - write(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); if(startup){ if(stop){ - write(fd, "b start_kernel\n", + os_write_file(fd, "b start_kernel\n", strlen("b start_kernel\n")); } - write(fd, "c\n", strlen("c\n")); + os_write_file(fd, "c\n", strlen("c\n")); } if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ printk("start_debugger : PTRACE_TRACEME failed, " diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c index 50a120d5e..c42855aed 100644 --- a/arch/um/kernel/tt/ptproxy/sysdep.c +++ b/arch/um/kernel/tt/ptproxy/sysdep.c @@ -9,6 +9,7 @@ terms and conditions. #include #include #include +#include #include #include #include diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c index aad7e4b62..86ef67653 100644 --- a/arch/um/kernel/tt/ptproxy/wait.c +++ b/arch/um/kernel/tt/ptproxy/wait.c @@ -56,21 +56,23 @@ int parent_wait_return(struct debugger *debugger, pid_t unused) int real_wait_return(struct debugger *debugger) { unsigned long ip; - int err, pid; + int pid; pid = debugger->pid; + ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); - ip = IP_RESTART_SYSCALL(ip); - err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip); + IP_RESTART_SYSCALL(ip); + if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) tracer_panic("real_wait_return : Failed to restart system " - "call, errno = %d\n"); + "call, errno = %d\n", errno); + if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || debugger_normal_return(debugger, -1)) tracer_panic("real_wait_return : gdb failed to wait, " - "errno = %d\n"); + "errno = %d\n", errno); return(0); } diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile index 2ad8271c6..3eeea057c 100644 --- a/arch/um/kernel/tt/sys-i386/Makefile +++ b/arch/um/kernel/tt/sys-i386/Makefile @@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 1b71f9ce5..555ffd0ee 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c index f7c845d99..1cabbd866 100644 --- a/arch/um/kernel/tt/syscall_user.c +++ b/arch/um/kernel/tt/syscall_user.c @@ -33,7 +33,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs) SC_START_SYSCALL(sc); index = record_syscall_start(syscall); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); /* regs->sc may have changed while the system call ran (there may @@ -46,7 +46,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs) (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index 32ac316de..d8ad334cf 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -10,6 +10,7 @@ #include "asm/page.h" #include "asm/pgtable.h" #include "asm/uaccess.h" +#include "asm/tlbflush.h" #include "user_util.h" #include "mem_user.h" #include "os.h" diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 6a6322a3e..3271e6a63 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -39,16 +39,17 @@ int is_tracer_winch(int pid, int fd, void *data) return(0); register_winch_irq(tracer_winch[0], fd, -1, data); - return(0); + return(1); } static void tracer_winch_handler(int sig) { + int n; char c = 1; - if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) - printk("tracer_winch_handler - write failed, errno = %d\n", - errno); + n = os_write_file(tracer_winch[1], &c, sizeof(c)); + if(n != sizeof(c)) + printk("tracer_winch_handler - write failed, err = %d\n", -n); } /* Called only by the tracing thread during initialization */ @@ -58,9 +59,8 @@ static void setup_tracer_winch(void) int err; err = os_pipe(tracer_winch, 1, 1); - if(err){ - printk("setup_tracer_winch : os_pipe failed, errno = %d\n", - -err); + if(err < 0){ + printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); return; } signal(SIGWINCH, tracer_winch_handler); @@ -130,8 +130,8 @@ static void sleeping_process_signal(int pid, int sig) case SIGTSTP: if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, errno = %d\n", pid, - sig); + "continue pid %d, signal = %d, " + "errno = %d\n", pid, sig, errno); break; /* This happens when the debugger (e.g. strace) is doing system call @@ -145,7 +145,7 @@ static void sleeping_process_signal(int pid, int sig) if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) tracer_panic("sleeping_process_signal : Failed to " "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, sig); + pid, errno); break; case SIGSTOP: break; @@ -218,7 +218,7 @@ int tracer(int (*init_proc)(void *), void *sp) err = attach(debugger_parent); if(err){ printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, err); + "errno = %d\n", debugger_parent, -err); debugger_parent = -1; } else { @@ -233,7 +233,8 @@ int tracer(int (*init_proc)(void *), void *sp) } set_cmdline("(tracing thread)"); while(1){ - if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + pid = waitpid(-1, &status, WUNTRACED); + if(pid <= 0){ if(errno != ECHILD){ printf("wait failed - errno = %d\n", errno); } @@ -401,7 +402,7 @@ static int __init uml_debug_setup(char *line, int *add) if(!strcmp(line, "go")) debug_stop = 0; else if(!strcmp(line, "parent")) debug_parent = 1; - else printk("Unknown debug option : '%s'\n", line); + else printf("Unknown debug option : '%s'\n", line); line = next; } diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 537ee9fba..f084f0c2b 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -8,15 +8,20 @@ #include #include "user_util.h" #include "uml_uaccess.h" +#include "task.h" +#include "kern_util.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, __do_copy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(n - (fault - (unsigned long) from)); } @@ -29,11 +34,14 @@ static void __do_strncpy(void *dst, const void *src, int count) int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, __do_strncpy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(strlen(dst)); else return(-1); } @@ -46,11 +54,14 @@ static void __do_clear(void *to, const void *from, int n) int __do_clear_user(void *mem, unsigned long len, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, __do_clear, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(len - (fault - (unsigned long) mem)); } @@ -58,19 +69,20 @@ int __do_clear_user(void *mem, unsigned long len, int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0) ret = strlen(str) + 1; - } - else { - ret = *faddrp - (unsigned long) str; - } + else ret = *faddrp - (unsigned long) str; + *fault_addr = NULL; *fault_catcher = NULL; + + TASK_REGS(get_current())->tt = save; return ret; } diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c index 36d3e6992..3f7aecdbe 100644 --- a/arch/um/kernel/tt/unmap.c +++ b/arch/um/kernel/tt/unmap.c @@ -3,10 +3,7 @@ * Licensed under the GPL */ -#include -#include #include -#include "user.h" int switcheroo(int fd, int prot, void *from, void *to, int size) { diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c index 61c4cc3af..be0dec54b 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/kernel/tty_log.c @@ -9,10 +9,10 @@ #include #include #include -#include #include #include "init.h" #include "user.h" +#include "kern_util.h" #include "os.h" #define TTY_LOG_DIR "./" @@ -24,29 +24,40 @@ static int tty_log_fd = -1; #define TTY_LOG_OPEN 1 #define TTY_LOG_CLOSE 2 #define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 struct tty_log_buf { int what; unsigned long tty; int len; + int direction; + unsigned long sec; + unsigned long usec; }; -int open_tty_log(void *tty) +int open_tty_log(void *tty, void *current_tty) { struct timeval tv; struct tty_log_buf data; char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; int fd; + gettimeofday(&tv, NULL); if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_OPEN, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, + .tty = (unsigned long) tty, + .len = sizeof(current_tty), + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + os_write_file(tty_log_fd, ¤t_tty, data.len); return(tty_log_fd); } - gettimeofday(&tv, NULL); sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec); @@ -62,30 +73,117 @@ int open_tty_log(void *tty) void close_tty_log(int fd, void *tty) { struct tty_log_buf data; + struct timeval tv; if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_CLOSE, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, + .tty = (unsigned long) tty, + .len = 0, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); return; } - close(fd); + os_close_file(fd); +} + +static int log_chunk(int fd, const char *buf, int len) +{ + int total = 0, try, missed, n; + char chunk[64]; + + while(len > 0){ + try = (len > sizeof(chunk)) ? sizeof(chunk) : len; + missed = copy_from_user_proc(chunk, (char *) buf, try); + try -= missed; + n = os_write_file(fd, chunk, try); + if(n != try) { + if(n < 0) + return(n); + return(-EIO); + } + if(missed != 0) + return(-EFAULT); + + len -= try; + total += try; + buf += try; + } + + return(total); } -int write_tty_log(int fd, char *buf, int len, void *tty) +int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) { + struct timeval tv; struct tty_log_buf data; + int direction; if(fd == tty_log_fd){ - data = ((struct tty_log_buf) { what : TTY_LOG_WRITE, - tty : (unsigned long) tty, - len : len }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + direction = is_read ? TTY_READ : TTY_WRITE; + data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, + .tty = (unsigned long) tty, + .len = len, + .direction = direction, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + } + + return(log_chunk(fd, buf, len)); +} + +void log_exec(char **argv, void *tty) +{ + struct timeval tv; + struct tty_log_buf data; + char **ptr,*arg; + int len; + + if(tty_log_fd == -1) return; + + gettimeofday(&tv, NULL); + + len = 0; + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + len += strlen_user_proc(arg); + } + + data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, + .tty = (unsigned long) tty, + .len = len, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); } - return(write(fd, buf, len)); } +extern void register_tty_logger(int (*opener)(void *, void *), + int (*writer)(int, const char *, int, + void *, int), + void (*closer)(int, void *)); + +static int register_logger(void) +{ + register_tty_logger(open_tty_log, write_tty_log, close_tty_log); + return(0); +} + +__uml_initcall(register_logger); + static int __init set_tty_log_dir(char *name, int *add) { tty_log_dir = name; @@ -104,7 +202,7 @@ static int __init set_tty_log_fd(char *name, int *add) tty_log_fd = strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - printk("set_tty_log_fd - strtoul failed on '%s'\n", name); + printf("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } return 0; diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c index eb9be24ce..fc079512a 100644 --- a/arch/um/kernel/uaccess_user.c +++ b/arch/um/kernel/uaccess_user.c @@ -20,7 +20,7 @@ unsigned long __do_user_copy(void *to, const void *from, int n, jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0){ (*op)(to, from, n); ret = 0; *faulted_out = 0; diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index e8f0cacc1..18a4a7607 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -38,13 +38,18 @@ #include "mode_kern.h" #include "mode.h" -#define DEFAULT_COMMAND_LINE "root=6200" +#define DEFAULT_COMMAND_LINE "root=98:0" struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; +/* Placeholder to make UML link until the vsyscall stuff is actually + * implemented + */ +void *__kernel_vsyscall; + unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, @@ -53,18 +58,22 @@ unsigned long thread_saved_pc(struct task_struct *task) static int show_cpuinfo(struct seq_file *m, void *v) { - int index; + int index = 0; - index = (struct cpuinfo_um *)v - cpu_data; #ifdef CONFIG_SMP + index = (struct cpuinfo_um *) v - cpu_data; if (!cpu_online(index)) return 0; #endif - seq_printf(m, "bogomips\t: %lu.%02lu\n", + seq_printf(m, "processor\t: %d\n", index); + seq_printf(m, "vendor_id\t: User Mode Linux\n"); + seq_printf(m, "model name\t: UML\n"); + seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); + seq_printf(m, "host\t\t: %s\n", host_info); + seq_printf(m, "bogomips\t: %lu.%02lu\n\n", loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); - seq_printf(m, "host\t\t: %s\n", host_info); return(0); } @@ -134,12 +143,12 @@ void set_cmdline(char *cmd) if(umid != NULL){ snprintf(argv1_begin, (argv1_end - argv1_begin) * sizeof(*ptr), - "(%s)", umid); + "(%s) ", umid); ptr = &argv1_begin[strlen(argv1_begin)]; } else ptr = argv1_begin; - snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd); + snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); memset(argv1_begin + strlen(argv1_begin), '\0', argv1_end - argv1_begin - strlen(argv1_begin)); #endif @@ -179,7 +188,7 @@ __uml_setup("root=", uml_root_setup, static int __init uml_ncpus_setup(char *line, int *add) { if (!sscanf(line, "%d", &ncpus)) { - printk("Couldn't parse [%s]\n", line); + printf("Couldn't parse [%s]\n", line); return -1; } @@ -210,7 +219,7 @@ static int __init mode_tt_setup(char *line, int *add) static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); + printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); return(0); } @@ -221,7 +230,7 @@ static int __init mode_tt_setup(char *line, int *add) static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); + printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); return(0); } @@ -291,7 +300,7 @@ static void __init uml_postsetup(void) /* Set during early boot */ unsigned long brk_start; -static struct vm_reserved kernel_vm_reserved; +unsigned long end_iomem; #define MIN_VMALLOC (32 * 1024 * 1024) @@ -299,7 +308,7 @@ int linux_main(int argc, char **argv) { unsigned long avail; unsigned long virtmem_size, max_physmem; - unsigned int i, add, err; + unsigned int i, add; for (i = 1; i < argc; i++){ if((i == 1) && (argv[i][0] == ' ')) continue; @@ -328,12 +337,16 @@ int linux_main(int argc, char **argv) argv1_end = &argv[1][strlen(argv[1])]; #endif - set_usable_vm(uml_physmem, get_kmem_end()); - highmem = 0; - max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC; - if(physmem_size > max_physmem){ - highmem = physmem_size - max_physmem; + iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + + /* Zones have to begin on a 1 << MAX_ORDER page boundary, + * so this makes sure that's true for highmem + */ + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + if(physmem_size + iomem_size > max_physmem){ + highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; @@ -343,11 +356,19 @@ int linux_main(int argc, char **argv) } high_physmem = uml_physmem + physmem_size; - high_memory = (void *) high_physmem; + end_iomem = high_physmem + iomem_size; + high_memory = (void *) end_iomem; start_vm = VMALLOC_START; - setup_physmem(uml_physmem, uml_reserved, physmem_size); + setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); + if(init_maps(physmem_size, iomem_size, highmem)){ + printf("Failed to allocate mem_map for %ld bytes of physical " + "memory and %ld bytes of highmem\n", physmem_size, + highmem); + exit(1); + } + virtmem_size = physmem_size; avail = get_kmem_end() - start_vm; if(physmem_size > avail) virtmem_size = avail; @@ -357,28 +378,26 @@ int linux_main(int argc, char **argv) printf("Kernel virtual memory size shrunk to %ld bytes\n", virtmem_size); - err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err){ - printf("Failed to reserve VM area for kernel VM\n"); - exit(1); - } - uml_postsetup(); init_task.thread.kernel_stack = (unsigned long) &init_thread_info + 2 * PAGE_SIZE; task_protections((unsigned long) &init_thread_info); + os_flush_stdout(); return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); } +extern int uml_exitcode; + static int panic_exit(struct notifier_block *self, unsigned long unused1, void *unused2) { #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('p', ¤t->thread.regs, NULL, NULL); + handle_sysrq('p', ¤t->thread.regs, NULL); #endif + uml_exitcode = 1; machine_halt(); return(0); } @@ -403,6 +422,11 @@ void __init check_bugs(void) arch_check_bugs(); check_ptrace(); check_sigio(); + check_devanon(); +} + +void apply_alternatives(void *start, void *end) +{ } /* diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 1da1a0d66..645fbfe51 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -33,18 +32,19 @@ static char *uml_dir = UML_DIR; static int umid_is_random = 1; static int umid_inited = 0; -static int make_umid(void); +static int make_umid(int (*printer)(const char *fmt, ...)); -static int __init set_umid(char *name, int is_random) +static int __init set_umid(char *name, int is_random, + int (*printer)(const char *fmt, ...)) { if(umid_inited){ - printk("Unique machine name can't be set twice\n"); + (*printer)("Unique machine name can't be set twice\n"); return(-1); } if(strlen(name) > UMID_LEN - 1) - printk("Unique machine name is being truncated to %s " - "characters\n", UMID_LEN); + (*printer)("Unique machine name is being truncated to %s " + "characters\n", UMID_LEN); strlcpy(umid, name, sizeof(umid)); umid_is_random = is_random; @@ -54,7 +54,7 @@ static int __init set_umid(char *name, int is_random) static int __init set_umid_arg(char *name, int *add) { - return(set_umid(name, 0)); + return(set_umid(name, 0, printf)); } __uml_setup("umid=", set_umid_arg, @@ -67,7 +67,7 @@ int __init umid_file_name(char *name, char *buf, int len) { int n; - if(!umid_inited && make_umid()) return(-1); + if(!umid_inited && make_umid(printk)) return(-1); n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; if(n > len){ @@ -85,22 +85,23 @@ static int __init create_pid_file(void) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")]; - int fd; + int fd, n; if(umid_file_name("pid", file, sizeof(file))) return 0; fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 0644); if(fd < 0){ - printk("Open of machine pid file \"%s\" failed - " - "errno = %d\n", file, -fd); + printf("Open of machine pid file \"%s\" failed - " + "err = %d\n", file, -fd); return 0; } sprintf(pid, "%d\n", os_getpid()); - if(write(fd, pid, strlen(pid)) != strlen(pid)) - printk("Write of pid file failed - errno = %d\n", errno); - close(fd); + n = os_write_file(fd, pid, strlen(pid)); + if(n != strlen(pid)) + printf("Write of pid file failed - err = %d\n", -n); + os_close_file(fd); return 0; } @@ -111,7 +112,8 @@ static int actually_do_remove(char *dir) int len; char file[256]; - if((directory = opendir(dir)) == NULL){ + directory = opendir(dir); + if(directory == NULL){ printk("actually_do_remove : couldn't open directory '%s', " "errno = %d\n", dir, errno); return(1); @@ -160,22 +162,24 @@ int not_dead_yet(char *dir) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; - int dead, fd, p; + int dead, fd, p, n; sprintf(file, "%s/pid", dir); dead = 0; - if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){ + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ if(fd != -ENOENT){ printk("not_dead_yet : couldn't open pid file '%s', " - "errno = %d\n", file, -fd); + "err = %d\n", file, -fd); return(1); } dead = 1; } if(fd > 0){ - if(read(fd, pid, sizeof(pid)) < 0){ + n = os_read_file(fd, pid, sizeof(pid)); + if(n < 0){ printk("not_dead_yet : couldn't read pid file '%s', " - "errno = %d\n", file, errno); + "err = %d\n", file, -n); return(1); } p = strtoul(pid, &end, 0); @@ -197,7 +201,7 @@ static int __init set_uml_dir(char *name, int *add) if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ uml_dir = malloc(strlen(name) + 1); if(uml_dir == NULL){ - printk("Failed to malloc uml_dir - error = %d\n", + printf("Failed to malloc uml_dir - error = %d\n", errno); uml_dir = name; return(0); @@ -217,7 +221,7 @@ static int __init make_uml_dir(void) char *home = getenv("HOME"); if(home == NULL){ - printk("make_uml_dir : no value in environment for " + printf("make_uml_dir : no value in environment for " "$HOME\n"); exit(1); } @@ -232,57 +236,59 @@ static int __init make_uml_dir(void) dir[len + 1] = '\0'; } - if((uml_dir = malloc(strlen(dir) + 1)) == NULL){ + uml_dir = malloc(strlen(dir) + 1); + if(uml_dir == NULL){ printf("make_uml_dir : malloc failed, errno = %d\n", errno); exit(1); } strcpy(uml_dir, dir); if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ - printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno); + printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno); return(-1); } return 0; } -static int __init make_umid(void) +static int __init make_umid(int (*printer)(const char *fmt, ...)) { int fd, err; char tmp[strlen(uml_dir) + UMID_LEN + 1]; strlcpy(tmp, uml_dir, sizeof(tmp)); - if(*umid == 0){ + if(!umid_inited){ strcat(tmp, "XXXXXX"); fd = mkstemp(tmp); if(fd < 0){ - printk("make_umid - mkstemp failed, errno = %d\n", - errno); + (*printer)("make_umid - mkstemp failed, errno = %d\n", + errno); return(1); } - close(fd); + os_close_file(fd); /* There's a nice tiny little race between this unlink and * the mkdir below. It'd be nice if there were a mkstemp * for directories. */ unlink(tmp); - set_umid(&tmp[strlen(uml_dir)], 1); + set_umid(&tmp[strlen(uml_dir)], 1, printer); } sprintf(tmp, "%s%s", uml_dir, umid); - if((err = mkdir(tmp, 0777)) < 0){ + err = mkdir(tmp, 0777); + if(err < 0){ if(errno == EEXIST){ if(not_dead_yet(tmp)){ - printk("umid '%s' is in use\n", umid); + (*printer)("umid '%s' is in use\n", umid); return(-1); } err = mkdir(tmp, 0777); } } if(err < 0){ - printk("Failed to create %s - errno = %d\n", umid, errno); + (*printer)("Failed to create %s - errno = %d\n", umid, errno); return(-1); } @@ -295,7 +301,13 @@ __uml_setup("uml_dir=", set_uml_dir, ); __uml_postsetup(make_uml_dir); -__uml_postsetup(make_umid); + +static int __init make_umid_setup(void) +{ + return(make_umid(printf)); +} + +__uml_postsetup(make_umid_setup); __uml_postsetup(create_pid_file); /* diff --git a/arch/um/kernel/user_syms.c b/arch/um/kernel/user_syms.c deleted file mode 100644 index 2d32ea3c5..000000000 --- a/arch/um/kernel/user_syms.c +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "mem_user.h" -#include "uml-config.h" - -/* Had to steal this from linux/module.h because that file can't be included - * since this includes various user-level headers. - */ - -struct module_symbol -{ - unsigned long value; - const char *name; -}; - -/* Indirect stringification. */ - -#define __MODULE_STRING_1(x) #x -#define __MODULE_STRING(x) __MODULE_STRING_1(x) - -#if !defined(__AUTOCONF_INCLUDED__) - -#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module -#define EXPORT_SYMBOL(var) error config_must_be_included_before_module -#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module - -#elif !defined(UML_CONFIG_MODULES) - -#define __EXPORT_SYMBOL(sym,str) -#define EXPORT_SYMBOL(var) -#define EXPORT_SYMBOL_NOVERS(var) - -#else - -#define __EXPORT_SYMBOL(sym, str) \ -const char __kstrtab_##sym[] \ -__attribute__((section(".kstrtab"))) = str; \ -const struct module_symbol __ksymtab_##sym \ -__attribute__((section("__ksymtab"))) = \ -{ (unsigned long)&sym, __kstrtab_##sym } - -#if defined(__MODVERSIONS__) || !defined(UML_CONFIG_MODVERSIONS) -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) -#else -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var))) -#endif - -#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) - -#endif - -EXPORT_SYMBOL(__errno_location); - -EXPORT_SYMBOL(access); -EXPORT_SYMBOL(open); -EXPORT_SYMBOL(open64); -EXPORT_SYMBOL(close); -EXPORT_SYMBOL(read); -EXPORT_SYMBOL(write); -EXPORT_SYMBOL(dup2); -EXPORT_SYMBOL(__xstat); -EXPORT_SYMBOL(__lxstat); -EXPORT_SYMBOL(__lxstat64); -EXPORT_SYMBOL(lseek); -EXPORT_SYMBOL(lseek64); -EXPORT_SYMBOL(chown); -EXPORT_SYMBOL(truncate); -EXPORT_SYMBOL(utime); -EXPORT_SYMBOL(chmod); -EXPORT_SYMBOL(rename); -EXPORT_SYMBOL(__xmknod); - -EXPORT_SYMBOL(symlink); -EXPORT_SYMBOL(link); -EXPORT_SYMBOL(unlink); -EXPORT_SYMBOL(readlink); - -EXPORT_SYMBOL(mkdir); -EXPORT_SYMBOL(rmdir); -EXPORT_SYMBOL(opendir); -EXPORT_SYMBOL(readdir); -EXPORT_SYMBOL(closedir); -EXPORT_SYMBOL(seekdir); -EXPORT_SYMBOL(telldir); - -EXPORT_SYMBOL(ioctl); - -extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes, - __off64_t __offset); -extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, - __off64_t __offset); -EXPORT_SYMBOL(pread64); -EXPORT_SYMBOL(pwrite64); - -EXPORT_SYMBOL(statfs); -EXPORT_SYMBOL(statfs64); - -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(getuid); - -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strstr); - -EXPORT_SYMBOL(find_iomem); diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c index a953a08c1..b15d79c3b 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/kernel/user_util.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -82,7 +81,8 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) int status, ret; while(1){ - if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) || + ret = waitpid(pid, &status, WUNTRACED); + if((ret < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ if(ret < 0){ if(errno == EINTR) continue; @@ -119,17 +119,6 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) } } -int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags) -{ - int pid; - - pid = clone(fn, sp, flags, arg); - if(pid < 0) return(-1); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - ptrace(PTRACE_CONT, pid, 0, 0); - return(pid); -} - int raw(int fd, int complain) { struct termios tt; diff --git a/arch/um/main.c b/arch/um/main.c index 386688425..ead5e2cf0 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -123,12 +124,14 @@ int main(int argc, char **argv, char **envp) set_stklim(); - if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ + new_argv = malloc((argc + 1) * sizeof(char *)); + if(new_argv == NULL){ perror("Mallocing argv"); exit(1); } for(i=0;i #include #include -#include #include #include #include @@ -42,13 +41,14 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, { struct addr_change change; void *output; + int n; change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); - if(write(fd, &change, sizeof(change)) != sizeof(change)) - printk("etap_change - request failed, errno = %d\n", - errno); + n = os_write_file(fd, &change, sizeof(change)); + if(n != sizeof(change)) + printk("etap_change - request failed, err = %d\n", -n); output = um_kmalloc(page_size()); if(output == NULL) printk("etap_change : Failed to allocate output buffer\n"); @@ -82,15 +82,15 @@ static void etap_pre_exec(void *arg) struct etap_pre_exec_data *data = arg; dup2(data->control_remote, 1); - close(data->data_me); - close(data->control_me); + os_close_file(data->data_me); + os_close_file(data->control_me); } static int etap_tramp(char *dev, char *gate, int control_me, int control_remote, int data_me, int data_remote) { struct etap_pre_exec_data pe_data; - int pid, status, err; + int pid, status, err, n; char version_buf[sizeof("nnnnn\0")]; char data_fd_buf[sizeof("nnnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; @@ -114,21 +114,21 @@ static int etap_tramp(char *dev, char *gate, int control_me, pe_data.data_me = data_me; pid = run_helper(etap_pre_exec, &pe_data, args, NULL); - if(pid < 0) err = errno; - close(data_remote); - close(control_remote); - if(read(control_me, &c, sizeof(c)) != sizeof(c)){ - printk("etap_tramp : read of status failed, errno = %d\n", - errno); - return(EINVAL); + if(pid < 0) err = pid; + os_close_file(data_remote); + os_close_file(control_remote); + n = os_read_file(control_me, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("etap_tramp : read of status failed, err = %d\n", -n); + return(-EINVAL); } if(c != 1){ printk("etap_tramp : uml_net failed\n"); - err = EINVAL; - if(waitpid(pid, &status, 0) < 0) err = errno; - else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){ + err = -EINVAL; + if(waitpid(pid, &status, 0) < 0) + err = -errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); - } } return(err); } @@ -143,14 +143,14 @@ static int etap_open(void *data) if(err) return(err); err = os_pipe(data_fds, 0, 0); - if(err){ - printk("data os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("data os_pipe failed - err = %d\n", -err); return(err); } err = os_pipe(control_fds, 1, 0); - if(err){ - printk("control os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("control os_pipe failed - err = %d\n", -err); return(err); } @@ -167,9 +167,9 @@ static int etap_open(void *data) kfree(output); } - if(err != 0){ - printk("etap_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("etap_tramp failed - err = %d\n", -err); + return(err); } pri->data_fd = data_fds[0]; @@ -183,11 +183,11 @@ static void etap_close(int fd, void *data) struct ethertap_data *pri = data; iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); - close(fd); + os_close_file(fd); os_shutdown_socket(pri->data_fd, 1, 1); - close(pri->data_fd); + os_close_file(pri->data_fd); pri->data_fd = -1; - close(pri->control_fd); + os_close_file(pri->control_fd); pri->control_fd = -1; } diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index c858f1160..054874d75 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -61,7 +60,7 @@ static void tuntap_pre_exec(void *arg) struct tuntap_pre_exec_data *data = arg; dup2(data->stdout, 1); - close(data->close_me); + os_close_file(data->close_me); } static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, @@ -86,7 +85,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, if(pid < 0) return(-pid); - close(remote); + os_close_file(remote); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -107,19 +106,19 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, if(n < 0){ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", errno); - return(errno); + return(-errno); } waitpid(pid, NULL, 0); cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ printk("tuntap_open_tramp : didn't receive a message\n"); - return(EINVAL); + return(-EINVAL); } if((cmsg->cmsg_level != SOL_SOCKET) || (cmsg->cmsg_type != SCM_RIGHTS)){ printk("tuntap_open_tramp : didn't receive a descriptor\n"); - return(EINVAL); + return(-EINVAL); } *fd_out = ((int *) CMSG_DATA(cmsg))[0]; return(0); @@ -133,27 +132,29 @@ static int tuntap_open(void *data) int err, fds[2], len, used; err = tap_open_common(pri->dev, pri->gate_addr); - if(err) return(err); + if(err < 0) + return(err); if(pri->fixed_config){ - if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){ - printk("Failed to open /dev/net/tun, errno = %d\n", - errno); - return(-errno); + pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); + if(pri->fd < 0){ + printk("Failed to open /dev/net/tun, err = %d\n", + -pri->fd); + return(pri->fd); } memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP; + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ - printk("TUNSETIFF failed, errno = %d", errno); - close(pri->fd); + printk("TUNSETIFF failed, errno = %d\n", errno); + os_close_file(pri->fd); return(-errno); } } else { err = os_pipe(fds, 0, 0); - if(err){ - printk("tuntap_open : os_pipe failed - errno = %d\n", + if(err < 0){ + printk("tuntap_open : os_pipe failed - err = %d\n", -err); return(err); } @@ -166,19 +167,19 @@ static int tuntap_open(void *data) fds[1], buffer, len, &used); output = buffer; - if(err == 0){ - pri->dev_name = uml_strdup(buffer); - output += IFNAMSIZ; - printk(output); - free_output_buffer(buffer); - } - else { - printk(output); + if(err < 0) { + printk("%s", output); free_output_buffer(buffer); - printk("tuntap_open_tramp failed - errno = %d\n", err); - return(-err); + printk("tuntap_open_tramp failed - err = %d\n", -err); + return(err); } - close(fds[0]); + + pri->dev_name = uml_strdup(buffer); + output += IFNAMSIZ; + printk("%s", output); + free_output_buffer(buffer); + + os_close_file(fds[0]); iter_addresses(pri->dev, open_addr, pri->dev_name); } @@ -191,7 +192,7 @@ static void tuntap_close(int fd, void *data) if(!pri->fixed_config) iter_addresses(pri->dev, close_addr, pri->dev_name); - close(fd); + os_close_file(fd); pri->fd = -1; } diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index e622db007..4083bf96c 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,33 +19,235 @@ #include "user.h" #include "kern_util.h" -int os_file_type(char *file) +static void copy_stat(struct uml_stat *dst, struct stat64 *src) +{ + *dst = ((struct uml_stat) { + .ust_dev = src->st_dev, /* device */ + .ust_ino = src->st_ino, /* inode */ + .ust_mode = src->st_mode, /* protection */ + .ust_nlink = src->st_nlink, /* number of hard links */ + .ust_uid = src->st_uid, /* user ID of owner */ + .ust_gid = src->st_gid, /* group ID of owner */ + .ust_size = src->st_size, /* total size, in bytes */ + .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */ + .ust_blocks = src->st_blocks, /* number of blocks allocated */ + .ust_atime = src->st_atime, /* time of last access */ + .ust_mtime = src->st_mtime, /* time of last modification */ + .ust_ctime = src->st_ctime, /* time of last change */ + }); +} + +int os_stat_fd(const int fd, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = fstat64(fd, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_stat_file(const char *file_name, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = stat64(file_name, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_access(const char* file, int mode) +{ + int amode, err; + + amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | + (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + + err = access(file, amode); + if(err < 0) + return(-errno); + + return(0); +} + +void os_print_error(int error, const char* str) +{ + errno = error < 0 ? -error : error; + + perror(str); +} + +/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ +int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + err = ioctl(fd, cmd, arg); + if(err < 0) + return(-errno); + + return(err); +} + +int os_window_size(int fd, int *rows, int *cols) +{ + struct winsize size; + + if(ioctl(fd, TIOCGWINSZ, &size) < 0) + return(-errno); + + *rows = size.ws_row; + *cols = size.ws_col; + + return(0); +} + +int os_new_tty_pgrp(int fd, int pid) +{ + if(ioctl(fd, TIOCSCTTY, 0) < 0){ + printk("TIOCSCTTY failed, errno = %d\n", errno); + return(-errno); + } + + if(tcsetpgrp(fd, pid) < 0){ + printk("tcsetpgrp failed, errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +/* FIXME: ensure namebuf in os_get_if_name is big enough */ +int os_get_ifname(int fd, char* namebuf) +{ + if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) + return(-errno); + + return(0); +} + +int os_set_slip(int fd) +{ + int disc, sencap; + + disc = N_SLIP; + if(ioctl(fd, TIOCSETD, &disc) < 0){ + printk("Failed to set slip line discipline - " + "errno = %d\n", errno); + return(-errno); + } + + sencap = 0; + if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ + printk("Failed to set slip encapsulation - " + "errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +int os_set_owner(int fd, int pid) +{ + if(fcntl(fd, F_SETOWN, pid) < 0){ + int save_errno = errno; + + if(fcntl(fd, F_GETOWN, 0) != pid) + return(-save_errno); + } + + return(0); +} + +/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ +int os_sigio_async(int master, int slave) +{ + int flags; + + flags = fcntl(master, F_GETFL); + if(flags < 0) { + printk("fcntl F_GETFL failed, errno = %d\n", errno); + return(-errno); + } + + if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)){ + printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno); + return(-errno); + } + + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){ + printk("fcntl F_SETFL failed, errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +int os_mode_fd(int fd, int mode) { - struct stat64 buf; + int err; + + do { + err = fchmod(fd, mode); + } while((err < 0) && (errno==EINTR)) ; - if(stat64(file, &buf) == -1) + if(err < 0) return(-errno); - if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.st_mode)) return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.st_mode)) return(OS_TYPE_SOCK); + return(0); +} + +int os_file_type(char *file) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0) + return(err); + + if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); + else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); + else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); + else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); + else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); + else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); else return(OS_TYPE_FILE); } int os_file_mode(char *file, struct openflags *mode_out) { + int err; + *mode_out = OPENFLAGS(); - if(!access(file, W_OK)) *mode_out = of_write(*mode_out); - else if(errno != EACCES) - return(-errno); + err = os_access(file, OS_ACC_W_OK); + if((err < 0) && (err != -EACCES)) + return(err); - if(!access(file, R_OK)) *mode_out = of_read(*mode_out); - else if(errno != EACCES) - return(-errno); + *mode_out = of_write(*mode_out); + + err = os_access(file, OS_ACC_R_OK); + if((err < 0) && (err != -EACCES)) + return(err); + + *mode_out = of_read(*mode_out); return(0); } @@ -63,16 +267,14 @@ int os_open_file(char *file, struct openflags flags, int mode) if(flags.e) f |= O_EXCL; fd = open64(file, f, mode); - if(fd < 0) return(-errno); - - if(flags.cl){ - if(fcntl(fd, F_SETFD, 1)){ - close(fd); - return(-errno); - } + if(fd < 0) + return(-errno); + + if(flags.cl && fcntl(fd, F_SETFD, 1)){ + os_close_file(fd); + return(-errno); } - return(fd); return(fd); } @@ -90,7 +292,7 @@ int os_connect_socket(char *name) err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); if(err) - return(err); + return(-errno); return(fd); } @@ -109,88 +311,162 @@ int os_seek_file(int fd, __u64 offset) return(0); } -int os_read_file(int fd, void *buf, int len) +static int fault_buffer(void *start, int len, + int (*copy_proc)(void *addr, void *buf, int len)) { - int n; + int page = getpagesize(), i; + char c; - /* Force buf into memory if it's not already. */ + for(i = 0; i < len; i += page){ + if((*copy_proc)(start + i, &c, sizeof(c))) + return(-EFAULT); + } + if((len % page) != 0){ + if((*copy_proc)(start + len - 1, &c, sizeof(c))) + return(-EFAULT); + } + return(0); +} - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, &c, sizeof(c))) - return(-EFAULT); -#endif +static int file_io(int fd, void *buf, int len, + int (*io_proc)(int fd, void *buf, int len), + int (*copy_user_proc)(void *addr, void *buf, int len)) +{ + int n, err; + + do { + n = (*io_proc)(fd, buf, len); + if((n < 0) && (errno == EFAULT)){ + err = fault_buffer(buf, len, copy_user_proc); + if(err) + return(err); + n = (*io_proc)(fd, buf, len); + } + } while((n < 0) && (errno == EINTR)); - n = read(fd, buf, len); if(n < 0) return(-errno); return(n); } -int os_write_file(int fd, void *buf, int count) +int os_read_file(int fd, void *buf, int len) { - int n; - - /* Force buf into memory if it's not already. */ - - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, buf, buf[0])) - return(-EFAULT); -#endif + return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, + copy_from_user_proc)); +} - n = write(fd, buf, count); - if(n < 0) - return(-errno); - return(n); +int os_write_file(int fd, const void *buf, int len) +{ + return(file_io(fd, (void *) buf, len, + (int (*)(int, void *, int)) write, copy_to_user_proc)); } int os_file_size(char *file, long long *size_out) { - struct stat64 buf; + struct uml_stat buf; + int err; - if(stat64(file, &buf) == -1){ - printk("Couldn't stat \"%s\" : errno = %d\n", file, errno); - return(-errno); + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); } - if(S_ISBLK(buf.st_mode)){ + + if(S_ISBLK(buf.ust_mode)){ int fd, blocks; - if((fd = open64(file, O_RDONLY)) < 0){ - printk("Couldn't open \"%s\", errno = %d\n", file, - errno); - return(-errno); + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open \"%s\", errno = %d\n", file, -fd); + return(fd); } if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ printk("Couldn't get the block size of \"%s\", " "errno = %d\n", file, errno); - close(fd); - return(-errno); + err = -errno; + os_close_file(fd); + return(err); } *size_out = ((long long) blocks) * 512; - close(fd); + os_close_file(fd); return(0); } - *size_out = buf.st_size; + *size_out = buf.ust_size; + return(0); +} + +int os_file_modtime(char *file, unsigned long *modtime) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); + } + + *modtime = buf.ust_mtime; return(0); } +int os_get_exec_close(int fd, int* close_on_exec) +{ + int ret; + + do { + ret = fcntl(fd, F_GETFD); + } while((ret < 0) && (errno == EINTR)) ; + + if(ret < 0) + return(-errno); + + *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; + return(ret); +} + +int os_set_exec_close(int fd, int close_on_exec) +{ + int flag, err; + + if(close_on_exec) flag = FD_CLOEXEC; + else flag = 0; + + do { + err = fcntl(fd, F_SETFD, flag); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + return(err); +} + int os_pipe(int *fds, int stream, int close_on_exec) { int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err) + if(err < 0) return(-errno); if(!close_on_exec) return(0); - if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0)) - printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", - errno); + err = os_set_exec_close(fds[0], 1); + if(err < 0) + goto error; + + err = os_set_exec_close(fds[1], 1); + if(err < 0) + goto error; return(0); + + error: + printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); + os_close_file(fds[1]); + os_close_file(fds[0]); + return(err); } int os_set_fd_async(int fd, int owner) @@ -270,7 +546,7 @@ int os_shutdown_socket(int fd, int r, int w) return(-EINVAL); } err = shutdown(fd, what); - if(err) + if(err < 0) return(-errno); return(0); } @@ -315,7 +591,7 @@ int os_rcv_fd(int fd, int *helper_pid_out) return(new); } -int create_unix_socket(char *file, int len) +int os_create_unix_socket(char *file, int len, int close_on_exec) { struct sockaddr_un addr; int sock, err; @@ -327,6 +603,13 @@ int create_unix_socket(char *file, int len) return(-errno); } + if(close_on_exec) { + err = os_set_exec_close(sock, 1); + if(err < 0) + printk("create_unix_socket : close_on_exec failed, " + "err = %d", -err); + } + addr.sun_family = AF_UNIX; /* XXX Be more careful about overflow */ @@ -334,14 +617,45 @@ int create_unix_socket(char *file, int len) err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0){ - printk("create_listening_socket - bind failed, errno = %d\n", - errno); + printk("create_listening_socket at '%s' - bind failed, " + "errno = %d\n", file, errno); return(-errno); } return(sock); } +void os_flush_stdout(void) +{ + fflush(stdout); +} + +int os_lock_file(int fd, int excl) +{ + int type = excl ? F_WRLCK : F_RDLCK; + struct flock lock = ((struct flock) { .l_type = type, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0 } ); + int err, save; + + err = fcntl(fd, F_SETLK, &lock); + if(!err) + goto out; + + save = -errno; + err = fcntl(fd, F_GETLK, &lock); + if(err){ + err = -errno; + goto out; + } + + printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); + err = save; + out: + return(err); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index a97778f31..f1b178cb3 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,32 +7,37 @@ #include #include #include +#include #include #include #include "os.h" #include "user.h" +#define ARBITRARY_ADDR -1 +#define FAILURE_PID -1 + unsigned long os_process_pc(int pid) { char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; unsigned long pc; - int fd; + int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("os_process_pc - couldn't open '%s', errno = %d\n", - proc_stat, errno); - return(-1); + printk("os_process_pc - couldn't open '%s', err = %d\n", + proc_stat, -fd); + return(ARBITRARY_ADDR); } - if(read(fd, buf, sizeof(buf)) < 0){ - printk("os_process_pc - couldn't read '%s', errno = %d\n", - proc_stat, errno); - close(fd); - return(-1); + err = os_read_file(fd, buf, sizeof(buf)); + if(err < 0){ + printk("os_process_pc - couldn't read '%s', err = %d\n", + proc_stat, -err); + os_close_file(fd); + return(ARBITRARY_ADDR); } - close(fd); - pc = -1; + os_close_file(fd); + pc = ARBITRARY_ADDR; if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %ld", &pc) != 1){ @@ -52,22 +57,23 @@ int os_process_parent(int pid) snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = os_open_file(stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("Couldn't open '%s', errno = %d\n", stat, -fd); - return(-1); + printk("Couldn't open '%s', err = %d\n", stat, -fd); + return(FAILURE_PID); } - n = read(fd, data, sizeof(data)); - close(fd); + n = os_read_file(fd, data, sizeof(data)); + os_close_file(fd); if(n < 0){ - printk("Couldn't read '%s', errno = %d\n", stat); - return(-1); + printk("Couldn't read '%s', err = %d\n", stat, -n); + return(FAILURE_PID); } - parent = -1; + parent = FAILURE_PID; /* XXX This will break if there is a space in the command */ n = sscanf(data, "%*d %*s %*c %d", &parent); - if(n != 1) printk("Failed to scan '%s'\n", data); + if(n != 1) + printk("Failed to scan '%s'\n", data); return(parent); } @@ -87,7 +93,8 @@ void os_kill_process(int pid, int reap_child) void os_usr1_process(int pid) { - kill(pid, SIGUSR1); + syscall(__NR_tkill, pid, SIGUSR1); + /* kill(pid, SIGUSR1); */ } int os_getpid(void) @@ -95,7 +102,7 @@ int os_getpid(void) return(getpid()); } -int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, +int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x) { void *loc; @@ -104,8 +111,8 @@ int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, - fd, off); + loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, + fd, off); if(loc == MAP_FAILED) return(-errno); return(0); @@ -126,7 +133,8 @@ int os_unmap_memory(void *addr, int len) int err; err = munmap(addr, len); - if(err < 0) return(-errno); + if(err < 0) + return(-errno); return(0); } diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 2866ddbc9..4cfdd18ea 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -28,10 +28,10 @@ int get_pty(void) struct grantpt_info info; int fd; - if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n", - errno); - return(-1); + fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); + if(fd < 0){ + printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); + return(fd); } info.fd = fd; @@ -39,7 +39,7 @@ int get_pty(void) if(info.res < 0){ printk("get_pty : Couldn't grant pty - errno = %d\n", - info.err); + -info.err); return(-1); } if(unlockpt(fd) < 0){ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 7525859c5..c9c539fe4 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,7 +1,8 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \ - ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o +obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \ + semaphore.o sigcontext.o syscalls.o sysrq.o time.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_MODULES) += module.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) @@ -9,6 +10,8 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) SYMLINKS = semaphore.c highmem.c module.c SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) +clean-files := $(SYMLINKS) + semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel @@ -24,19 +27,4 @@ $(USER_OBJS) : %.o: %.c $(SYMLINKS): $(call make_link,$@) -clean: - $(MAKE) -C util clean - -fastdep: - -dep: - -archmrproper: - rm -f $(SYMLINKS) - -archclean: - -archdep: - -modules: - +subdir- := util diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index 3905bab88..b453e2f76 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -4,20 +4,21 @@ */ #include -#include #include #include #include +#include #include "kern_util.h" #include "user.h" #include "sysdep/ptrace.h" #include "task.h" +#include "os.h" #define MAXTOKEN 64 /* Set during early boot */ -int cpu_has_cmov = 1; -int cpu_has_xmm = 0; +int host_has_cmov = 1; +int host_has_xmm = 0; static char token(int fd, char *buf, int len, char stop) { @@ -27,13 +28,15 @@ static char token(int fd, char *buf, int len, char stop) ptr = buf; end = &buf[len]; do { - n = read(fd, ptr, sizeof(*ptr)); + n = os_read_file(fd, ptr, sizeof(*ptr)); c = *ptr++; - if(n == 0) return(0); - else if(n != sizeof(*ptr)){ - printk("Reading /proc/cpuinfo failed, " - "errno = %d\n", errno); - return(-errno); + if(n != sizeof(*ptr)){ + if(n == 0) return(0); + printk("Reading /proc/cpuinfo failed, err = %d\n", -n); + if(n < 0) + return(n); + else + return(-EIO); } } while((c != '\n') && (c != stop) && (ptr < end)); @@ -45,45 +48,79 @@ static char token(int fd, char *buf, int len, char stop) return(c); } -static int check_cpu_feature(char *feature, int *have_it) +static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) { - char buf[MAXTOKEN], c; - int fd, len = sizeof(buf)/sizeof(buf[0]), n; - - printk("Checking for host processor %s support...", feature); - fd = open("/proc/cpuinfo", O_RDONLY); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno); - return(0); - } + int n; + char c; - *have_it = 0; - buf[len - 1] = '\0'; + scratch[len - 1] = '\0'; while(1){ - c = token(fd, buf, len - 1, ':'); - if(c <= 0) goto out; + c = token(fd, scratch, len - 1, ':'); + if(c <= 0) + return(0); else if(c != ':'){ printk("Failed to find ':' in /proc/cpuinfo\n"); - goto out; + return(0); } - if(!strncmp(buf, "flags", strlen("flags"))) break; + if(!strncmp(scratch, key, strlen(key))) + return(1); do { - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ printk("Failed to find newline in " - "/proc/cpuinfo, n = %d, errno = %d\n", - n, errno); - goto out; + "/proc/cpuinfo, err = %d\n", -n); + return(0); } } while(c != '\n'); } + return(0); +} + +int cpu_feature(char *what, char *buf, int len) +{ + int fd, ret = 0; + + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + if(!find_cpuinfo_line(fd, what, buf, len)){ + printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); + goto out_close; + } + + token(fd, buf, len, '\n'); + ret = 1; + + out_close: + os_close_file(fd); + return(ret); +} + +static int check_cpu_flag(char *feature, int *have_it) +{ + char buf[MAXTOKEN], c; + int fd, len = sizeof(buf)/sizeof(buf[0]); + + printk("Checking for host processor %s support...", feature); + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + *have_it = 0; + if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0]))) + goto out; c = token(fd, buf, len - 1, ' '); if(c < 0) goto out; else if(c != ' '){ - printk("Failed to find ':' in /proc/cpuinfo\n"); + printk("Failed to find ' ' in /proc/cpuinfo\n"); goto out; } @@ -100,21 +137,48 @@ static int check_cpu_feature(char *feature, int *have_it) out: if(*have_it == 0) printk("No\n"); else if(*have_it == 1) printk("Yes\n"); - close(fd); + os_close_file(fd); return(1); } +#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems + * for some people. + */ +static void disable_lcall(void) +{ + struct modify_ldt_ldt_s ldt; + int err; + + bzero(&ldt, sizeof(ldt)); + ldt.entry_number = 7; + ldt.base_addr = 0; + ldt.limit = 0; + err = modify_ldt(1, &ldt, sizeof(ldt)); + if(err) + printk("Failed to disable lcall7 - errno = %d\n", errno); +} +#endif + +void arch_init_thread(void) +{ +#if 0 + disable_lcall(); +#endif +} + void arch_check_bugs(void) { int have_it; - if(access("/proc/cpuinfo", R_OK)){ + if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){ printk("/proc/cpuinfo not available - skipping CPU capability " "checks\n"); return; } - if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it; - if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it; + if(check_cpu_flag("cmov", &have_it)) + host_has_cmov = have_it; + if(check_cpu_flag("xmm", &have_it)) + host_has_xmm = have_it; } int arch_handle_signal(int sig, union uml_pt_regs *regs) @@ -130,18 +194,18 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs) if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) return(0); - if(cpu_has_cmov == 0) + if(host_has_cmov == 0) panic("SIGILL caused by cmov, which this processor doesn't " "implement, boot a filesystem compiled for older " "processors"); - else if(cpu_has_cmov == 1) + else if(host_has_cmov == 1) panic("SIGILL caused by cmov, which this processor claims to " "implement"); - else if(cpu_has_cmov == -1) + else if(host_has_cmov == -1) panic("SIGILL caused by cmov, couldn't tell if this processor " "implements it, boot a filesystem compiled for older " "processors"); - else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov); + else panic("Bad value for host_has_cmov (%d)", host_has_cmov); return(0); } diff --git a/arch/um/sys-i386/extable.c b/arch/um/sys-i386/extable.c deleted file mode 100644 index 946e7ad6f..000000000 --- a/arch/um/sys-i386/extable.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * linux/arch/i386/mm/extable.c - */ - -#include -#include -#include -#include - -/* Simple binary search */ -const struct exception_table_entry * -search_extable(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return NULL; -} diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c index 6a0ec334c..a8ddb3856 100644 --- a/arch/um/sys-i386/fault.c +++ b/arch/um/sys-i386/fault.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,16 +7,24 @@ #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" -extern unsigned long search_exception_table(unsigned long addr); +/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ +struct exception_table_entry +{ + unsigned long insn; + unsigned long fixup; +}; +const struct exception_table_entry *search_exception_tables(unsigned long add); + +/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ int arch_fixup(unsigned long address, void *sc_ptr) { struct sigcontext *sc = sc_ptr; - unsigned long fixup; + const struct exception_table_entry *fixup; fixup = search_exception_tables(address); if(fixup != 0){ - sc->eip = fixup; + sc->eip = fixup->fixup; return(1); } return(0); diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 70da62313..6b9ba0845 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -39,10 +39,10 @@ static void write_debugregs(int pid, unsigned long *regs) nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ if((i == 4) || (i == 5)) continue; - if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], + if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i], regs[i]) < 0) - printk("write_debugregs - ptrace failed, " - "errno = %d\n", errno); + printk("write_debugregs - ptrace failed on " + "register %d, errno = %d\n", errno); } } @@ -54,7 +54,7 @@ static void read_debugregs(int pid, unsigned long *regs) dummy = NULL; nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ - regs[i] = ptrace(PTRACE_PEEKUSR, pid, + regs[i] = ptrace(PTRACE_PEEKUSER, pid, &dummy->u_debugreg[i], 0); } } diff --git a/arch/um/sys-i386/time.c b/arch/um/sys-i386/time.c new file mode 100644 index 000000000..a6a5ba755 --- /dev/null +++ b/arch/um/sys-i386/time.c @@ -0,0 +1,24 @@ +/* + * sys-i386/time.c + * Created 25.9.2002 Sapan Bhatia + * + */ + +unsigned long long time_stamp(void) +{ + unsigned long low, high; + + asm("rdtsc" : "=a" (low), "=d" (high)); + return((((unsigned long long) high) << 32) + low); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile index a3eca5f22..d10c36a01 100644 --- a/arch/um/sys-i386/util/Makefile +++ b/arch/um/sys-i386/util/Makefile @@ -1,15 +1,10 @@ +host-progs := mk_sc mk_thread +always := $(host-progs) -host-progs := mk_sc -always := $(host-progs) mk_thread -targets := mk_thread_kern.o mk_thread_user.o +mk_thread-objs := mk_thread_kern.o mk_thread_user.o -mk_sc-objs := mk_sc.o - -$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o - $(CC) $(CFLAGS) -o $@ $^ - -$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c - $(CC) $(USER_CFLAGS) -c -o $@ $< +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) clean : $(RM) -f $(build-targets) diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c index 224b6ad75..85cbd3039 100644 --- a/arch/um/sys-i386/util/mk_sc.c +++ b/arch/um/sys-i386/util/mk_sc.c @@ -38,6 +38,7 @@ int main(int argc, char **argv) SC_OFFSET("SC_ERR", err); SC_OFFSET("SC_CR2", cr2); SC_OFFSET("SC_FPSTATE", fpstate); + SC_OFFSET("SC_SIGMASK", oldmask); SC_FP_OFFSET("SC_FP_CW", cw); SC_FP_OFFSET("SC_FP_SW", sw); SC_FP_OFFSET("SC_FP_TAG", tag); diff --git a/arch/um/sys-ia64/Makefile b/arch/um/sys-ia64/Makefile index 4dd735320..d02f4c265 100644 --- a/arch/um/sys-ia64/Makefile +++ b/arch/um/sys-ia64/Makefile @@ -7,18 +7,5 @@ all: $(OBJ) $(OBJ): $(OBJS) rm -f $@ $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ -clean: - rm -f $(OBJS) -fastdep: - -archmrproper: - -archclean: - rm -f link.ld - @$(MAKEBOOT) clean - -archdep: - @$(MAKEBOOT) dep - -modules: +clean-files := $(OBJS) link.ld diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile index 3767c2583..af200268f 100644 --- a/arch/um/sys-ppc/Makefile +++ b/arch/um/sys-ppc/Makefile @@ -66,13 +66,4 @@ misc.o: misc.S ppc_defs.h $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean: - rm -f $(OBJS) - rm -f ppc_defs.h - rm -f checksum.S semaphore.c mk_defs.c - -fastdep: - -dep: - -modules: +clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S index d182fb5de..3c2fdec13 100644 --- a/arch/um/uml.lds.S +++ b/arch/um/uml.lds.S @@ -9,7 +9,6 @@ SECTIONS { . = START + SIZEOF_HEADERS; - . = ALIGN(4096); __binary_start = .; #ifdef MODE_TT .thread_private : { @@ -26,11 +25,16 @@ SECTIONS . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); .text : { *(.text) + SCHED_TEXT /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) @@ -38,7 +42,7 @@ SECTIONS #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(init.data) } .data : { . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile index defd03861..f480f42bd 100644 --- a/arch/um/util/Makefile +++ b/arch/um/util/Makefile @@ -1,23 +1,8 @@ -always := mk_task mk_constants -targets := mk_task_user.o mk_task_kern.o \ - mk_constants_user.o mk_constants_kern.o +host-progs := mk_task mk_constants +always := $(host-progs) -$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o - $(CC) -o $@ $^ +mk_task-objs := mk_task_user.o mk_task_kern.o +mk_constants-objs := mk_constants_user.o mk_constants_kern.o -$(obj)/mk_task_user.o: $(src)/mk_task_user.c - $(CC) -o $@ -c $< - -$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o - $(CC) -o $@ $^ - -$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c - $(CC) -c $< -o $@ - -$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - $(RM) $(build-targets) - -archmrproper: +HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS) diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c index 7e7493431..cdcb1232a 100644 --- a/arch/um/util/mk_constants_kern.c +++ b/arch/um/util/mk_constants_kern.c @@ -1,5 +1,6 @@ #include "linux/kernel.h" #include "linux/stringify.h" +#include "linux/time.h" #include "asm/page.h" extern void print_head(void); @@ -11,6 +12,7 @@ int main(int argc, char **argv) { print_head(); print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); + print_constant_str("UM_KERN_EMERG", KERN_EMERG); print_constant_str("UM_KERN_ALERT", KERN_ALERT); print_constant_str("UM_KERN_CRIT", KERN_CRIT); @@ -19,6 +21,8 @@ int main(int argc, char **argv) print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); print_constant_str("UM_KERN_INFO", KERN_INFO); print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); + + print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC); print_tail(); return(0); } diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig index 8665652e2..994e4f859 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -334,6 +334,8 @@ config NO_KERNEL_MSG endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c index fc06058f2..7d2554774 100644 --- a/arch/v850/kernel/ptrace.c +++ b/arch/v850/kernel/ptrace.c @@ -138,6 +138,8 @@ int sys_ptrace(long request, long pid, long addr, long data) read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; rval = -EPERM; if (pid == 1) /* you may not mess with init */ diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 2122afc52..1c07776ac 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -499,6 +499,8 @@ config IOMMU_LEAK endmenu +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index e569a1435..df768a0e9 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -34,7 +34,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y -CONFIG_KALLSYMS_ALL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -235,7 +234,6 @@ CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -260,6 +258,7 @@ CONFIG_BLK_DEV_SD=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_REPORT_LUNS is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set @@ -790,6 +789,7 @@ CONFIG_USB_HIDINPUT=y # Firmware Drivers # # CONFIG_EDD is not set +# CONFIG_SMBIOS is not set # # File systems diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c index f9a2638c8..c6d0b02a1 100644 --- a/arch/x86_64/ia32/fpu32.c +++ b/arch/x86_64/ia32/fpu32.c @@ -72,15 +72,15 @@ static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, - struct _fpstate_ia32 __user *buf) + struct _fpstate_ia32 *buf) { struct _fpxreg *to; - struct _fpreg __user *from; + struct _fpreg *from; int i; u32 v; int err = 0; -#define G(num,val) err |= __get_user(val, num + (u32 __user *)buf) +#define G(num,val) err |= __get_user(val, num + (u32 *)buf) G(0, fxsave->cwd); G(1, fxsave->swd); G(2, fxsave->twd); @@ -104,12 +104,12 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, } -static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf, +static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf, struct i387_fxsave_struct *fxsave, struct pt_regs *regs, struct task_struct *tsk) { - struct _fpreg __user *to; + struct _fpreg *to; struct _fpxreg *from; int i; u16 cs,ds; @@ -125,7 +125,7 @@ static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf, cs = regs->cs; } -#define P(num,val) err |= __put_user(val, num + (u32 __user *)buf) +#define P(num,val) err |= __put_user(val, num + (u32 *)buf) P(0, (u32)fxsave->cwd | 0xffff0000); P(1, (u32)fxsave->swd | 0xffff0000); P(2, twd_fxsr_to_i387(fxsave)); @@ -147,7 +147,7 @@ static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf, return 0; } -int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, int fsave) +int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave) { clear_fpu(tsk); if (!fsave) { @@ -162,7 +162,7 @@ int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, } int save_i387_ia32(struct task_struct *tsk, - struct _fpstate_ia32 __user *buf, + struct _fpstate_ia32 *buf, struct pt_regs *regs, int fsave) { diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c index 040adf699..b7b698c68 100644 --- a/arch/x86_64/ia32/ia32_aout.c +++ b/arch/x86_64/ia32/ia32_aout.c @@ -308,7 +308,8 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = TASK_UNMAPPED_BASE; - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 8e6b845f7..fc1a9b01a 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -327,7 +327,7 @@ static void elf32_init(struct pt_regs *regs) int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) { - unsigned long stack_base; + unsigned long stack_base, grow; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i; @@ -344,7 +344,10 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + grow = (IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p)) + >> PAGE_SHIFT; + if (security_vm_enough_memory(grow) || + !vx_vmpages_avail(mm, grow)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -365,7 +368,9 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + // mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + vx_vmpages_sub(mm, mm->total_vm - + ((mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -382,7 +387,7 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) } static unsigned long -elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused) { unsigned long map_addr; struct task_struct *me = current; diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c index 8c6964245..d39795746 100644 --- a/arch/x86_64/ia32/ia32_ioctl.c +++ b/arch/x86_64/ia32/ia32_ioctl.c @@ -21,7 +21,7 @@ #ifndef TIOCGDEV #define TIOCGDEV _IOR('T',0x32, unsigned int) #endif -static int tiocgdev(unsigned fd, unsigned cmd, unsigned int __user *ptr) +static int tiocgdev(unsigned fd, unsigned cmd, unsigned int *ptr) { struct file *file = fget(fd); @@ -54,7 +54,7 @@ static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); set_fs(oldfs); if (!ret) - ret = put_user(val, (unsigned int __user *) arg); + ret = put_user(val, (unsigned int*) arg); return ret; case RTC_IRQP_SET32: @@ -66,7 +66,7 @@ static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); set_fs(oldfs); if (!ret) - ret = put_user(val, (unsigned int __user *) arg); + ret = put_user(val, (unsigned int*) arg); return ret; case RTC_EPOCH_SET32: @@ -113,7 +113,7 @@ static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg) struct mtrr_gentry g; struct mtrr_sentry s; int get = 0, err = 0; - struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)arg; + struct mtrr_gentry32 *g32 = (struct mtrr_gentry32 *)arg; mm_segment_t oldfs = get_fs(); switch (cmd) { @@ -139,7 +139,7 @@ static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg) arg = (unsigned long)&g; } else { - struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)arg; + struct mtrr_sentry32 *s32 = (struct mtrr_sentry32 *)arg; err = get_user(s.base, &s32->base); err |= get_user(s.size, &s32->size); err |= get_user(s.type, &s32->type); diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c index 2fe68d976..7e95c0a6e 100644 --- a/arch/x86_64/ia32/ia32_signal.c +++ b/arch/x86_64/ia32/ia32_signal.c @@ -42,7 +42,7 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); -void signal_fault(struct pt_regs *regs, void __user *frame, char *where); +void signal_fault(struct pt_regs *regs, void *frame, char *where); int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from) { @@ -136,9 +136,8 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r } asmlinkage long -sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, - stack_ia32_t __user *uoss_ptr, - struct pt_regs regs) +sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, + struct pt_regs regs) { stack_t uss,uoss; int ret; @@ -194,7 +193,7 @@ struct rt_sigframe }; static int -ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc, unsigned int *peax) +ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsigned int *peax) { unsigned int err = 0; @@ -253,9 +252,9 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc, { u32 tmp; - struct _fpstate_ia32 __user * buf; + struct _fpstate_ia32 * buf; err |= __get_user(tmp, &sc->fpstate); - buf = compat_ptr(tmp); + buf = (struct _fpstate_ia32 *) (u64)tmp; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; @@ -276,7 +275,7 @@ badframe: asmlinkage long sys32_sigreturn(struct pt_regs regs) { - struct sigframe __user *frame = (struct sigframe __user *)(regs.rsp-8); + struct sigframe *frame = (struct sigframe *)(regs.rsp - 8); sigset_t set; unsigned int eax; @@ -305,8 +304,9 @@ badframe: asmlinkage long sys32_rt_sigreturn(struct pt_regs regs) { - struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs.rsp - 4); + struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4); sigset_t set; + stack_t st; unsigned int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -338,20 +338,20 @@ badframe: */ static int -ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate, +ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, struct pt_regs *regs, unsigned int mask) { int tmp, err = 0; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->gs); + err |= __put_user(tmp, (unsigned int *)&sc->gs); __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->fs); + err |= __put_user(tmp, (unsigned int *)&sc->fs); __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->ds); + err |= __put_user(tmp, (unsigned int *)&sc->ds); __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int __user *)&sc->es); + err |= __put_user(tmp, (unsigned int *)&sc->es); err |= __put_user((u32)regs->rdi, &sc->edi); err |= __put_user((u32)regs->rsi, &sc->esi); @@ -388,7 +388,7 @@ ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __ /* * Determine which stack to use.. */ -static void __user * +static void * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long rsp; @@ -409,13 +409,13 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) rsp = (unsigned long) ka->sa.sa_restorer; } - return (void __user *)((rsp - frame_size) & -8UL); + return (void *)((rsp - frame_size) & -8UL); } void ia32_setup_frame(int sig, struct k_sigaction *ka, compat_sigset_t *set, struct pt_regs * regs) { - struct sigframe __user *frame; + struct sigframe *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -502,7 +502,7 @@ give_sigsegv: void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, compat_sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 0a2fb66b6..1b988918e 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -322,7 +322,7 @@ ia32_sys_call_table: .quad sys_mknod .quad sys_chmod /* 15 */ .quad sys_lchown16 - .quad quiet_ni_syscall /* old break syscall holder */ + .quad ni_syscall /* old break syscall holder */ .quad sys_stat .quad sys32_lseek .quad sys_getpid /* 20 */ @@ -336,11 +336,11 @@ ia32_sys_call_table: .quad sys_fstat /* (old)fstat */ .quad sys_pause .quad compat_sys_utime /* 30 */ - .quad quiet_ni_syscall /* old stty syscall holder */ - .quad quiet_ni_syscall /* old gtty syscall holder */ + .quad ni_syscall /* old stty syscall holder */ + .quad ni_syscall /* old gtty syscall holder */ .quad sys_access .quad sys_nice - .quad quiet_ni_syscall /* 35 */ /* old ftime syscall holder */ + .quad ni_syscall /* 35 */ /* old ftime syscall holder */ .quad sys_sync .quad sys32_kill .quad sys_rename @@ -349,7 +349,7 @@ ia32_sys_call_table: .quad sys_dup .quad sys32_pipe .quad compat_sys_times - .quad quiet_ni_syscall /* old prof syscall holder */ + .quad ni_syscall /* old prof syscall holder */ .quad sys_brk /* 45 */ .quad sys_setgid16 .quad sys_getgid16 @@ -358,12 +358,12 @@ ia32_sys_call_table: .quad sys_getegid16 /* 50 */ .quad sys_acct .quad sys_umount /* new_umount */ - .quad quiet_ni_syscall /* old lock syscall holder */ + .quad ni_syscall /* old lock syscall holder */ .quad compat_sys_ioctl .quad compat_sys_fcntl64 /* 55 */ - .quad quiet_ni_syscall /* old mpx syscall holder */ + .quad ni_syscall /* old mpx syscall holder */ .quad sys_setpgid - .quad quiet_ni_syscall /* old ulimit syscall holder */ + .quad ni_syscall /* old ulimit syscall holder */ .quad sys32_olduname .quad sys_umask /* 60 */ .quad sys_chroot @@ -403,7 +403,7 @@ ia32_sys_call_table: .quad sys_fchown16 /* 95 */ .quad sys_getpriority .quad sys_setpriority - .quad quiet_ni_syscall /* old profil syscall holder */ + .quad ni_syscall /* old profil syscall holder */ .quad compat_sys_statfs .quad compat_sys_fstatfs /* 100 */ .quad sys_ioperm @@ -417,7 +417,7 @@ ia32_sys_call_table: .quad sys32_uname .quad stub32_iopl /* 110 */ .quad sys_vhangup - .quad quiet_ni_syscall /* old "idle" system call */ + .quad ni_syscall /* old "idle" system call */ .quad sys32_vm86_warning /* vm86old */ .quad compat_sys_wait4 .quad sys_swapoff /* 115 */ @@ -442,7 +442,7 @@ ia32_sys_call_table: .quad quiet_ni_syscall /* bdflush */ .quad sys_sysfs /* 135 */ .quad sys_personality - .quad quiet_ni_syscall /* for afs_syscall */ + .quad ni_syscall /* for afs_syscall */ .quad sys_setfsuid16 .quad sys_setfsgid16 .quad sys_llseek /* 140 */ @@ -493,8 +493,8 @@ ia32_sys_call_table: .quad sys_capset .quad stub32_sigaltstack .quad sys32_sendfile - .quad quiet_ni_syscall /* streams1 */ - .quad quiet_ni_syscall /* streams2 */ + .quad ni_syscall /* streams1 */ + .quad ni_syscall /* streams2 */ .quad stub32_vfork /* 190 */ .quad compat_sys_getrlimit .quad sys32_mmap2 @@ -543,52 +543,51 @@ ia32_sys_call_table: .quad sys_removexattr /* 235 */ .quad sys_lremovexattr .quad sys_fremovexattr - .quad sys_tkill + .quad sys_tkill /* 238 */ .quad sys_sendfile64 .quad compat_sys_futex /* 240 */ - .quad compat_sys_sched_setaffinity - .quad compat_sys_sched_getaffinity + .quad compat_sys_sched_setaffinity + .quad compat_sys_sched_getaffinity .quad sys32_set_thread_area .quad sys32_get_thread_area - .quad sys32_io_setup /* 245 */ + .quad sys32_io_setup .quad sys_io_destroy .quad sys32_io_getevents .quad sys32_io_submit .quad sys_io_cancel - .quad sys_fadvise64 /* 250 */ - .quad quiet_ni_syscall /* free_huge_pages */ - .quad sys_exit_group + .quad sys_fadvise64 + .quad quiet_ni_syscall /* free_huge_pages */ + .quad sys_exit_group /* exit_group */ .quad sys_lookup_dcookie .quad sys_epoll_create - .quad sys_epoll_ctl /* 255 */ + .quad sys_epoll_ctl .quad sys_epoll_wait .quad sys_remap_file_pages .quad sys_set_tid_address .quad sys32_timer_create - .quad compat_timer_settime /* 260 */ + .quad compat_timer_settime .quad compat_timer_gettime .quad sys_timer_getoverrun .quad sys_timer_delete .quad compat_clock_settime - .quad compat_clock_gettime /* 265 */ + .quad compat_clock_gettime .quad compat_clock_getres .quad compat_clock_nanosleep - .quad compat_statfs64 - .quad compat_fstatfs64 - .quad sys_tgkill /* 270 */ + .quad compat_statfs64 /* statfs64 */ + .quad compat_fstatfs64 /* fstatfs64 */ + .quad sys_tgkill .quad compat_sys_utimes .quad sys32_fadvise64_64 - .quad quiet_ni_syscall /* sys_vserver */ - .quad sys_mbind - .quad compat_get_mempolicy /* 275 */ - .quad sys_set_mempolicy + .quad sys_ni_syscall /* sys_vserver */ + .quad sys_ni_syscall /* sys_mbind */ + .quad sys_ni_syscall /* 275 sys_get_mempolicy */ + .quad sys_ni_syscall /* sys_set_mempolicy */ .quad compat_sys_mq_open .quad sys_mq_unlink .quad compat_sys_mq_timedsend .quad compat_sys_mq_timedreceive /* 280 */ .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr - .quad quiet_ni_syscall /* reserved for kexec */ /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index 01202b792..c2ef94295 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -229,7 +228,6 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) { struct task_struct *child; struct pt_regs *childregs; - void __user *datap = compat_ptr(data); int ret; __u32 val; @@ -266,7 +264,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32)) ret = -EIO; else - ret = put_user(val, (unsigned int __user *)datap); + ret = put_user(val, (unsigned int *)(u64)data); break; case PTRACE_POKEDATA: @@ -279,7 +277,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) case PTRACE_PEEKUSR: ret = getreg32(child, addr, &val); if (ret == 0) - ret = put_user(val, (__u32 __user *)datap); + ret = put_user(val, (__u32 *)(unsigned long) data); break; case PTRACE_POKEUSR: @@ -288,15 +286,15 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) case PTRACE_GETREGS: { /* Get all gp regs from the child. */ int i; - if (!access_ok(VERIFY_WRITE, datap, 16*4)) { + if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) { ret = -EIO; break; } ret = 0; for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) { getreg32(child, i, &val); - ret |= __put_user(val,(u32 __user *)datap); - datap += sizeof(u32); + ret |= __put_user(val,(u32 *) (unsigned long) data); + data += sizeof(u32); } break; } @@ -304,40 +302,40 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp; int i; - if (!access_ok(VERIFY_READ, datap, 16*4)) { + if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) { ret = -EIO; break; } ret = 0; for ( i = 0; i <= 16*4; i += sizeof(u32) ) { - ret |= __get_user(tmp, (u32 __user *)datap); + ret |= __get_user(tmp, (u32 *) (unsigned long) data); putreg32(child, i, tmp); - datap += sizeof(u32); + data += sizeof(u32); } break; } case PTRACE_GETFPREGS: ret = -EIO; - if (!access_ok(VERIFY_READ, compat_ptr(data), + if (!access_ok(VERIFY_READ, (void *)(u64)data, sizeof(struct user_i387_struct))) break; - save_i387_ia32(child, datap, childregs, 1); + save_i387_ia32(child, (void *)(u64)data, childregs, 1); ret = 0; break; case PTRACE_SETFPREGS: ret = -EIO; - if (!access_ok(VERIFY_WRITE, datap, + if (!access_ok(VERIFY_WRITE, (void *)(u64)data, sizeof(struct user_i387_struct))) break; ret = 0; /* don't check EFAULT to be bug-to-bug compatible to i386 */ - restore_i387_ia32(child, datap, 1); + restore_i387_ia32(child, (void *)(u64)data, 1); break; case PTRACE_GETFPXREGS: { - struct user32_fxsr_struct __user *u = datap; + struct user32_fxsr_struct *u = (void *)(u64)data; init_fpu(child); ret = -EIO; if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) @@ -350,7 +348,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) break; } case PTRACE_SETFPXREGS: { - struct user32_fxsr_struct __user *u = datap; + struct user32_fxsr_struct *u = (void *)(u64)data; unlazy_fpu(child); ret = -EIO; if (!access_ok(VERIFY_READ, u, sizeof(*u))) diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 6f7622399..d59981b95 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -76,9 +76,9 @@ #define A(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x)) #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) -int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) +int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf) { typeof(ubuf->st_uid) uid = 0; typeof(ubuf->st_gid) gid = 0; @@ -110,7 +110,7 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) } asmlinkage long -sys32_truncate64(char __user * filename, unsigned long offset_low, unsigned long offset_high) +sys32_truncate64(char * filename, unsigned long offset_low, unsigned long offset_high) { return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low); } @@ -125,7 +125,7 @@ sys32_ftruncate64(unsigned int fd, unsigned long offset_low, unsigned long offse support for 64bit inode numbers. */ static int -cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) +cp_stat64(struct stat64 *ubuf, struct kstat *stat) { typeof(ubuf->st_uid) uid = 0; typeof(ubuf->st_gid) gid = 0; @@ -154,7 +154,7 @@ cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) } asmlinkage long -sys32_stat64(char __user * filename, struct stat64 __user *statbuf) +sys32_stat64(char * filename, struct stat64 *statbuf) { struct kstat stat; int ret = vfs_stat(filename, &stat); @@ -164,7 +164,7 @@ sys32_stat64(char __user * filename, struct stat64 __user *statbuf) } asmlinkage long -sys32_lstat64(char __user * filename, struct stat64 __user *statbuf) +sys32_lstat64(char * filename, struct stat64 *statbuf) { struct kstat stat; int ret = vfs_lstat(filename, &stat); @@ -174,7 +174,7 @@ sys32_lstat64(char __user * filename, struct stat64 __user *statbuf) } asmlinkage long -sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) +sys32_fstat64(unsigned int fd, struct stat64 *statbuf) { struct kstat stat; int ret = vfs_fstat(fd, &stat); @@ -199,7 +199,7 @@ struct mmap_arg_struct { }; asmlinkage long -sys32_mmap(struct mmap_arg_struct __user *arg) +sys32_mmap(struct mmap_arg_struct *arg) { struct mmap_arg_struct a; struct file *file = NULL; @@ -241,7 +241,7 @@ sys32_mprotect(unsigned long start, size_t len, unsigned long prot) } asmlinkage long -sys32_pipe(int __user *fd) +sys32_pipe(int *fd) { int retval; int fds[2]; @@ -256,8 +256,8 @@ sys32_pipe(int __user *fd) } asmlinkage long -sys32_rt_sigaction(int sig, struct sigaction32 __user *act, - struct sigaction32 __user *oact, unsigned int sigsetsize) +sys32_rt_sigaction(int sig, struct sigaction32 *act, + struct sigaction32 *oact, unsigned int sigsetsize) { struct k_sigaction new_ka, old_ka; int ret; @@ -321,7 +321,7 @@ sys32_rt_sigaction(int sig, struct sigaction32 __user *act, } asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact) +sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -395,7 +395,7 @@ sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, } static inline long -get_tv32(struct timeval *o, struct compat_timeval __user *i) +get_tv32(struct timeval *o, struct compat_timeval *i) { int err = -EFAULT; if (access_ok(VERIFY_READ, i, sizeof(*i))) { @@ -406,7 +406,7 @@ get_tv32(struct timeval *o, struct compat_timeval __user *i) } static inline long -put_tv32(struct compat_timeval __user *o, struct timeval *i) +put_tv32(struct compat_timeval *o, struct timeval *i) { int err = -EFAULT; if (access_ok(VERIFY_WRITE, o, sizeof(*o))) { @@ -442,7 +442,7 @@ sys32_alarm(unsigned int seconds) extern struct timezone sys_tz; asmlinkage long -sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) +sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz) { if (tv) { struct timeval ktv; @@ -458,7 +458,7 @@ sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) } asmlinkage long -sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) +sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz) { struct timeval ktv; struct timespec kts; @@ -493,14 +493,14 @@ struct old_linux32_dirent { }; struct getdents32_callback { - struct linux32_dirent __user * current_dir; - struct linux32_dirent __user * previous; + struct linux32_dirent * current_dir; + struct linux32_dirent * previous; int count; int error; }; struct readdir32_callback { - struct old_linux32_dirent __user * dirent; + struct old_linux32_dirent * dirent; int count; }; @@ -508,7 +508,7 @@ static int filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct linux32_dirent __user * dirent; + struct linux32_dirent * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2, 4); @@ -524,18 +524,18 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - put_user(d_type, (char __user *)dirent + reclen - 1); - dirent = ((void __user *)dirent) + reclen; + put_user(d_type, (char *)dirent + reclen - 1); + dirent = ((void *)dirent) + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; } asmlinkage long -sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count) +sys32_getdents (unsigned int fd, void * dirent, unsigned int count) { struct file * file; - struct linux32_dirent __user * lastdirent; + struct linux32_dirent * lastdirent; struct getdents32_callback buf; int error; @@ -544,7 +544,7 @@ sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count) if (!file) goto out; - buf.current_dir = (struct linux32_dirent __user *) dirent; + buf.current_dir = (struct linux32_dirent *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -569,7 +569,7 @@ static int fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned d_type) { struct readdir32_callback * buf = (struct readdir32_callback *) __buf; - struct old_linux32_dirent __user * dirent; + struct old_linux32_dirent * dirent; if (buf->count) return -EINVAL; @@ -584,7 +584,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t } asmlinkage long -sys32_oldreaddir (unsigned int fd, void __user * dirent, unsigned int count) +sys32_oldreaddir (unsigned int fd, void * dirent, unsigned int count) { int error; struct file * file; @@ -615,7 +615,7 @@ struct sel_arg_struct { }; asmlinkage long -sys32_old_select(struct sel_arg_struct __user *arg) +sys32_old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; @@ -630,7 +630,7 @@ sys32_old_select(struct sel_arg_struct __user *arg) * sys_gettimeofday(). x86-64 did this but i386 Linux did not * so we have to implement this system call here. */ -asmlinkage long sys32_time(int __user * tloc) +asmlinkage long sys32_time(int * tloc) { int i; struct timeval tv; @@ -693,7 +693,7 @@ struct sysinfo32 { }; asmlinkage long -sys32_sysinfo(struct sysinfo32 __user *info) +sys32_sysinfo(struct sysinfo32 *info) { struct sysinfo s; int ret; @@ -742,7 +742,7 @@ sys32_sysinfo(struct sysinfo32 __user *info) } asmlinkage long -sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) +sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec *interval) { struct timespec t; int ret; @@ -782,8 +782,8 @@ sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) asmlinkage long -sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, - struct compat_timespec __user *uts, compat_size_t sigsetsize) +sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo, + struct compat_timespec *uts, compat_size_t sigsetsize) { sigset_t s; compat_sigset_t s32; @@ -820,7 +820,7 @@ sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, } asmlinkage long -sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo) +sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) { siginfo_t info; int ret; @@ -856,7 +856,7 @@ struct sysctl_ia32 { asmlinkage long -sys32_sysctl(struct sysctl_ia32 __user *args32) +sys32_sysctl(struct sysctl_ia32 *args32) { #ifndef CONFIG_SYSCTL return -ENOSYS; @@ -906,14 +906,14 @@ sys32_sysctl(struct sysctl_ia32 __user *args32) /* warning: next two assume little endian */ asmlinkage long -sys32_pread(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi) +sys32_pread(unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi) { return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } asmlinkage long -sys32_pwrite(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi) +sys32_pwrite(unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi) { return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); @@ -934,7 +934,7 @@ sys32_personality(unsigned long personality) } asmlinkage long -sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) +sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -971,7 +971,7 @@ struct timex32 { extern int do_adjtimex(struct timex *); asmlinkage long -sys32_adjtimex(struct timex32 __user *utp) +sys32_adjtimex(struct timex32 *utp) { struct timex txc; int ret; @@ -1056,9 +1056,10 @@ asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, return error; } -asmlinkage long sys32_olduname(struct oldold_utsname __user * name) +asmlinkage long sys32_olduname(struct oldold_utsname * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -1067,13 +1068,14 @@ asmlinkage long sys32_olduname(struct oldold_utsname __user * name) down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); __put_user(0,name->sysname+__OLD_UTS_LEN); - __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); __put_user(0,name->nodename+__OLD_UTS_LEN); - __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); __put_user(0,name->release+__OLD_UTS_LEN); - __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); __put_user(0,name->version+__OLD_UTS_LEN); { char *arch = "x86_64"; @@ -1090,13 +1092,13 @@ asmlinkage long sys32_olduname(struct oldold_utsname __user * name) return error; } -long sys32_uname(struct old_utsname __user * name) +long sys32_uname(struct old_utsname * name) { int err; if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); @@ -1124,7 +1126,7 @@ long sys32_ustat(unsigned dev, struct ustat32 __user *u32p) return ret; } -asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, +asmlinkage long sys32_execve(char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, struct pt_regs regs) { long error; @@ -1143,8 +1145,8 @@ asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs) { - void __user *parent_tid = (void __user *)regs.rdx; - void __user *child_tid = (void __user *)regs.rdi; + void *parent_tid = (void *)regs.rdx; + void *child_tid = (void *)regs.rdi; if (!newsp) newsp = regs.rsp; return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, @@ -1166,7 +1168,7 @@ long sys32_kill(int pid, int sig) } -long sys32_io_setup(unsigned nr_reqs, u32 __user *ctx32p) +long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) { long ret; aio_context_t ctx64; @@ -1181,7 +1183,7 @@ long sys32_io_setup(unsigned nr_reqs, u32 __user *ctx32p) } asmlinkage long sys32_io_submit(aio_context_t ctx_id, int nr, - compat_uptr_t __user *iocbpp) + compat_uptr_t *iocbpp) { struct kioctx *ctx; long ret = 0; @@ -1201,8 +1203,7 @@ asmlinkage long sys32_io_submit(aio_context_t ctx_id, int nr, for (i=0; i 32bit use arch_prctl() */ -int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +int do_set_thread_area(struct thread_struct *t, struct user_desc *u_info) { struct user_desc info; struct n_desc_struct *desc; @@ -75,7 +75,7 @@ int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) return 0; } -asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info) +asmlinkage long sys32_set_thread_area(struct user_desc *u_info) { return do_set_thread_area(¤t->thread, u_info); } @@ -102,7 +102,7 @@ asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info) #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) #define GET_LONGMODE(desc) (((desc)->b >> 21) & 1) -int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +int do_get_thread_area(struct thread_struct *t, struct user_desc *u_info) { struct user_desc info; struct n_desc_struct *desc; @@ -132,7 +132,7 @@ int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info) return 0; } -asmlinkage long sys32_get_thread_area(struct user_desc __user *u_info) +asmlinkage long sys32_get_thread_area(struct user_desc *u_info) { return do_get_thread_area(¤t->thread, u_info); } @@ -141,11 +141,10 @@ asmlinkage long sys32_get_thread_area(struct user_desc __user *u_info) int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs) { struct n_desc_struct *desc; - struct user_desc info; - struct user_desc __user *cp; + struct user_desc info, *cp; int idx; - cp = (void __user *)childregs->rsi; + cp = (void *)childregs->rsi; if (copy_from_user(&info, cp, sizeof(info))) return -EFAULT; if (LDT_empty(&info)) diff --git a/arch/x86_64/kernel/Makefile-HEAD b/arch/x86_64/kernel/Makefile-HEAD deleted file mode 100644 index dc6f2695e..000000000 --- a/arch/x86_64/kernel/Makefile-HEAD +++ /dev/null @@ -1,38 +0,0 @@ -# -# Makefile for the linux kernel. -# - -extra-y := head.o head64.o init_task.o vmlinux.lds.s -EXTRA_AFLAGS := -traditional -obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ - ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ - x8664_ksyms.o i387.o syscall.o vsyscall.o \ - setup64.o bootflag.o e820.o reboot.o warmreboot.o -obj-y += mce.o - -obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI_BOOT) += acpi/ -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o -obj-$(CONFIG_PM) += suspend.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o -obj-$(CONFIG_CPU_FREQ) += cpufreq/ -obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o -obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o -obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_SCHED_SMT) += domain.o - -obj-$(CONFIG_MODULES) += module.o - -obj-y += topology.o - -bootflag-y += ../../i386/kernel/bootflag.o -cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o -topology-y += ../../i386/mach-default/topology.o -swiotlb-$(CONFIG_SWIOTLB) += ../../ia64/lib/swiotlb.o -microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c index 3331a564f..20e9266df 100644 --- a/arch/x86_64/kernel/acpi/sleep.c +++ b/arch/x86_64/kernel/acpi/sleep.c @@ -114,6 +114,7 @@ void __init acpi_reserve_bootmem(void) acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) printk(KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt to suspend\n"); + printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address); } static int __init acpi_sleep_setup(char *str) diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index e338e5f26..6235eab18 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -140,6 +140,41 @@ void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned lon } } +int __get_cpu_vendor(void) +{ + char v[16]; + int cpuid_level; + memset(v, 0, 16); + cpuid(0x00000000, &cpuid_level, + (int *)&v[0], + (int *)&v[8], + (int *)&v[4]); + if (!strcmp(v, "GenuineIntel")) + return X86_VENDOR_INTEL; + else if (!strcmp(v, "AuthenticAMD")) + return X86_VENDOR_AMD; + else if (!strcmp(v, "CyrixInstead")) + return X86_VENDOR_CYRIX; +// else if (!strcmp(v, "Geode by NSC")) +// return X86_VENDOR_NSC; + else if (!strcmp(v, "UMC UMC UMC ")) + return X86_VENDOR_UMC; + else if (!strcmp(v, "CentaurHauls")) + return X86_VENDOR_CENTAUR; + else if (!strcmp(v, "NexGenDriven")) + return X86_VENDOR_NEXGEN; + else if (!strcmp(v, "RiseRiseRise")) + return X86_VENDOR_RISE; + else if (!strcmp(v, "GenuineTMx86") || + !strcmp(v, "TransmetaCPU")) + return X86_VENDOR_TRANSMETA; +// else if (!strcmp(v, "SiS SiS SiS ")) +// return X86_VENDOR_SIS; + else + return X86_VENDOR_UNKNOWN; +} + + /* * Find the highest page frame number we have available */ @@ -154,6 +189,9 @@ unsigned long __init e820_end_of_ram(void) start = round_up(ei->addr, PAGE_SIZE); end = round_down(ei->addr + ei->size, PAGE_SIZE); + if (__get_cpu_vendor() != X86_VENDOR_AMD) + end = round_down(min(end, 0xffffffff),PAGE_SIZE); + if (start >= end) continue; if (ei->type == E820_RAM) { diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 4055c78d2..b04a1add2 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -73,8 +73,6 @@ static void __init setup_boot_cpu_data(void) boot_cpu_data.x86_mask = eax & 0xf; } -extern char _end[]; - void __init x86_64_start_kernel(char * real_mode_data) { char *s; @@ -82,9 +80,6 @@ void __init x86_64_start_kernel(char * real_mode_data) clear_bss(); pda_init(0); copy_bootdata(real_mode_data); -#ifdef CONFIG_SMP - cpu_set(0, cpu_online_map); -#endif /* default console: */ if (!strstr(saved_command_line, "console=")) strcat(saved_command_line, " console=tty0"); @@ -100,10 +95,6 @@ void __init x86_64_start_kernel(char * real_mode_data) if (strstr(saved_command_line, "disableapic")) disable_apic = 1; #endif - /* You need early console to see that */ - if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE) - panic("Kernel too big for kernel mapping\n"); - setup_boot_cpu_data(); start_kernel(); } diff --git a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387.c index 6bc3d64e0..1aa4deb43 100644 --- a/arch/x86_64/kernel/i387.c +++ b/arch/x86_64/kernel/i387.c @@ -77,7 +77,7 @@ void init_fpu(struct task_struct *child) * Signal frame handlers. */ -int save_i387(struct _fpstate __user *buf) +int save_i387(struct _fpstate *buf) { struct task_struct *tsk = current; int err = 0; @@ -95,7 +95,7 @@ int save_i387(struct _fpstate __user *buf) return 0; tsk->used_math = 0; /* trigger finit */ if (tsk->thread_info->status & TS_USEDFPU) { - err = save_i387_checking((struct i387_fxsave_struct __user *)buf); + err = save_i387_checking((struct i387_fxsave_struct *)buf); if (err) return err; stts(); } else { @@ -110,14 +110,14 @@ int save_i387(struct _fpstate __user *buf) * ptrace request handlers. */ -int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *tsk) +int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk) { init_fpu(tsk); - return __copy_to_user(buf, &tsk->thread.i387.fxsave, + return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)) ? -EFAULT : 0; } -int set_fpregs(struct task_struct *tsk, struct user_i387_struct __user *buf) +int set_fpregs(struct task_struct *tsk, struct user_i387_struct *buf) { if (__copy_from_user(&tsk->thread.i387.fxsave, buf, sizeof(struct user_i387_struct))) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 718504a32..f7625f3ee 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -252,8 +252,7 @@ void __init check_ioapic(void) switch (vendor) { case PCI_VENDOR_ID_VIA: #ifdef CONFIG_GART_IOMMU - if ((end_pfn >= (0xffffffff>>PAGE_SHIFT) || - force_iommu) && + if (end_pfn >= (0xffffffff>>PAGE_SHIFT) && !iommu_aperture_allowed) { printk(KERN_INFO "Looks like a VIA chipset. Disabling IOMMU. Overwrite with \"iommu=allowed\"\n"); diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index bfdb95e8b..732a6f4d3 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -833,8 +833,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, return len; } -static int irq_affinity_write_proc (struct file *file, - const char __user *buffer, +static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { int irq = (long) data, full_count = count, err; @@ -872,8 +871,7 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, return len; } -static int prof_cpu_mask_write_proc (struct file *file, - const char __user *buffer, +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { unsigned long full_count = count, err; diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c index 4e43e53a1..1b6252c09 100644 --- a/arch/x86_64/kernel/ldt.c +++ b/arch/x86_64/kernel/ldt.c @@ -125,7 +125,7 @@ void destroy_context(struct mm_struct *mm) } } -static int read_ldt(void __user * ptr, unsigned long bytecount) +static int read_ldt(void * ptr, unsigned long bytecount) { int err; unsigned long size; @@ -153,7 +153,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) return bytecount; } -static int read_default_ldt(void __user * ptr, unsigned long bytecount) +static int read_default_ldt(void * ptr, unsigned long bytecount) { /* Arbitrary number */ /* x86-64 default LDT is all zeros */ @@ -164,7 +164,7 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount) return bytecount; } -static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { struct task_struct *me = current; struct mm_struct * mm = me->mm; @@ -225,7 +225,7 @@ out: return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) { int ret = -ENOSYS; diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 3bb678f1e..922d62fcf 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -25,9 +25,8 @@ #define NR_BANKS 5 static int mce_disabled __initdata; -/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic, - 3: never panic or exit (for testing only) */ -static int tolerant = 1; +/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic */ +static int tolerant = 2; static int banks; static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL }; @@ -97,8 +96,7 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start) int i; oops_begin(); for (i = 0; i < MCE_LOG_LEN; i++) { - unsigned long tsc = mcelog.entry[i].tsc; - if (time_before(tsc, start)) + if (mcelog.entry[i].tsc < start) continue; print_mce(&mcelog.entry[i]); if (mcelog.entry[i].tsc == backup->tsc) @@ -106,10 +104,7 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start) } if (backup) print_mce(backup); - if (tolerant >= 3) - printk("Fake panic: %s\n", msg); - else - panic(msg); + panic(msg); } static int mce_available(struct cpuinfo_x86 *c) @@ -125,8 +120,8 @@ static int mce_available(struct cpuinfo_x86 *c) void do_machine_check(struct pt_regs * regs, long error_code) { - struct mce m, panicm; - int nowayout = (tolerant < 1); + struct mce m; + int nowayout = 0; int kill_it = 0; u64 mcestart; int i; @@ -154,31 +149,13 @@ void do_machine_check(struct pt_regs * regs, long error_code) for (i = 0; i < banks; i++) { if (!bank[i]) continue; - - m.misc = 0; - m.addr = 0; rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status); if ((m.status & MCI_STATUS_VAL) == 0) continue; - /* Should be implied by the banks check above, but - check it anyways */ - if ((m.status & MCI_STATUS_EN) == 0) - continue; - /* Did this bank cause the exception? */ - /* Assume that the bank with uncorrectable errors did it, - and that there is only a single one. */ - if (m.status & MCI_STATUS_UC) { - panicm = m; - } else { - m.rip = 0; - m.cs = 0; - } - - /* In theory _OVER could be a nowayout too, but - assume any overflowed errors were no fatal. */ - nowayout |= !!(m.status & MCI_STATUS_PCC); + nowayout |= (tolerant < 1); + nowayout |= !!(m.status & (MCI_STATUS_OVER|MCI_STATUS_PCC)); kill_it |= !!(m.status & MCI_STATUS_UC); m.bank = i; @@ -199,10 +176,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) if (nowayout) mce_panic("Machine check", &m, mcestart); if (kill_it) { - int user_space = 0; - - if (m.mcgstatus & MCG_STATUS_RIPV) - user_space = m.rip && (m.cs & 3); + int user_space = (m.rip && (m.cs & 3)); /* When the machine was in user space and the CPU didn't get confused it's normally not necessary to panic, unless you @@ -213,12 +187,11 @@ void do_machine_check(struct pt_regs * regs, long error_code) it is best to just halt the machine. */ if ((!user_space && (panic_on_oops || tolerant < 2)) || (unsigned)current->pid <= 1) - mce_panic("Uncorrected machine check", &panicm, mcestart); + mce_panic("Uncorrected machine check", &m, mcestart); /* do_exit takes an awful lot of locks and has as slight risk of deadlocking. If you don't want that don't set tolerant >= 2 */ - if (tolerant < 3) - do_exit(SIGBUS); + do_exit(SIGBUS); } } @@ -234,7 +207,7 @@ static void mce_clear_all(void) * Periodic polling timer for "silent" machine check errors. */ -static int check_interval = 5 * 60; /* 5 minutes */ +static int check_interval = 3600; /* one hour */ static void mcheck_timer(void *data); static DECLARE_WORK(mcheck_work, mcheck_timer, NULL); @@ -324,12 +297,12 @@ static void collect_tscs(void *data) rdtscll(cpu_tsc[smp_processor_id()]); } -static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off) +static ssize_t mce_read(struct file *filp, char *ubuf, size_t usize, loff_t *off) { unsigned long cpu_tsc[NR_CPUS]; static DECLARE_MUTEX(mce_read_sem); unsigned next; - char __user *buf = ubuf; + char *buf = ubuf; int i, err; down(&mce_read_sem); @@ -375,20 +348,19 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg) { - int __user *p = (int __user *)arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch (cmd) { case MCE_GET_RECORD_LEN: - return put_user(sizeof(struct mce), p); + return put_user(sizeof(struct mce), (int *)arg); case MCE_GET_LOG_LEN: - return put_user(MCE_LOG_LEN, p); + return put_user(MCE_LOG_LEN, (int *)arg); case MCE_GETCLEAR_FLAGS: { unsigned flags; do { flags = mcelog.flags; } while (cmpxchg(&mcelog.flags, flags, 0) != flags); - return put_user(flags, p); + return put_user(flags, (int *)arg); } default: return -ENOTTY; diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c index c2256e5ac..78ce354a5 100644 --- a/arch/x86_64/kernel/module.c +++ b/arch/x86_64/kernel/module.c @@ -121,7 +121,7 @@ void *module_alloc(unsigned long size) goto fail; } - if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages)) + if (map_vm_area(area, PAGE_KERNEL_EXEC, &pages)) goto fail; memset(addr, 0, size); diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 7dcc1b51a..27122be57 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -575,7 +575,6 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) extern void __bad_mpf_size(void); unsigned int *bp = phys_to_virt(base); struct intel_mp_floating *mpf; - static int printed __initdata; Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); if (sizeof(*mpf) != 16) @@ -599,10 +598,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) bp += 4; length -= 16; } - if (!printed) { - printk(KERN_INFO "No mptable found.\n"); - printed = 1; - } + printk(KERN_INFO "No mptable found.\n"); return 0; } diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c index 654e4578d..d2e6fff1b 100644 --- a/arch/x86_64/kernel/msr.c +++ b/arch/x86_64/kernel/msr.c @@ -186,10 +186,10 @@ static loff_t msr_seek(struct file *file, loff_t offset, int orig) return ret; } -static ssize_t msr_read(struct file * file, char __user * buf, +static ssize_t msr_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - char __user *tmp = buf; + u32 *tmp = (u32 *)buf; u32 data[2]; size_t rv; u32 reg = *ppos; @@ -205,16 +205,16 @@ static ssize_t msr_read(struct file * file, char __user * buf, return err; if ( copy_to_user(tmp,&data,8) ) return -EFAULT; - tmp += 8; + tmp += 2; } - return tmp - buf; + return ((char *)tmp) - buf; } -static ssize_t msr_write(struct file * file, const char __user * buf, +static ssize_t msr_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { - const char __user *tmp = buf; + const u32 *tmp = (const u32 *)buf; u32 data[2]; size_t rv; u32 reg = *ppos; @@ -230,10 +230,10 @@ static ssize_t msr_write(struct file * file, const char __user * buf, err = do_wrmsr(cpu, reg, data[0], data[1]); if ( err ) return err; - tmp += 8; + tmp += 2; } - return tmp - buf; + return ((char *)tmp) - buf; } static int msr_open(struct inode *inode, struct file *file) @@ -241,7 +241,7 @@ static int msr_open(struct inode *inode, struct file *file) int cpu = iminor(file->f_dentry->d_inode); struct cpuinfo_x86 *c = &(cpu_data)[cpu]; - if (cpu >= NR_CPUS || !cpu_online(cpu)) + if (!cpu_online(cpu)) return -ENXIO; /* No such CPU */ if ( !cpu_has(c, X86_FEATURE_MSR) ) return -EIO; /* MSR not supported */ diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index f7d3cf3ca..6b7861945 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -521,8 +521,7 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * * sys_execve() executes a new program. */ asmlinkage -long sys_execve(char __user *name, char __user * __user *argv, - char __user * __user *envp, struct pt_regs regs) +long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs) { long error; char * filename; @@ -551,7 +550,7 @@ asmlinkage long sys_fork(struct pt_regs regs) return do_fork(SIGCHLD, regs.rsp, ®s, 0, NULL, NULL); } -asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs regs) +asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *parent_tid, void *child_tid, struct pt_regs regs) { if (!newsp) newsp = regs.rsp; @@ -665,7 +664,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) rdmsrl(MSR_FS_BASE, base); } else base = task->thread.fs; - ret = put_user(base, (unsigned long __user *)addr); + ret = put_user(base, (unsigned long *)addr); break; } case ARCH_GET_GS: { @@ -676,7 +675,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) rdmsrl(MSR_KERNEL_GS_BASE, base); } else base = task->thread.gs; - ret = put_user(base, (unsigned long __user *)addr); + ret = put_user(base, (unsigned long *)addr); break; } diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 5dd7752ae..87ab1e27f 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -208,6 +208,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = -EPERM; if (pid == 1) /* you may not mess with init */ @@ -232,7 +234,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data ret = -EIO; if (copied != sizeof(tmp)) break; - ret = put_user(tmp,(unsigned long __user *) data); + ret = put_user(tmp,(unsigned long *) data); break; } @@ -271,7 +273,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data tmp = 0; break; } - ret = put_user(tmp,(unsigned long __user *) data); + ret = put_user(tmp,(unsigned long *) data); break; } @@ -360,20 +362,19 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data don't use it against 64bit processes, use PTRACE_ARCH_PRCTL instead. */ case PTRACE_SET_THREAD_AREA: { - struct user_desc __user *p; int old; - p = (struct user_desc __user *)data; - get_user(old, &p->entry_number); - put_user(addr, &p->entry_number); - ret = do_set_thread_area(&child->thread, p); - put_user(old, &p->entry_number); + get_user(old, &((struct user_desc *)data)->entry_number); + put_user(addr, &((struct user_desc *)data)->entry_number); + ret = do_set_thread_area(&child->thread, + (struct user_desc *)data); + put_user(old, &((struct user_desc *)data)->entry_number); break; case PTRACE_GET_THREAD_AREA: - p = (struct user_desc __user *)data; - get_user(old, &p->entry_number); - put_user(addr, &p->entry_number); - ret = do_get_thread_area(&child->thread, p); - put_user(old, &p->entry_number); + get_user(old, &((struct user_desc *)data)->entry_number); + put_user(addr, &((struct user_desc *)data)->entry_number); + ret = do_get_thread_area(&child->thread, + (struct user_desc *)data); + put_user(old, &((struct user_desc *)data)->entry_number); break; } #endif @@ -429,12 +430,12 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, FRAME_SIZE)) { + if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE)) { ret = -EIO; break; } for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { - __put_user(getreg(child, ui),(unsigned long __user *) data); + __put_user(getreg(child, ui),(unsigned long *) data); data += sizeof(long); } ret = 0; @@ -443,12 +444,12 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp; - if (!access_ok(VERIFY_READ, (unsigned __user *)data, FRAME_SIZE)) { + if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE)) { ret = -EIO; break; } for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { - __get_user(tmp, (unsigned long __user *) data); + __get_user(tmp, (unsigned long *) data); putreg(child, ui, tmp); data += sizeof(long); } @@ -457,23 +458,23 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data } case PTRACE_GETFPREGS: { /* Get the child extended FPU state. */ - if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, + if (!access_ok(VERIFY_WRITE, (unsigned *)data, sizeof(struct user_i387_struct))) { ret = -EIO; break; } - ret = get_fpregs((struct user_i387_struct __user *)data, child); + ret = get_fpregs((struct user_i387_struct *)data, child); break; } case PTRACE_SETFPREGS: { /* Set the child extended FPU state. */ - if (!access_ok(VERIFY_READ, (unsigned __user *)data, + if (!access_ok(VERIFY_READ, (unsigned *)data, sizeof(struct user_i387_struct))) { ret = -EIO; break; } child->used_math = 1; - ret = set_fpregs(child, (struct user_i387_struct __user *)data); + ret = set_fpregs(child, (struct user_i387_struct *)data); break; } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 14a25720f..09f9c7222 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -253,8 +253,6 @@ static __init void parse_cmdline_early (char ** cmdline_p) /* acpi=ht just means: do ACPI MADT parsing at bootup, but don't enable the full ACPI interpreter */ if (!memcmp(from, "acpi=ht", 7)) { - /* if (!acpi_force) */ - disable_acpi(); acpi_ht = 1; } else if (!memcmp(from, "pci=noacpi", 10)) @@ -537,7 +535,8 @@ void __init setup_arch(char **cmdline_p) * the bootmem allocator) but before get_smp_config (to allow parsing * of MADT). */ - acpi_boot_init(); + if (!acpi_disabled) + acpi_boot_init(); #endif #ifdef CONFIG_X86_LOCAL_APIC /* @@ -910,7 +909,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) c->x86_model += ((tfms >> 16) & 0xF) << 4; } if (c->x86_capability[0] & (1<<19)) - c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; + c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; @@ -968,7 +967,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) display_cacheinfo(c); break; } - + select_idle_routine(c); detect_ht(c); diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index 9d3137a55..dd0d41548 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -39,7 +39,7 @@ extern unsigned char __per_cpu_start[], __per_cpu_end[]; extern struct desc_ptr cpu_gdt_descr[]; struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; -char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned"))); +char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned; unsigned long __supported_pte_mask = ~0UL; static int do_not_nx __initdata = 0; @@ -190,8 +190,7 @@ void pda_init(int cpu) pda->irqstackptr += IRQSTACKSIZE-64; } -char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ] -__attribute__((section(".bss.page_aligned"))); +char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ]; void __init syscall_init(void) { diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index d814db6e3..fc81ceb32 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -40,7 +40,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs); asmlinkage long -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs regs) +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs regs) { sigset_t saveset, newset; @@ -57,7 +57,7 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs re current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n", saveset, newset, ®s, regs.rip); #endif @@ -71,7 +71,7 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs re } asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs regs) +sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs regs) { return do_sigaltstack(uss, uoss, regs.rsp); } @@ -89,7 +89,7 @@ struct rt_sigframe }; static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax) +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, unsigned long *prax) { unsigned int err = 0; @@ -117,7 +117,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned } { - struct _fpstate __user * buf; + struct _fpstate * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { @@ -136,11 +136,10 @@ badframe: asmlinkage long sys_rt_sigreturn(struct pt_regs regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 8); sigset_t set; long eax; - frame = (struct rt_sigframe __user *)(regs.rsp - 8); if (verify_area(VERIFY_READ, frame, sizeof(*frame))) { goto badframe; } @@ -158,7 +157,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs) goto badframe; } -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax); #endif @@ -177,7 +176,7 @@ badframe: */ static inline int -setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me) { int err = 0; @@ -214,7 +213,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo * Determine which stack to use.. */ -static void __user * +static void * get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) { unsigned long rsp; @@ -229,20 +228,20 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) rsp = current->sas_ss_sp + current->sas_ss_size; } - return (void __user *)round_down(rsp - size, 16); + return (void *)round_down(rsp - size, 16); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe __user *frame; - struct _fpstate __user *fp = NULL; + struct rt_sigframe *frame; + struct _fpstate *fp = NULL; int err = 0; struct task_struct *me = current; if (me->used_math) { fp = get_stack(ka, regs, sizeof(struct _fpstate)); - frame = (void __user *)round_down((u64)fp - sizeof(struct rt_sigframe), 16) - 8; + frame = (void *)round_down((u64)fp - sizeof(struct rt_sigframe), 16) - 8; if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { goto give_sigsegv; @@ -295,7 +294,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, goto give_sigsegv; } -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax); #endif @@ -320,7 +319,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, set_fs(USER_DS); regs->eflags &= ~TF_MASK; -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); #endif @@ -343,7 +342,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, { struct k_sigaction *ka = ¤t->sighand->action[sig-1]; -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, regs->rip, regs->rsp, regs); #endif @@ -455,7 +454,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags) { -#ifdef DEBUG_SIG +#if DEBUG_SIG printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n", thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current)); #endif @@ -471,7 +470,7 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_ do_signal(regs,oldset); } -void signal_fault(struct pt_regs *regs, void __user *frame, char *where) +void signal_fault(struct pt_regs *regs, void *frame, char *where) { struct task_struct *me = current; if (exception_trace) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index ba2cba68d..3ea64ef6d 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -895,17 +895,15 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpu_set(i, cpu_sibling_map[cpu]); } } - } else { + } else { siblings++; cpu_set(cpu, cpu_sibling_map[cpu]); } - if (siblings != smp_num_siblings) { - printk(KERN_WARNING - "WARNING: %d siblings found for CPU%d, should be %d\n", + if (siblings != smp_num_siblings) + printk(KERN_WARNING + "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings); - smp_num_siblings = siblings; - } } Dprintk("Boot done.\n"); diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index 38a286ca3..752d84075 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -25,7 +25,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage long sys_pipe(int __user *fildes) +asmlinkage long sys_pipe(int *fildes) { int fd[2]; int error; @@ -142,24 +142,24 @@ full_search: } } -asmlinkage long sys_uname(struct new_utsname __user * name) +asmlinkage long sys_uname(struct new_utsname * name) { int err; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); return err ? -EFAULT : 0; } -asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) +asmlinkage long wrap_sys_shmat(int shmid, char *shmaddr, int shmflg) { unsigned long raddr; return do_shmat(shmid,shmaddr,shmflg,&raddr) ?: (long)raddr; } -asmlinkage long sys_time64(long __user * tloc) +asmlinkage long sys_time64(long * tloc) { struct timeval now; int i; diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index d82da80d8..70a170032 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -302,7 +302,7 @@ void handle_BUG(struct pt_regs *regs) if (__get_user(tmp, f.filename)) f.filename = "unmapped filename"; printk("----------- [cut here ] --------- [please bite here ] ---------\n"); - printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line); + printk("Kernel BUG at %.50s:%d\n", f.filename, f.line); } void out_of_line_bug(void) @@ -356,7 +356,7 @@ void __die(const char * str, struct pt_regs * regs, long err) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); /* Executive summary in case the oops scrolled away */ - printk(KERN_ALERT "RIP "); + printk("RIP "); printk_address(regs->rip); printk(" RSP <%016lx>\n", regs->rsp); } diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 21383547b..c612e4d21 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -39,7 +39,6 @@ SECTIONS __bss_start = .; /* BSS */ .bss : { - *(.bss.page_aligned) *(.bss) } __bss_end = .; @@ -76,8 +75,8 @@ SECTIONS . = ALIGN(8192); /* init_task */ .data.init_task : { *(.data.init_task) } - . = ALIGN(4096); - .data.page_aligned : { *(.data.page_aligned) } + . = ALIGN(4096); + .data.boot_pgt : { *(.data.boot_pgt) } . = ALIGN(4096); /* Init code and data */ __init_begin = .; diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index 2b0d63924..a1f892b1e 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -219,3 +219,6 @@ EXPORT_SYMBOL_GPL(flush_tlb_all); #endif EXPORT_SYMBOL(sys_ioctl); + +EXPORT_SYMBOL(memcpy_toio); +EXPORT_SYMBOL(memcpy_fromio); diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 32b206440..f09cbc34c 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -4,11 +4,9 @@ CFLAGS_csum-partial.o := -funroll-loops -obj-y := io.o - lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk.o clear_page.o copy_page.o bitstr.o + thunk.o io.o clear_page.o copy_page.o bitstr.o lib-y += memcpy.o memmove.o memset.o copy_user.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff --git a/arch/x86_64/lib/csum-wrappers.c b/arch/x86_64/lib/csum-wrappers.c index a8e4c189f..b89aca460 100644 --- a/arch/x86_64/lib/csum-wrappers.c +++ b/arch/x86_64/lib/csum-wrappers.c @@ -19,7 +19,7 @@ * src and dst are best aligned to 64bits. */ unsigned int -csum_partial_copy_from_user(const char __user *src, char *dst, +csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int isum, int *errp) { *errp = 0; @@ -33,7 +33,7 @@ csum_partial_copy_from_user(const char __user *src, char *dst, if (unlikely((unsigned long)src & 6)) { while (((unsigned long)src & 6) && len >= 2) { __u16 val16; - *errp = __get_user(val16, (__u16 __user *)src); + *errp = __get_user(val16, (__u16 *)src); if (*errp) return isum; *(__u16 *)dst = val16; @@ -43,7 +43,7 @@ csum_partial_copy_from_user(const char __user *src, char *dst, len -= 2; } } - isum = csum_partial_copy_generic((void *)src,dst,len,isum,errp,NULL); + isum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL); if (likely(*errp == 0)) return isum; } @@ -66,7 +66,7 @@ EXPORT_SYMBOL(csum_partial_copy_from_user); * src and dst are best aligned to 64bits. */ unsigned int -csum_partial_copy_to_user(const char *src, char __user *dst, +csum_partial_copy_to_user(const char *src, char *dst, int len, unsigned int isum, int *errp) { if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) { @@ -78,7 +78,7 @@ csum_partial_copy_to_user(const char *src, char __user *dst, while (((unsigned long)dst & 6) && len >= 2) { __u16 val16 = *(__u16 *)src; isum = add32_with_carry(isum, val16); - *errp = __put_user(val16, (__u16 __user *)dst); + *errp = __put_user(val16, (__u16 *)dst); if (*errp) return isum; src += 2; @@ -88,7 +88,7 @@ csum_partial_copy_to_user(const char *src, char __user *dst, } *errp = 0; - return csum_partial_copy_generic(src, (void *)dst,len,isum,NULL,errp); + return csum_partial_copy_generic(src,dst,len,isum,NULL,errp); } EXPORT_SYMBOL(csum_partial_copy_to_user); diff --git a/arch/x86_64/lib/io.c b/arch/x86_64/lib/io.c index 5950b821d..ca08e3141 100644 --- a/arch/x86_64/lib/io.c +++ b/arch/x86_64/lib/io.c @@ -2,14 +2,12 @@ #include #include -void *__memcpy_toio(unsigned long dst,const void*src,unsigned len) +void *memcpy_toio(void *dst,const void*src,unsigned len) { - return __inline_memcpy((void *) dst,src,len); + return __inline_memcpy(dst,src,len); } -EXPORT_SYMBOL(__memcpy_toio); -void *__memcpy_fromio(void *dst,unsigned long src,unsigned len) +void *memcpy_fromio(void *dst,const void*src,unsigned len) { - return __inline_memcpy(dst,(const void *) src,len); + return __inline_memcpy(dst,src,len); } -EXPORT_SYMBOL(__memcpy_fromio); diff --git a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c index c83825e5c..4a8603efa 100644 --- a/arch/x86_64/lib/usercopy.c +++ b/arch/x86_64/lib/usercopy.c @@ -40,7 +40,7 @@ do { \ } while (0) long -__strncpy_from_user(char *dst, const char __user *src, long count) +__strncpy_from_user(char *dst, const char *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -48,7 +48,7 @@ __strncpy_from_user(char *dst, const char __user *src, long count) } long -strncpy_from_user(char *dst, const char __user *src, long count) +strncpy_from_user(char *dst, const char *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -60,7 +60,7 @@ strncpy_from_user(char *dst, const char __user *src, long count) * Zero Userspace */ -unsigned long __clear_user(void __user *addr, unsigned long size) +unsigned long __clear_user(void *addr, unsigned long size) { long __d0; /* no memory constraint because it doesn't change any memory gcc knows @@ -94,7 +94,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size) } -unsigned long clear_user(void __user *to, unsigned long n) +unsigned long clear_user(void *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) return __clear_user(to, n); @@ -107,7 +107,7 @@ unsigned long clear_user(void __user *to, unsigned long n) * Return 0 on exception, a value greater than N if too long */ -long strnlen_user(const char __user *s, long n) +long strnlen_user(const char *s, long n) { long res = 0; char c; @@ -127,7 +127,7 @@ long strnlen_user(const char __user *s, long n) } } -long strlen_user(const char __user *s) +long strlen_user(const char *s) { long res = 0; char c; @@ -142,10 +142,10 @@ long strlen_user(const char __user *s) } } -unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) +unsigned long copy_in_user(void *to, const void *from, unsigned len) { if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { - return copy_user_generic((void *)to, (void *)from, len); + return copy_user_generic(to, from, len); } return len; } diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index fa8cc3648..80266166a 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -374,7 +374,7 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size) __flush_tlb_all(); } -static inline int page_is_ram (unsigned long pagenr) +int page_is_ram (unsigned long pagenr) { int i; @@ -512,7 +512,9 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) /* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_DISCONTIGMEM int nid = phys_to_nid(phys); - reserve_bootmem_node(NODE_DATA(nid), phys, len); + if (phys < HIGH_MEMORY && nid) + panic("reserve of %lx at node %d", phys, nid); + reserve_bootmem_node(NODE_DATA(nid), phys, len); #else reserve_bootmem(phys, len); #endif diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index 0cc4a612f..8d1cb38a0 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -158,7 +158,6 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag area = get_vm_area(size, VM_IOREMAP); if (!area) return NULL; - area->phys_addr = phys_addr; addr = area->addr; if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { vunmap(addr); diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c index 550770815..00ced1d84 100644 --- a/arch/x86_64/mm/pageattr.c +++ b/arch/x86_64/mm/pageattr.c @@ -32,8 +32,7 @@ static inline pte_t *lookup_address(unsigned long address) return pte; } -static struct page *split_large_page(unsigned long address, pgprot_t prot, - pgprot_t ref_prot) +static struct page *split_large_page(unsigned long address, pgprot_t prot) { int i; unsigned long addr; @@ -46,7 +45,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, pbase = (pte_t *)page_address(base); for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) { pbase[i] = pfn_pte(addr >> PAGE_SHIFT, - addr == address ? prot : ref_prot); + addr == address ? prot : PAGE_KERNEL); } return base; } @@ -96,7 +95,7 @@ static inline void save_page(unsigned long address, struct page *fpage) * No more special protections in this 2/4MB area - revert to a * large page again. */ -static void revert_page(unsigned long address, pgprot_t ref_prot) +static void revert_page(struct page *kpte_page, unsigned long address) { pgd_t *pgd; pmd_t *pmd; @@ -105,14 +104,12 @@ static void revert_page(unsigned long address, pgprot_t ref_prot) pgd = pgd_offset_k(address); pmd = pmd_offset(pgd, address); BUG_ON(pmd_val(*pmd) & _PAGE_PSE); - pgprot_val(ref_prot) |= _PAGE_PSE; - large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot); + large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, PAGE_KERNEL_LARGE); set_pte((pte_t *)pmd, large_pte); } static int -__change_page_attr(unsigned long address, struct page *page, pgprot_t prot, - pgprot_t ref_prot) +__change_page_attr(unsigned long address, struct page *page, pgprot_t prot) { pte_t *kpte; struct page *kpte_page; @@ -122,29 +119,29 @@ __change_page_attr(unsigned long address, struct page *page, pgprot_t prot, if (!kpte) return 0; kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); kpte_flags = pte_val(*kpte); - if (pgprot_val(prot) != pgprot_val(ref_prot)) { + if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { if ((kpte_flags & _PAGE_PSE) == 0) { pte_t old = *kpte; - pte_t standard = mk_pte(page, ref_prot); + pte_t standard = mk_pte(page, PAGE_KERNEL); set_pte(kpte, mk_pte(page, prot)); if (pte_same(old,standard)) get_page(kpte_page); } else { - struct page *split = split_large_page(address, prot, ref_prot); + struct page *split = split_large_page(address, prot); if (!split) return -ENOMEM; get_page(kpte_page); - set_pte(kpte,mk_pte(split, ref_prot)); + set_pte(kpte,mk_pte(split, PAGE_KERNEL)); } } else if ((kpte_flags & _PAGE_PSE) == 0) { - set_pte(kpte, mk_pte(page, ref_prot)); + set_pte(kpte, mk_pte(page, PAGE_KERNEL)); __put_page(kpte_page); } if (page_count(kpte_page) == 1) { save_page(address, kpte_page); - revert_page(address, ref_prot); + revert_page(kpte_page, address); } return 0; } @@ -170,17 +167,13 @@ int change_page_attr(struct page *page, int numpages, pgprot_t prot) down_write(&init_mm.mmap_sem); for (i = 0; i < numpages; !err && i++, page++) { unsigned long address = (unsigned long)page_address(page); - err = __change_page_attr(address, page, prot, PAGE_KERNEL); + err = __change_page_attr(address, page, prot); if (err) break; - /* Handle kernel mapping too which aliases part of the - * lowmem */ - /* Disabled right now. Fixme */ - if (0 && page_to_phys(page) < KERNEL_TEXT_SIZE) { - unsigned long addr2; - addr2 = __START_KERNEL_map + page_to_phys(page); - err = __change_page_attr(addr2, page, prot, - PAGE_KERNEL_EXECUTABLE); + /* Handle kernel mapping too which aliases part of the lowmem */ + if (page_to_phys(page) < KERNEL_TEXT_SIZE) { + unsigned long addr2 = __START_KERNEL_map + page_to_phys(page); + err = __change_page_attr(addr2, page, prot); } } up_write(&init_mm.mmap_sem); diff --git a/configs/kernel-2.6.6-1.422-vs1.9.1-ckrm-E13 b/configs/kernel-2.6.6-1.422-vs1.9.1-ckrm-E13 new file mode 100644 index 000000000..55ca63656 --- /dev/null +++ b/configs/kernel-2.6.6-1.422-vs1.9.1-ckrm-E13 @@ -0,0 +1,2415 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y + +# +# Class Based Kernel Resource Management +# +CONFIG_CKRM=y +CONFIG_RCFS_FS=y +CONFIG_CKRM_TYPE_TASKCLASS=y +CONFIG_CKRM_RES_NUMTASKS=y +CONFIG_CKRM_TYPE_SOCKETCLASS=y +CONFIG_CKRM_RES_LISTENAQ=m +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_DELAY_ACCT=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +CONFIG_X86_LONGHAUL=y + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +# CONFIG_SCSI_SATA_SX4 is not set +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_ACCEPT_QUEUES=y + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +# CONFIG_NE2000 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DRV_LOOP=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +# CONFIG_SENSORS_MAX1619 is not set +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB=y +CONFIG_DVB_CORE=m + +# +# Supported Frontend Modules +# +CONFIG_DVB_TWINHAN_DST=m +CONFIG_DVB_STV0299=m +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_ALPS_TDLB7 is not set +CONFIG_DVB_ALPS_TDMB7=m +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_GRUNDIG_29504_491=m +CONFIG_DVB_GRUNDIG_29504_401=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +# CONFIG_DVB_TDA1004X is not set +CONFIG_DVB_NXT6000=m + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_RIVA=m +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +# CONFIG_USB_EGALAX is not set +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +CONFIG_USB_CYTHERM=m +# CONFIG_USB_PHIDGETSERVO is not set +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +# CONFIG_REISERFS_FS_XATTR is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +CONFIG_RELAYFS_FS=y +CONFIG_KLOG_CHANNEL=y +CONFIG_KLOG_CHANNEL_AUTOENABLE=y +CONFIG_KLOG_CHANNEL_SHIFT=21 + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.6-i586-smp.config b/configs/kernel-2.6.6-i586-smp.config new file mode 100644 index 000000000..f3dd73142 --- /dev/null +++ b/configs/kernel-2.6.6-i586-smp.config @@ -0,0 +1,2361 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +# CONFIG_X86_4G is not set +# CONFIG_X86_SWITCH_PAGETABLES is not set +# CONFIG_X86_4G_VM_LAYOUT is not set +# CONFIG_X86_UACCESS_INDIRECT is not set +# CONFIG_X86_HIGH_ENTRY is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_X86_MCE_P4THERMAL=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +# CONFIG_IRQBALANCE is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_USE_VECTOR=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_HOTPLUG_PCI_IBM=m +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +# CONFIG_TYPHOON is not set +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.6-i586.config b/configs/kernel-2.6.6-i586.config new file mode 100644 index 000000000..9b0f25868 --- /dev/null +++ b/configs/kernel-2.6.6-i586.config @@ -0,0 +1,2378 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +# CONFIG_X86_4G is not set +# CONFIG_X86_SWITCH_PAGETABLES is not set +# CONFIG_X86_4G_VM_LAYOUT is not set +# CONFIG_X86_UACCESS_INDIRECT is not set +# CONFIG_X86_HIGH_ENTRY is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_TOSHIBA=m +CONFIG_I8K=m +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +# CONFIG_TYPHOON is not set +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DRV_LOOP=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.6-i686-planetlab.config b/configs/kernel-2.6.6-i686-planetlab.config new file mode 100644 index 000000000..be78e5605 --- /dev/null +++ b/configs/kernel-2.6.6-i686-planetlab.config @@ -0,0 +1,1126 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y + +# +# Class Based Kernel Resource Management +# +# CONFIG_CKRM is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +# CONFIG_DELAY_ACCT is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +# CONFIG_HPET_EMULATE_RTC is not set +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +# CONFIG_PM is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +# CONFIG_ACPI is not set +CONFIG_ACPI_BOOT=y + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_RAID6 is not set +# CONFIG_MD_MULTIPATH is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_CRYPT is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_ACCEPT_QUEUES is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_TUX is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_CRASH is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=y +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I8XX_TCO is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set + +# +# ISA-based Watchdog Cards +# +# CONFIG_PCWATCHDOG is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_HANGCHECK_TIMER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# +# CONFIG_IBM_ASM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set +CONFIG_VIDEO_SELECT=y + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +# CONFIG_PROC_SECURE is not set +CONFIG_VSERVER_HARDCPU=y +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.6-i686-smp.config b/configs/kernel-2.6.6-i686-smp.config new file mode 100644 index 000000000..62cca9891 --- /dev/null +++ b/configs/kernel-2.6.6-i686-smp.config @@ -0,0 +1,2364 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +# CONFIG_X86_PC is not set +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +CONFIG_X86_GENERICARCH=y +# CONFIG_X86_ES7000 is not set +CONFIG_X86_CYCLONE_TIMER=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_SMP=y +CONFIG_NR_CPUS=32 +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_X86_MCE_P4THERMAL=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +# CONFIG_HIGHMEM4G is not set +CONFIG_HIGHMEM64G=y +CONFIG_HIGHMEM=y +CONFIG_X86_PAE=y +# CONFIG_NUMA is not set +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +# CONFIG_IRQBALANCE is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_USE_VECTOR=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_HOTPLUG_PCI_IBM=m +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.6-i686.config b/configs/kernel-2.6.6-i686.config new file mode 100644 index 000000000..b7db2faad --- /dev/null +++ b/configs/kernel-2.6.6-i686.config @@ -0,0 +1,2379 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DRV_LOOP=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Linux VServer +# +CONFIG_VSERVER_LEGACY=y +CONFIG_PROC_SECURE=y +# CONFIG_VSERVER_HARDCPU is not set +# CONFIG_INOXID_NONE is not set +# CONFIG_INOXID_GID16 is not set +CONFIG_INOXID_GID24=y +# CONFIG_INOXID_GID32 is not set +# CONFIG_INOXID_MAGIC is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_STD_RESOURCES=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.7-i586-smp.config b/configs/kernel-2.6.7-i586-smp.config new file mode 100644 index 000000000..c1d4cfab8 --- /dev/null +++ b/configs/kernel-2.6.7-i586-smp.config @@ -0,0 +1,2399 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +# CONFIG_X86_4G is not set +# CONFIG_X86_SWITCH_PAGETABLES is not set +# CONFIG_X86_4G_VM_LAYOUT is not set +# CONFIG_X86_UACCESS_INDIRECT is not set +# CONFIG_X86_HIGH_ENTRY is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_X86_MCE_P4THERMAL=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +# CONFIG_IRQBALANCE is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_USE_VECTOR=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_HOTPLUG_PCI_IBM=m +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +# CONFIG_TYPHOON is not set +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB=y +CONFIG_DVB_CORE=m + +# +# Supported Frontend Modules +# +CONFIG_DVB_TWINHAN_DST=m +CONFIG_DVB_STV0299=m +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_ALPS_TDLB7 is not set +CONFIG_DVB_ALPS_TDMB7=m +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_GRUNDIG_29504_491=m +CONFIG_DVB_GRUNDIG_29504_401=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +# CONFIG_DVB_TDA1004X is not set +CONFIG_DVB_NXT6000=m + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA_I2C is not set +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_RW_DETECT=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.7-i586.config b/configs/kernel-2.6.7-i586.config new file mode 100644 index 000000000..9c0db66a6 --- /dev/null +++ b/configs/kernel-2.6.7-i586.config @@ -0,0 +1,2416 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +CONFIG_M586=y +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +# CONFIG_X86_4G is not set +# CONFIG_X86_SWITCH_PAGETABLES is not set +# CONFIG_X86_4G_VM_LAYOUT is not set +# CONFIG_X86_UACCESS_INDIRECT is not set +# CONFIG_X86_HIGH_ENTRY is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_TOSHIBA=m +CONFIG_I8K=m +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +# CONFIG_TYPHOON is not set +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DRV_LOOP=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB=y +CONFIG_DVB_CORE=m + +# +# Supported Frontend Modules +# +CONFIG_DVB_TWINHAN_DST=m +CONFIG_DVB_STV0299=m +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_ALPS_TDLB7 is not set +CONFIG_DVB_ALPS_TDMB7=m +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_GRUNDIG_29504_491=m +CONFIG_DVB_GRUNDIG_29504_401=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +# CONFIG_DVB_TDA1004X is not set +CONFIG_DVB_NXT6000=m + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA_I2C is not set +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_RW_DETECT=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_BIOS_REBOOT=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.7-i686-smp.config b/configs/kernel-2.6.7-i686-smp.config new file mode 100644 index 000000000..9cf67ead7 --- /dev/null +++ b/configs/kernel-2.6.7-i686-smp.config @@ -0,0 +1,2402 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +# CONFIG_X86_PC is not set +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +CONFIG_X86_GENERICARCH=y +# CONFIG_X86_ES7000 is not set +CONFIG_X86_CYCLONE_TIMER=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_SMP=y +CONFIG_NR_CPUS=32 +CONFIG_SCHED_SMT=y +# CONFIG_PREEMPT is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_X86_MCE_P4THERMAL=y +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +# CONFIG_HIGHMEM4G is not set +CONFIG_HIGHMEM64G=y +CONFIG_HIGHMEM=y +CONFIG_X86_PAE=y +# CONFIG_NUMA is not set +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +# CONFIG_IRQBALANCE is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_USE_VECTOR=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_HOTPLUG_PCI_IBM=m +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +CONFIG_STALDRV=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB=y +CONFIG_DVB_CORE=m + +# +# Supported Frontend Modules +# +CONFIG_DVB_TWINHAN_DST=m +CONFIG_DVB_STV0299=m +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_ALPS_TDLB7 is not set +CONFIG_DVB_ALPS_TDMB7=m +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_GRUNDIG_29504_491=m +CONFIG_DVB_GRUNDIG_29504_401=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +# CONFIG_DVB_TDA1004X is not set +CONFIG_DVB_NXT6000=m + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA_I2C is not set +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_RW_DETECT=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_PC=y diff --git a/configs/kernel-2.6.7-i686.config b/configs/kernel-2.6.7-i686.config new file mode 100644 index 000000000..7445bef55 --- /dev/null +++ b/configs/kernel-2.6.7-i686.config @@ -0,0 +1,2417 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_SYSCTL=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Processor type and features +# +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_GOOD_APIC=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_4G=y +CONFIG_X86_SWITCH_PAGETABLES=y +CONFIG_X86_4G_VM_LAYOUT=y +CONFIG_X86_UACCESS_INDIRECT=y +CONFIG_X86_HIGH_ENTRY=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_X86_UP_APIC is not set +CONFIG_X86_TSC=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCE_NONFATAL is not set +CONFIG_TOSHIBA=m +CONFIG_I8K=m +CONFIG_MICROCODE=m +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m + +# +# Firmware Drivers +# +CONFIG_EDD=m +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +# CONFIG_MATH_EMULATION is not set +CONFIG_MTRR=y +# CONFIG_EFI is not set +CONFIG_REGPARM=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_PM_DISK is not set + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI=y +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_ASUS=m +CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_EC=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +CONFIG_X86_PM_TIMER=y + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +CONFIG_APM_RTC_IS_GMT=y +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_TABLE=y + +# +# CPUFreq processor drivers +# +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=y +CONFIG_X86_POWERNOW_K8=m +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_CENTRINO=y +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI=y +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_P4_CLOCKMOD=m +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_NAMES is not set +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_YENTA=m +CONFIG_CARDBUS=y +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_TCIC=m +CONFIG_PCMCIA_PROBE=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_COMPAQ=m +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE=y +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PNC2000 is not set +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_NETSC520=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_ELAN_104NC=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICH2ROM=m +CONFIG_MTD_SCB2_FLASH=m +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_DILNETPC is not set +CONFIG_MTD_L440GX=m +CONFIG_MTD_PCI=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +# CONFIG_MTD_DOC2001 is not set +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NAND_IDS=m + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +CONFIG_PARPORT_SERIAL=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Plug and Play support +# +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_CARMEL=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_INITRD=y +CONFIG_LBD=y + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPNP=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_RZ1000=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_ADMA=y +CONFIG_BLK_DEV_AEC62XX=y +CONFIG_BLK_DEV_ALI15X3=y +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=y +CONFIG_BLK_DEV_ATIIXP=y +CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_TRIFLEX=y +CONFIG_BLK_DEV_CY82C693=y +CONFIG_BLK_DEV_CS5520=y +CONFIG_BLK_DEV_CS5530=y +CONFIG_BLK_DEV_HPT34X=y +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_SC1200 is not set +CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_NS87415 is not set +CONFIG_BLK_DEV_PDC202XX_OLD=y +# CONFIG_PDC202XX_BURST is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +CONFIG_PDC202XX_FORCE=y +CONFIG_BLK_DEV_SVWKS=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_BLK_DEV_SIS5513=y +CONFIG_BLK_DEV_SLC90E66=y +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m + +# +# SCSI low-level drivers +# +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +# CONFIG_SCSI_7000FASST is not set +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=4 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_MEGARAID=m +CONFIG_SCSI_SATA=y +CONFIG_SCSI_SATA_SVW=m +CONFIG_SCSI_ATA_PIIX=m +CONFIG_SCSI_SATA_PROMISE=m +CONFIG_SCSI_SATA_SX4=m +CONFIG_SCSI_SATA_SIL=m +CONFIG_SCSI_SATA_SIS=m +CONFIG_SCSI_SATA_VIA=m +CONFIG_SCSI_SATA_VITESSE=m +CONFIG_SCSI_BUSLOGIC=m +# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_QLOGIC_ISP=m +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA21XX=m +CONFIG_SCSI_QLA22XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +CONFIG_FUSION=m +CONFIG_FUSION_MAX_SGE=40 +# CONFIG_FUSION_ISENSE is not set +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_OUI_DB=y +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_ETH1394 is not set +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_LOCAL=y +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_RAW=m + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=y + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_LTPC=m +CONFIG_COPS=m +CONFIG_COPS_DAYNA=y +CONFIG_COPS_TANGENT=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_NSC_FIR=m +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_BCSP_TXCRC=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_TUX=m + +# +# TUX options +# +CONFIG_TUX_EXTCGI=y +# CONFIG_TUX_EXTENDED_LOG is not set +# CONFIG_TUX_DEBUG is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ETHERTAP=m +CONFIG_NET_SB1000=m + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_EL1=m +CONFIG_EL2=m +CONFIG_ELPLUS=m +CONFIG_EL16=m +CONFIG_EL3=m +CONFIG_3C515=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_LANCE=m +CONFIG_NET_VENDOR_SMC=y +CONFIG_WD80x3=m +CONFIG_ULTRA=m +CONFIG_SMC9194=m +CONFIG_NET_VENDOR_RACAL=y +# CONFIG_NI5010 is not set +CONFIG_NI52=m +CONFIG_NI65=m + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +# CONFIG_AT1700 is not set +CONFIG_DEPCA=m +CONFIG_HP100=m +# CONFIG_NET_ISA is not set +CONFIG_NE2000=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD8111E_NAPI=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADAPTEC_STARFIRE_NAPI=y +CONFIG_AC3200=m +CONFIG_APRICOT=m +CONFIG_B44=m +CONFIG_FORCEDETH=m +CONFIG_CS89x0=m +CONFIG_DGRS=m +CONFIG_EEPRO100=m +# CONFIG_EEPRO100_PIO is not set +CONFIG_E100=m +CONFIG_E100_NAPI=y +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_NET_POCKET=y +CONFIG_ATP=m +CONFIG_DE600=m +CONFIG_DE620=m + +# +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +CONFIG_E1000_NAPI=y +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +CONFIG_SK98LIN=m +CONFIG_TIGON3=m + +# +# Ethernet (10000 Mbit) +# +CONFIG_IXGB=m +CONFIG_IXGB_NAPI=y +CONFIG_S2IO=m +CONFIG_S2IO_NAPI=y + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_AIRO=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_WL3501=m + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_FDDI=y +# CONFIG_DEFXX is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set +CONFIG_NET_FC=y +# CONFIG_SHAPER is not set +CONFIG_NETCONSOLE=m + +# +# ISDN subsystem +# +CONFIG_ISDN=m + +# +# Old ISDN4Linux +# +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +# CONFIG_ISDN_PPP_BSDCOMP is not set +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y + +# +# ISDN feature submodules +# +CONFIG_ISDN_DRV_LOOP=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +CONFIG_HISAX_NO_SENDCOMPLETE=y +CONFIG_HISAX_NO_LLC=y +CONFIG_HISAX_NO_KEYPAD=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_TPAM=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y + +# +# CAPI subsystem +# +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# + +# +# Active AVM cards +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m + +# +# Active Eicon DIVA Server cards +# +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +CONFIG_GAMEPORT=m +CONFIG_SOUND_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_VORTEX=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_CS461x=m +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_ATIXL=y +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDDLER=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +# CONFIG_INPUT_JOYDUMP is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_MULTIPORT=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_CRASH=m +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_TIPAR=m +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_SC520_WDT=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_I8XX_TCO=m +CONFIG_SC1200_WDT=m +# CONFIG_SCx200_WDT is not set +# CONFIG_60XX_WDT is not set +CONFIG_CPU5_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_MACHZ_WDT=m + +# +# ISA-based Watchdog Cards +# +CONFIG_PCWATCHDOG=m +# CONFIG_MIXCOMWD is not set +CONFIG_WDT=m +# CONFIG_WDT_501 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=m +CONFIG_NVRAM=m +CONFIG_RTC=y +CONFIG_DTLK=m +CONFIG_R3964=m +# CONFIG_APPLICOM is not set +CONFIG_SONYPI=m + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_ALI=y +CONFIG_AGP_ATI=y +CONFIG_AGP_AMD=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_INTEL_MCH=y +CONFIG_AGP_NVIDIA=y +CONFIG_AGP_SIS=y +CONFIG_AGP_SWORKS=y +CONFIG_AGP_VIA=y +CONFIG_AGP_EFFICEON=y +CONFIG_DRM=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_GAMMA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_MWAVE=m +# CONFIG_RAW_DRIVER is not set +# CONFIG_HPET is not set +CONFIG_HANGCHECK_TIMER=m + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_ISA=m +CONFIG_I2C_NFORCE2=m +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PIIX4=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_SCx200_ACB is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m + +# +# Other I2C Chip support +# +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_RTC8564=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Misc devices +# +CONFIG_IBM_ASM=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m + +# +# Radio Adapters +# +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m + +# +# Digital Video Broadcasting Devices +# +CONFIG_DVB=y +CONFIG_DVB_CORE=m + +# +# Supported Frontend Modules +# +CONFIG_DVB_TWINHAN_DST=m +CONFIG_DVB_STV0299=m +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_ALPS_TDLB7 is not set +CONFIG_DVB_ALPS_TDMB7=m +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_GRUNDIG_29504_491=m +CONFIG_DVB_GRUNDIG_29504_401=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +# CONFIG_DVB_TDA1004X is not set +CONFIG_DVB_NXT6000=m + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_VIDEOBUF=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR=m + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_VESA=y +CONFIG_VIDEO_SELECT=y +CONFIG_FB_HGA=m +CONFIG_FB_HGA_ACCEL=y +CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA_I2C is not set +CONFIG_FB_I810=m +CONFIG_FB_I810_GTF=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +CONFIG_FB_3DFX_ACCEL=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_TRIDENT_ACCEL=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_MDA_CONSOLE=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +# CONFIG_SND_SERIAL_U16550 is not set +CONFIG_SND_MPU401=m + +# +# ISA devices +# +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_ES968=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_SB8=m +CONFIG_SND_SB16=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB16_CSP=y +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_ALS100=m +CONFIG_SND_AZT2320=m +CONFIG_SND_CMI8330=m +CONFIG_SND_DT019X=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SSCAPE=m + +# +# PCI devices +# +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS4281=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_KORG1212=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_HDSP=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_ALS4000=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VX222=m + +# +# ALSA USB devices +# +CONFIG_SND_USB_AUDIO=m + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_VXP440 is not set +CONFIG_SND_PDAUDIOCF=m + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +CONFIG_USB_MIDI=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_RW_DETECT=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_HID_FF=y +CONFIG_HID_PID=y +CONFIG_LOGITECH_FF=y +CONFIG_THRUSTMASTER_FF=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_AIPTEK=m +CONFIG_USB_WACOM=m +CONFIG_USB_KBTAB=m +CONFIG_USB_POWERMATE=m +CONFIG_USB_MTOUCH=m +CONFIG_USB_EGALAX=m +CONFIG_USB_XPAD=m +CONFIG_USB_ATI_REMOTE=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# +CONFIG_USB_DABUSB=m +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_W9968CF=m + +# +# USB Network adaptors +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +# CONFIG_USB_EMI26 is not set +CONFIG_USB_TIGL=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_LED=m +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_TEST=m + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_SMALLDOS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_MLS is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_X86_BIOS_REBOOT=y +CONFIG_PC=y diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index e0a313f57..028da158a 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -79,7 +79,6 @@ acpi_ds_execute_arguments ( acpi_status status; union acpi_parse_object *op; struct acpi_walk_state *walk_state; - union acpi_parse_object *arg; ACPI_FUNCTION_TRACE ("ds_execute_arguments"); @@ -126,9 +125,7 @@ acpi_ds_execute_arguments ( /* Get and init the Op created above */ - arg = op->common.value.arg; op->common.node = node; - arg->common.node = node; acpi_ps_delete_parse_tree (op); /* Evaluate the deferred arguments */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 56bb801e2..bc9e24904 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -600,7 +600,7 @@ acpi_ec_add ( acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); - kfree(ec_ecdt); +// kfree(ec_ecdt); } /* Get GPE bit assignment (EC events). */ diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index e33b5357e..e46d01b9b 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -683,7 +682,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) opcode.opcode = OPCODE_GET_PROM; opcode.pad = 0; - prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), DMA_FROM_DEVICE); + prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); @@ -695,7 +694,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE); + fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); @@ -1004,7 +1003,7 @@ fore200e_tx_irq(struct fore200e* fore200e) /* remove DMA mapping */ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, - DMA_TO_DEVICE); + FORE200E_DMA_TODEVICE); vc_map = entry->vc_map; @@ -1229,12 +1228,12 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); /* Make device DMA transfer visible to CPU. */ - fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); + fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); /* Now let the device get at it again. */ - fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); + fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); } DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); @@ -1808,7 +1807,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) entry->data = tx_copy ? data : NULL; tpd = entry->tpd; - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, DMA_TO_DEVICE); + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, FORE200E_DMA_TODEVICE); tpd->tsd[ 0 ].length = tx_len; FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); @@ -1882,7 +1881,7 @@ fore200e_getstats(struct fore200e* fore200e) } stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, - sizeof(struct stats), DMA_FROM_DEVICE); + sizeof(struct stats), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1899,7 +1898,7 @@ fore200e_getstats(struct fore200e* fore200e) *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE); + fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); @@ -1911,7 +1910,7 @@ fore200e_getstats(struct fore200e* fore200e) static int -fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, int optlen) +fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) { /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */ @@ -1923,7 +1922,7 @@ fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void __user *op static int -fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, int optlen) +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) { /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */ @@ -1944,7 +1943,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) int ok; u32 oc3_regs_dma_addr; - oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), DMA_FROM_DEVICE); + oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1963,7 +1962,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), DMA_FROM_DEVICE); + fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); @@ -2059,7 +2058,7 @@ fore200e_swap(unsigned int in) static int -fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) +fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg) { struct sonet_stats tmp; @@ -2088,7 +2087,7 @@ fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) static int -fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void __user * arg) +fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) { struct fore200e* fore200e = FORE200E_DEV(dev); @@ -2097,19 +2096,19 @@ fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void __user * arg) switch (cmd) { case SONET_GETSTAT: - return fore200e_fetch_stats(fore200e, (struct sonet_stats __user *)arg); + return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); case SONET_GETDIAG: - return put_user(0, (int __user *)arg) ? -EFAULT : 0; + return put_user(0, (int*)arg) ? -EFAULT : 0; case ATM_SETLOOP: return fore200e_setloop(fore200e, (int)(unsigned long)arg); case ATM_GETLOOP: - return put_user(fore200e->loop_mode, (int __user *)arg) ? -EFAULT : 0; + return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int __user *)arg) ? -EFAULT : 0; + return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? -EFAULT : 0; } return -ENOSYS; /* not implemented */ @@ -2258,7 +2257,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e) /* allocate the receive buffer body */ if (fore200e_chunk_alloc(fore200e, &buffer[ i ].data, size, fore200e->bus->buffer_alignment, - DMA_FROM_DEVICE) < 0) { + FORE200E_DMA_FROMDEVICE) < 0) { while (i > 0) fore200e_chunk_free(fore200e, &buffer[ --i ].data); diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index aca550b66..6a9d2ee97 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -556,7 +556,7 @@ typedef struct host_bsq_entry { typedef struct host_cmdq_entry { struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */ - enum status *status; /* addr of host resident status */ + enum status* status; /* addr of host resident status */ } host_cmdq_entry_t; @@ -668,7 +668,7 @@ typedef struct bs_spec { typedef struct init_block { enum opcode opcode; /* initialize command */ - enum status status; /* related status word */ + enum status status; /* related status word */ u32 receive_threshold; /* not used */ u32 num_connect; /* ATM connections */ u32 cmd_queue_len; /* length of command queue */ @@ -827,6 +827,28 @@ typedef struct fore200e_bus { int (*proc_read)(struct fore200e*, char*); } fore200e_bus_t; + +#if defined(CONFIG_ATM_FORE200E_SBA) +# if defined(CONFIG_ATM_FORE200E_PCA) +# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE +# else +# define FORE200E_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE SBUS_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE SBUS_DMA_FROMDEVICE +# endif +#else +# ifndef CONFIG_ATM_FORE200E_PCA +# warning compiling the fore200e driver without any hardware support enabled! +# include +# endif +# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE +#endif + + /* vc mapping */ typedef struct fore200e_vc_map { diff --git a/drivers/base/node.c b/drivers/base/node.c index b5aa9dc6c..7508df373 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -21,10 +21,9 @@ static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) cpumask_t mask = node_dev->cpumap; int len; - /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */ - BUILD_BUG_ON(NR_CPUS/4 > PAGE_SIZE/2); - - len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask); + /* FIXME - someone should pass us a buffer size (count) or + * use seq_file or something to avoid buffer overrun risk. */ + len = cpumask_scnprintf(buf, 99 /* XXX FIXME */, mask); len += sprintf(buf + len, "\n"); return len; } diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 56b9ce97c..02a29e86c 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -97,8 +97,7 @@ static int DAC960_ioctl(struct inode *inode, struct file *file, struct gendisk *disk = inode->i_bdev->bd_disk; DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; - struct hd_geometry g; - struct hd_geometry __user *loc = (struct hd_geometry __user *)arg; + struct hd_geometry g, *loc = (struct hd_geometry *)arg; if (cmd != HDIO_GETGEO || !loc) return -EINVAL; @@ -6126,6 +6125,9 @@ static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, unsigned long flags; unsigned char Channel, TargetID, LogicalDriveNumber; unsigned short LogicalDeviceNumber; + wait_queue_t __wait; + + init_waitqueue_entry(&__wait, current); spin_lock_irqsave(&Controller->queue_lock, flags); while ((Command = DAC960_AllocateCommand(Controller)) == NULL) @@ -6308,11 +6310,18 @@ static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, .SegmentByteCount = CommandMailbox->ControllerInfo.DataTransferSize; DAC960_ExecuteCommand(Command); + add_wait_queue(&Controller->CommandWaitQueue, &__wait); + set_current_state(TASK_UNINTERRUPTIBLE); + while (Controller->V2.NewControllerInformation->PhysicalScanActive) { DAC960_ExecuteCommand(Command); - sleep_on_timeout(&Controller->CommandWaitQueue, HZ); + schedule_timeout(HZ); + set_current_state(TASK_UNINTERRUPTIBLE); } + current->state = TASK_RUNNING; + remove_wait_queue(&Controller->CommandWaitQueue, &__wait); + DAC960_UserCritical("Discovery Completed\n", Controller); } } @@ -6456,8 +6465,7 @@ static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset, DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command. */ -static int DAC960_ProcWriteUserCommand(struct file *file, - const char __user *Buffer, +static int DAC960_ProcWriteUserCommand(struct file *file, const char *Buffer, unsigned long Count, void *Data) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; @@ -6545,8 +6553,8 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file, return DAC960_ControllerCount; case DAC960_IOCTL_GET_CONTROLLER_INFO: { - DAC960_ControllerInfo_T __user *UserSpaceControllerInfo = - (DAC960_ControllerInfo_T __user *) Argument; + DAC960_ControllerInfo_T *UserSpaceControllerInfo = + (DAC960_ControllerInfo_T *) Argument; DAC960_ControllerInfo_T ControllerInfo; DAC960_Controller_T *Controller; int ControllerNumber; @@ -6576,8 +6584,8 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file, } case DAC960_IOCTL_V1_EXECUTE_COMMAND: { - DAC960_V1_UserCommand_T __user *UserSpaceUserCommand = - (DAC960_V1_UserCommand_T __user *) Argument; + DAC960_V1_UserCommand_T *UserSpaceUserCommand = + (DAC960_V1_UserCommand_T *) Argument; DAC960_V1_UserCommand_T UserCommand; DAC960_Controller_T *Controller; DAC960_Command_T *Command = NULL; @@ -6736,8 +6744,8 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file, } case DAC960_IOCTL_V2_EXECUTE_COMMAND: { - DAC960_V2_UserCommand_T __user *UserSpaceUserCommand = - (DAC960_V2_UserCommand_T __user *) Argument; + DAC960_V2_UserCommand_T *UserSpaceUserCommand = + (DAC960_V2_UserCommand_T *) Argument; DAC960_V2_UserCommand_T UserCommand; DAC960_Controller_T *Controller; DAC960_Command_T *Command = NULL; @@ -6890,8 +6898,8 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file, } case DAC960_IOCTL_V2_GET_HEALTH_STATUS: { - DAC960_V2_GetHealthStatus_T __user *UserSpaceGetHealthStatus = - (DAC960_V2_GetHealthStatus_T __user *) Argument; + DAC960_V2_GetHealthStatus_T *UserSpaceGetHealthStatus = + (DAC960_V2_GetHealthStatus_T *) Argument; DAC960_V2_GetHealthStatus_T GetHealthStatus; DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer; DAC960_Controller_T *Controller; diff --git a/drivers/block/carmel.c b/drivers/block/carmel.c index 38fd6fe42..6a5ed6483 100644 --- a/drivers/block/carmel.c +++ b/drivers/block/carmel.c @@ -413,7 +413,7 @@ static unsigned long carm_major_alloc; static int carm_bdev_ioctl(struct inode *ino, struct file *fil, unsigned int cmd, unsigned long arg) { - void __user *usermem = (void __user *) arg; + void __user *usermem = (void *) arg; struct carm_port *port = ino->i_bdev->bd_disk->private_data; struct hd_geometry geom; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index b42a8d33f..f6f781898 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1157,8 +1157,8 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); int error; int diskinfo[4]; - struct hd_geometry __user *geo = (struct hd_geometry __user *)arg; - ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg; + struct hd_geometry *geo = (struct hd_geometry *)arg; + ida_ioctl_t *io = (ida_ioctl_t*)arg; ida_ioctl_t *my_io; switch(cmd) { @@ -1202,7 +1202,7 @@ out_passthru: return error; case IDAGETCTLRSIG: if (!arg) return -EINVAL; - put_user(host->ctlr_sig, (int __user *)arg); + put_user(host->ctlr_sig, (int*)arg); return 0; case IDAREVALIDATEVOLS: if (iminor(inode) != 0) @@ -1210,7 +1210,7 @@ out_passthru: return revalidate_allvol(host); case IDADRIVERVERSION: if (!arg) return -EINVAL; - put_user(DRIVER_VERSION, (unsigned long __user *)arg); + put_user(DRIVER_VERSION, (unsigned long*)arg); return 0; case IDAGETPCIINFO: { @@ -1221,7 +1221,7 @@ out_passthru: pciinfo.bus = host->pci_dev->bus->number; pciinfo.dev_fn = host->pci_dev->devfn; pciinfo.board_id = host->board_id; - if(copy_to_user((void __user *) arg, &pciinfo, + if(copy_to_user((void *) arg, &pciinfo, sizeof( ida_pci_info_struct))) return -EFAULT; return(0); @@ -1272,7 +1272,7 @@ static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io) cmd_free(h, c, 0); return(error); } - if (copy_from_user(p, io->sg[0].addr, io->sg[0].size)) { + if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) { kfree(p); cmd_free(h, c, 0); return -EFAULT; @@ -1313,7 +1313,7 @@ static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io) cmd_free(h, c, 0); return(error); } - if (copy_from_user(p, io->sg[0].addr, io->sg[0].size)) { + if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) { kfree(p); cmd_free(h, c, 0); return -EFAULT; @@ -1354,7 +1354,7 @@ static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io) case DIAG_PASS_THRU: case SENSE_CONTROLLER_PERFORMANCE: case READ_FLASH_ROM: - if (copy_to_user(io->sg[0].addr, p, io->sg[0].size)) { + if (copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size)) { kfree(p); return -EFAULT; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 70375a056..f1cc33409 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4238,7 +4238,7 @@ int __init floppy_init(void) } disks[dr]->major = FLOPPY_MAJOR; - disks[dr]->first_minor = TOMINOR(dr); + disks[dr]->first_minor = TOMINOR(i); disks[dr]->fops = &floppy_fops; sprintf(disks[dr]->disk_name, "fd%d", dr); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 5baa11da0..e4a8c0dee 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1306,12 +1306,12 @@ static int blk_init_free_list(request_queue_t *q) static int __make_request(request_queue_t *, struct bio *); static elevator_t *chosen_elevator = -#if defined(CONFIG_IOSCHED_AS) +#if defined(CONFIG_IOSCHED_CFQ) + &iosched_cfq; +#elif defined(CONFIG_IOSCHED_AS) &iosched_as; #elif defined(CONFIG_IOSCHED_DEADLINE) &iosched_deadline; -#elif defined(CONFIG_IOSCHED_CFQ) - &iosched_cfq; #elif defined(CONFIG_IOSCHED_NOOP) &elevator_noop; #else diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f1250943c..95ec95cfa 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -308,9 +308,7 @@ lo_read_actor(read_descriptor_t *desc, struct page *page, page->index); desc->error = -EINVAL; } - - flush_dcache_page(p->page); - + desc->count = count - size; desc->written += size; p->offset += size; diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index d73e3ec9f..5ccc106fc 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -212,9 +212,9 @@ MODULE_PARM(drive3, "1-6i"); static int pg_open(struct inode *inode, struct file *file); static int pg_release(struct inode *inode, struct file *file); -static ssize_t pg_read(struct file *filp, char __user *buf, +static ssize_t pg_read(struct file *filp, char *buf, size_t count, loff_t * ppos); -static ssize_t pg_write(struct file *filp, const char __user *buf, +static ssize_t pg_write(struct file *filp, const char *buf, size_t count, loff_t * ppos); static int pg_detect(void); @@ -571,7 +571,7 @@ static int pg_release(struct inode *inode, struct file *file) return 0; } -static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t pg_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) { struct pg *dev = filp->private_data; struct pg_write_hdr hdr; @@ -582,7 +582,7 @@ static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, if (count < hs) return -EINVAL; - if (copy_from_user(&hdr, buf, hs)) + if (copy_from_user((char *) &hdr, buf, hs)) return -EFAULT; if (hdr.magic != PG_MAGIC) @@ -619,7 +619,7 @@ static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, return count; } -static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +static ssize_t pg_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { struct pg *dev = filp->private_data; struct pg_read_hdr hdr; @@ -651,7 +651,7 @@ static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t hdr.duration = (jiffies - dev->start + HZ / 2) / HZ; hdr.scsi = dev->status & 0x0f; - if (copy_to_user(buf, &hdr, hs)) + if (copy_to_user(buf, (char *) &hdr, hs)) return -EFAULT; if (copy > 0) if (copy_to_user(buf + hs, dev->bufptr, copy)) diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 44b12134d..81c4690cf 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -212,9 +212,9 @@ static int pt_open(struct inode *inode, struct file *file); static int pt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int pt_release(struct inode *inode, struct file *file); -static ssize_t pt_read(struct file *filp, char __user *buf, +static ssize_t pt_read(struct file *filp, char *buf, size_t count, loff_t * ppos); -static ssize_t pt_write(struct file *filp, const char __user *buf, +static ssize_t pt_write(struct file *filp, const char *buf, size_t count, loff_t * ppos); static int pt_detect(void); @@ -710,12 +710,12 @@ static int pt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct pt_unit *tape = file->private_data; - struct mtop __user *p = (void __user *)arg; struct mtop mtop; switch (cmd) { case MTIOCTOP: - if (copy_from_user(&mtop, p, sizeof(struct mtop))) + if (copy_from_user((char *) &mtop, (char *) arg, + sizeof (struct mtop))) return -EFAULT; switch (mtop.mt_op) { @@ -764,7 +764,7 @@ pt_release(struct inode *inode, struct file *file) } -static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) +static ssize_t pt_read(struct file *filp, char *buf, size_t count, loff_t * ppos) { struct pt_unit *tape = filp->private_data; struct pi_adapter *pi = tape->pi; @@ -861,7 +861,7 @@ static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t } -static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) +static ssize_t pt_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) { struct pt_unit *tape = filp->private_data; struct pi_adapter *pi = tape->pi; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 82a5f19fd..87b324086 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1063,17 +1063,17 @@ static int ps2esdi_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data; - struct ps2esdi_geometry geom; + struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg; + int err; if (cmd != HDIO_GETGEO) return -EINVAL; - memset(&geom, 0, sizeof(geom)); - geom.heads = p->head; - geom.sectors = p->sect; - geom.cylinders = p->cyl; - geom.start = get_start_sect(inode->i_bdev); - if (copy_to_user((void __user *)arg, &geom, sizeof(geom))) - return -EFAULT; + if ((err = verify_area(VERIFY_WRITE, geometry, sizeof(*geometry)))) + return (err); + put_user(p->head, (char *) &geometry->heads); + put_user(p->sect, (char *) &geometry->sectors); + put_user(p->cyl, (short *) &geometry->cylinders); + put_user(get_start_sect(inode->i_bdev), (long *) &geometry->start); return 0; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index fe8332e34..5566351d4 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -108,21 +108,8 @@ static void make_page_uptodate(struct page *page) struct buffer_head *head = bh; do { - if (!buffer_uptodate(bh)) { + if (!buffer_uptodate(bh)) memset(bh->b_data, 0, bh->b_size); - /* - * akpm: I'm totally undecided about this. The - * buffer has just been magically brought "up to - * date", but nobody should want to be reading - * it anyway, because it hasn't been used for - * anything yet. It is still in a "not read - * from disk yet" state. - * - * But non-uptodate buffers against an uptodate - * page are against the rules. So do it anyway. - */ - set_buffer_uptodate(bh); - } } while ((bh = bh->b_this_page) != head); } else { memset(page_address(page), 0, PAGE_CACHE_SIZE); diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 93ebb681c..cd3bc2d42 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -235,12 +235,12 @@ static int sg_scsi_ioctl(request_queue_t *q, struct gendisk *bd_disk, return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; - if (get_user(opcode, sic->data)) + if (get_user(opcode, (int *)sic->data)) return -EFAULT; bytes = max(in_len, out_len); if (bytes) { - buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER); + buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER | __GFP_NOWARN); if (!buffer) return -ENOMEM; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 2b126d8d2..f7488ae75 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -833,7 +833,7 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned geo.start = get_start_sect(i->i_bdev); geo.cylinders = size / (geo.heads * geo.sectors); - if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) + if (copy_to_user((void *) arg, &geo, sizeof(geo))) return -EFAULT; return 0; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ba134216..dda06e9a6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -498,11 +498,11 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, /* * We don't provide read/write/poll interface for user space. */ -static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) +static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) { return 0; } -static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char __user *data, size_t count) +static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { return 0; } diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 97ab1b33f..83086769f 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -873,7 +873,7 @@ static int aztUpdateToc(void) /* Read the table of contents header, i.e. no. of tracks and start of first * track */ -static int aztGetDiskInfo(void) +static int aztGetDiskInfo() { int limit; unsigned char test; @@ -1167,7 +1167,6 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, struct azt_Toc *tocPtr; struct cdrom_subchnl subchnl; struct cdrom_volctrl volctrl; - void __user *argp = (void __user *)arg; #ifdef AZT_DEBUG printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n", @@ -1231,7 +1230,8 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, #ifdef AZT_DEBUG printk("aztcd ioctl MULTISESSION\n"); #endif - if (copy_from_user(&ms, argp, + if (copy_from_user + (&ms, (void *) arg, sizeof(struct cdrom_multisession))) return -EFAULT; if (ms.addr_format == CDROM_MSF) { @@ -1248,7 +1248,8 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, else return -EINVAL; ms.xa_flag = DiskInfo.xa; - if (copy_to_user(argp, &ms, + if (copy_to_user + ((void *) arg, &ms, sizeof(struct cdrom_multisession))) return -EFAULT; #ifdef AZT_DEBUG @@ -1271,7 +1272,7 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, return 0; } case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - if (copy_from_user(&ti, argp, sizeof ti)) + if (copy_from_user(&ti, (void *) arg, sizeof ti)) return -EFAULT; if (ti.cdti_trk0 < DiskInfo.first || ti.cdti_trk0 > DiskInfo.last @@ -1302,7 +1303,7 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, aztAudioStatus = CDROM_AUDIO_NO_STATUS; } */ - if (copy_from_user(&msf, argp, sizeof msf)) + if (copy_from_user(&msf, (void *) arg, sizeof msf)) return -EFAULT; /* convert to bcd */ azt_bin2bcd(&msf.cdmsf_min0); @@ -1334,11 +1335,11 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, case CDROMREADTOCHDR: /* Read the table of contents header */ tocHdr.cdth_trk0 = DiskInfo.first; tocHdr.cdth_trk1 = DiskInfo.last; - if (copy_to_user(argp, &tocHdr, sizeof tocHdr)) + if (copy_to_user((void *) arg, &tocHdr, sizeof tocHdr)) return -EFAULT; break; case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ - if (copy_from_user(&entry, argp, sizeof entry)) + if (copy_from_user(&entry, (void *) arg, sizeof entry)) return -EFAULT; if ((!aztTocUpToDate) || aztDiskChanged) aztUpdateToc(); @@ -1364,12 +1365,12 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, } else { return -EINVAL; } - if (copy_to_user(argp, &entry, sizeof entry)) + if (copy_to_user((void *) arg, &entry, sizeof entry)) return -EFAULT; break; case CDROMSUBCHNL: /* Get subchannel info */ if (copy_from_user - (&subchnl, argp, sizeof(struct cdrom_subchnl))) + (&subchnl, (void *) arg, sizeof(struct cdrom_subchnl))) return -EFAULT; if (aztGetQChannelInfo(&qInfo) < 0) { #ifdef AZT_DEBUG @@ -1404,14 +1405,16 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, subchnl.cdsc_reladdr.msf.frame = azt_bcd2bin(qInfo.trackTime.frame); } - if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl))) + if (copy_to_user + ((void *) arg, &subchnl, sizeof(struct cdrom_subchnl))) return -EFAULT; break; case CDROMVOLCTRL: /* Volume control * With my Aztech CD268-01A volume control does not work, I can only turn the channels on (any value !=0) or off (value==0). Maybe it works better with your drive */ - if (copy_from_user(&volctrl, argp, sizeof(volctrl))) + if (copy_from_user + (&volctrl, (char *) arg, sizeof(volctrl))) return -EFAULT; azt_Play.start.min = 0x21; azt_Play.start.sec = 0x84; @@ -1454,7 +1457,7 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */ case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */ { - if (copy_from_user(&msf, argp, sizeof msf)) + if (copy_from_user(&msf, (void *) arg, sizeof msf)) return -EFAULT; /* convert to bcd */ azt_bin2bcd(&msf.cdmsf_min0); @@ -1473,11 +1476,16 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, if (DiskInfo.xa) { return -1; /*XA Disks can't be read raw */ } else { - if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) + if (sendAztCmd + (ACMD_PLAY_READ_RAW, + &azt_Play)) return -1; DTEN_LOW; - insb(DATA_PORT, buf, CD_FRAMESIZE_RAW); - if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW)) + insb(DATA_PORT, buf, + CD_FRAMESIZE_RAW); + if (copy_to_user + ((void *) arg, &buf, + CD_FRAMESIZE_RAW)) return -EFAULT; } } else @@ -1486,13 +1494,14 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, return -1; DTEN_LOW; insb(DATA_PORT, buf, CD_FRAMESIZE); - if (copy_to_user(argp, &buf, CD_FRAMESIZE)) + if (copy_to_user + ((void *) arg, &buf, CD_FRAMESIZE)) return -EFAULT; } } break; case CDROMSEEK: /*seek msf address */ - if (copy_from_user(&msf, argp, sizeof msf)) + if (copy_from_user(&msf, (void *) arg, sizeof msf)) return -EFAULT; /* convert to bcd */ azt_bin2bcd(&msf.cdmsf_min0); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index d82006ca7..01867107d 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -651,6 +651,7 @@ int cdrom_get_random_writable(struct cdrom_device_info *cdi, { struct packet_command cgc; char buffer[24]; + struct feature_header *fh; int ret; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); @@ -663,7 +664,14 @@ int cdrom_get_random_writable(struct cdrom_device_info *cdi, if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; - memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); + fh = (struct feature_header *)&buffer[0]; + if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+ + sizeof(struct rwrt_feature_desc))) + memcpy(rfd, &buffer[sizeof(struct feature_header)], + sizeof (*rfd)); + else + memset(rfd, 0, sizeof(*rfd)); + return 0; } @@ -671,24 +679,28 @@ int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) { struct packet_command cgc; char buffer[16]; + struct feature_header *fh; __u16 *feature_code; int ret; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); - cgc.cmd[0] = GPCMD_GET_CONFIGURATION; - cgc.cmd[3] = CDF_HWDM; - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ + cgc.cmd[3] = CDF_HWDM; /* often 0x0024 */ + cgc.cmd[8] = sizeof(buffer); /* often 0x10 */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; - feature_code = (__u16 *) &buffer[sizeof(struct feature_header)]; - if (be16_to_cpu(*feature_code) == CDF_HWDM) - return 0; - - return 1; + fh = (struct feature_header *)&buffer[0]; + ret = 1; + if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+8)) { + feature_code = (__u16 *)&buffer[sizeof(struct feature_header)]; + if (CDF_HWDM == be16_to_cpu(*feature_code)) + ret = 0; + } + return ret; } diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 69122d880..341348f2c 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -373,7 +373,7 @@ config AU1000_UART config SGI_L1_SERIAL bool "SGI Altix L1 serial support" - depends on SERIAL_NONSTANDARD && IA64 + depends on SERIAL_NONSTANDARD && IA64 && DISCONTIGMEM help If you have an SGI Altix and you want to use the serial port connected to the system controller (you want this!), say Y. @@ -482,6 +482,8 @@ config LEGACY_PTYS security. This option enables these legacy devices; on most systems, it is safe to say N. +config CRASH + tristate "Crash Utility memory driver" config LEGACY_PTY_COUNT int "Maximum number of legacy PTY in use" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 2a42fd3c7..53439fc47 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,6 +82,8 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o +obj-$(CONFIG_CRASH) += crash.o + # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c diff --git a/drivers/char/crash.c b/drivers/char/crash.c new file mode 100644 index 000000000..43cc96f38 --- /dev/null +++ b/drivers/char/crash.c @@ -0,0 +1,129 @@ +/* + * linux/drivers/char/crash.c + * + * Copyright (C) 2004 Dave Anderson + * Copyright (C) 2004 Red Hat, Inc. + */ + +/****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CRASH_VERSION "1.0" + +/* + * These are the file operation functions that allow crash utility + * access to physical memory. + */ + +static loff_t +crash_llseek(struct file * file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + +/* + * Determine the page address for an address offset value, + * get a virtual address for it, and copy it out. + * Accesses must fit within a page. + */ +static ssize_t +crash_read(struct file *file, char *buf, size_t count, loff_t *poff) +{ + void *vaddr; + struct page *page; + u64 offset; + ssize_t read; + + offset = *poff; + if (offset >> PAGE_SHIFT != (offset+count-1) >> PAGE_SHIFT) + return -EINVAL; + + vaddr = map_virtual(offset, &page); + if (!vaddr) + return -EFAULT; + + if (copy_to_user(buf, vaddr, count)) { + unmap_virtual(page); + return -EFAULT; + } + unmap_virtual(page); + + read = count; + *poff += read; + return read; +} + +static struct file_operations crash_fops = { + owner: THIS_MODULE, + llseek: crash_llseek, + read: crash_read, +}; + +static struct miscdevice crash_dev = { + MISC_DYNAMIC_MINOR, + "crash", + &crash_fops +}; + +static int __init +crash_init(void) +{ + int ret; + + ret = misc_register(&crash_dev); + if (ret) { + printk(KERN_ERR + "crash memory driver: cannot misc_register (MISC_DYNAMIC_MINOR)\n"); + goto out; + } + + ret = 0; + printk(KERN_INFO "crash memory driver: version %s\n", CRASH_VERSION); +out: + return ret; +} + +static void __exit +crash_cleanup_module(void) +{ + misc_deregister(&crash_dev); +} + +module_init(crash_init); +module_exit(crash_cleanup_module); + +MODULE_LICENSE("GPL"); diff --git a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h index aa7fd54bb..2abb7fa01 100644 --- a/drivers/char/drm/drm_agpsupport.h +++ b/drivers/char/drm/drm_agpsupport.h @@ -109,6 +109,8 @@ int DRM(agp_acquire)(struct inode *inode, struct file *filp, return -EBUSY; if (!drm_agp->acquire) return -EINVAL; + if ( dev->agp->cant_use_aperture ) + return -EINVAL; if ((retcode = drm_agp->acquire())) return retcode; dev->agp->acquired = 1; diff --git a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h index cbf2dbf02..f89aa9ee3 100644 --- a/drivers/char/drm/drm_ioctl.h +++ b/drivers/char/drm/drm_ioctl.h @@ -142,13 +142,6 @@ DRM(set_busid)(drm_device_t *dev) snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); - dev->devname = DRM(alloc)(strlen(dev->name) + dev->unique_len + 2, - DRM_MEM_DRIVER); - if (dev->devname == NULL) - return ENOMEM; - - sprintf(dev->devname, "%s@%s", dev->name, dev->unique); - return 0; } diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index 765355999..d4bc68b5a 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -285,19 +285,19 @@ static unsigned long ffb_get_unmapped_area(struct file *filp, unsigned long addr = -ENOMEM; if (!map) - return get_unmapped_area(NULL, hint, len, pgoff, flags); + return get_unmapped_area(NULL, hint, len, pgoff, flags, 0); if (map->type == _DRM_FRAME_BUFFER || map->type == _DRM_REGISTERS) { #ifdef HAVE_ARCH_FB_UNMAPPED_AREA addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags); #else - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); + addr = get_unmapped_area(NULL, hint, len, pgoff, flags, 0); #endif } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) { unsigned long slack = SHMLBA - PAGE_SIZE; - addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags); + addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags, 0); if (!(addr & ~PAGE_MASK)) { unsigned long kvirt = (unsigned long) map->handle; @@ -313,7 +313,7 @@ static unsigned long ffb_get_unmapped_area(struct file *filp, } } } else { - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); + addr = get_unmapped_area(NULL, hint, len, pgoff, flags, 0); } return addr; diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c index ed6a8358d..d45f5195a 100644 --- a/drivers/char/drm/gamma_dma.c +++ b/drivers/char/drm/gamma_dma.c @@ -346,9 +346,6 @@ static int gamma_dma_priority(struct file *filp, drm_buf_t *buf; drm_buf_t *last_buf = NULL; drm_device_dma_t *dma = dev->dma; - int *send_indices = NULL; - int *send_sizes = NULL; - DECLARE_WAITQUEUE(entry, current); /* Turn off interrupt handling */ @@ -368,31 +365,11 @@ static int gamma_dma_priority(struct file *filp, ++must_free; } - send_indices = DRM(alloc)(d->send_count * sizeof(*send_indices), - DRM_MEM_DRIVER); - if (send_indices == NULL) - return -ENOMEM; - if (copy_from_user(send_indices, d->send_indices, - d->send_count * sizeof(*send_indices))) { - retcode = -EFAULT; - goto cleanup; - } - - send_sizes = DRM(alloc)(d->send_count * sizeof(*send_sizes), - DRM_MEM_DRIVER); - if (send_sizes == NULL) - return -ENOMEM; - if (copy_from_user(send_sizes, d->send_sizes, - d->send_count * sizeof(*send_sizes))) { - retcode = -EFAULT; - goto cleanup; - } - for (i = 0; i < d->send_count; i++) { - idx = send_indices[i]; + idx = d->send_indices[i]; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", - send_indices[i], dma->buf_count - 1); + d->send_indices[i], dma->buf_count - 1); continue; } buf = dma->buflist[ idx ]; @@ -414,7 +391,7 @@ static int gamma_dma_priority(struct file *filp, process closes the /dev/drm? handle, so it can't also be doing DMA. */ buf->list = DRM_LIST_PRIO; - buf->used = send_sizes[i]; + buf->used = d->send_sizes[i]; buf->context = d->context; buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; address = (unsigned long)buf->address; @@ -425,14 +402,14 @@ static int gamma_dma_priority(struct file *filp, if (buf->pending) { DRM_ERROR("Sending pending buffer:" " buffer %d, offset %d\n", - send_indices[i], i); + d->send_indices[i], i); retcode = -EINVAL; goto cleanup; } if (buf->waiting) { DRM_ERROR("Sending waiting buffer:" " buffer %d, offset %d\n", - send_indices[i], i); + d->send_indices[i], i); retcode = -EINVAL; goto cleanup; } @@ -481,12 +458,6 @@ cleanup: gamma_dma_ready(dev); gamma_free_buffer(dev, last_buf); } - if (send_indices) - DRM(free)(send_indices, d->send_count * sizeof(*send_indices), - DRM_MEM_DRIVER); - if (send_sizes) - DRM(free)(send_sizes, d->send_count * sizeof(*send_sizes), - DRM_MEM_DRIVER); if (must_free && !dev->context_flag) { if (gamma_lock_free(dev, &dev->lock.hw_lock->lock, @@ -505,13 +476,9 @@ static int gamma_dma_send_buffers(struct file *filp, drm_buf_t *last_buf = NULL; int retcode = 0; drm_device_dma_t *dma = dev->dma; - int send_index; - - if (get_user(send_index, &d->send_indices[d->send_count-1])) - return -EFAULT; if (d->flags & _DRM_DMA_BLOCK) { - last_buf = dma->buflist[send_index]; + last_buf = dma->buflist[d->send_indices[d->send_count-1]]; add_wait_queue(&last_buf->dma_wait, &entry); } diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index 84823f664..fff7f0646 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -843,14 +843,11 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev, if (buf_priv->currently_mapped == I810_BUF_MAPPED) { unsigned int prim = (sarea_priv->vertex_prim & PR_MASK); - - put_user((GFX_OP_PRIMITIVE | prim | - ((used/4)-2)), - (u32 *)buf_priv->virtual); + + *(u32 *)buf_priv->kernel_virtual = ((GFX_OP_PRIMITIVE | prim | ((used/4)-2))); if (used & 4) { - put_user(0, - (u32 *)((u32)buf_priv->virtual + used)); + *(u32 *)((u32)buf_priv->kernel_virtual + used) = 0; used += 4; } diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 86c4e4204..090957dc5 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -1165,19 +1165,19 @@ static void i830_dma_dispatch_vertex(drm_device_t *dev, DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); if (buf_priv->currently_mapped == I830_BUF_MAPPED) { - u32 *vp = buf_priv->virtual; + u32 *vp = buf_priv->kernel_virtual; - put_user( (GFX_OP_PRIMITIVE | + vp[0] = (GFX_OP_PRIMITIVE | sarea_priv->vertex_prim | - ((used/4)-2)), &vp[0]); + ((used/4)-2)); if (dev_priv->use_mi_batchbuffer_start) { - put_user(MI_BATCH_BUFFER_END, &vp[used/4]); + vp[used/4] = MI_BATCH_BUFFER_END; used += 4; } if (used & 4) { - put_user(0, &vp[used/4]); + vp[used/4] = 0; used += 4; } diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 6ec11b025..81d220996 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -916,7 +916,7 @@ static int r128_cce_dispatch_write_span( drm_device_t *dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { return DRM_ERR(EFAULT); @@ -1012,7 +1012,7 @@ static int r128_cce_dispatch_write_pixels( drm_device_t *dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); @@ -1131,7 +1131,7 @@ static int r128_cce_dispatch_read_span( drm_device_t *dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { return DRM_ERR(EFAULT); @@ -1176,7 +1176,7 @@ static int r128_cce_dispatch_read_pixels( drm_device_t *dev, count = depth->n; if (count > 4096 || count <= 0) - return DRM_ERR(EMSGSIZE); + return -EMSGSIZE; if ( count > dev_priv->depth_pitch ) { count = dev_priv->depth_pitch; diff --git a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h index 54fac7940..9a22c0604 100644 --- a/drivers/char/drm/radeon.h +++ b/drivers/char/drm/radeon.h @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 11 +#define DRIVER_MINOR 10 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -84,8 +84,6 @@ * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which * clients use to tell the DRM where they think the framebuffer is * located in the card's address space - * 1.11- Add packet R200_EMIT_RB3D_BLENDCOLOR to support GL_EXT_blend_color - * and GL_EXT_blend_[func|equation]_separate on r200 */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 735e04ef4..c60c09fd4 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -144,8 +144,7 @@ #define RADEON_EMIT_PP_TEX_SIZE_0 73 #define RADEON_EMIT_PP_TEX_SIZE_1 74 #define RADEON_EMIT_PP_TEX_SIZE_2 75 -#define R200_EMIT_RB3D_BLENDCOLOR 76 -#define RADEON_MAX_STATE_PACKETS 77 +#define RADEON_MAX_STATE_PACKETS 76 /* Commands understood by cmd_buffer ioctl. More can be added but diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 45eafd056..afa516e8b 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -690,7 +690,6 @@ extern void radeon_do_release(drm_device_t *dev); #define R200_SE_VTX_FMT_1 0x208c #define R200_RE_CNTL 0x1c50 -#define R200_RB3D_BLENDCOLOR 0x3218 /* Constants */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 64143d190..a8780bc90 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -201,7 +201,6 @@ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_ case RADEON_EMIT_PP_TEX_SIZE_0: case RADEON_EMIT_PP_TEX_SIZE_1: case RADEON_EMIT_PP_TEX_SIZE_2: - case R200_EMIT_RB3D_BLENDCOLOR: /* These packets don't contain memory offsets */ break; @@ -564,7 +563,6 @@ static struct { { RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0" }, { RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1" }, { RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_1" }, - { R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR" }, }; diff --git a/drivers/char/dz.c b/drivers/char/dz.c deleted file mode 100644 index 23630030e..000000000 --- a/drivers/char/dz.c +++ /dev/null @@ -1,1540 +0,0 @@ -/* - * dz.c: Serial port driver for DECStations equiped - * with the DZ chipset. - * - * Copyright (C) 1998 Olivier A. D. Lebaillif - * - * Email: olivier.lebaillif@ifrsys.com - * - * [31-AUG-98] triemer - * Changed IRQ to use Harald's dec internals interrupts.h - * removed base_addr code - moving address assignment to setup.c - * Changed name of dz_init to rs_init to be consistent with tc code - * [13-NOV-98] triemer fixed code to receive characters - * after patches by harald to irq code. - * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout - * field from "current" - somewhere between 2.1.121 and 2.1.131 -Qua Jun 27 15:02:26 BRT 2001 - * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups - * - * Parts (C) 1999 David Airlie, airlied@linux.ie - * [07-SEP-99] Bugfixes - */ - -/* #define DEBUG_DZ 1 */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for definition of SERIAL */ - -/* for definition of struct console */ -#ifdef CONFIG_SERIAL_CONSOLE -#define CONSOLE_LINE (3) -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ -#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) -#include -#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ - -#include -#include - -#include -#include -#include -#include -#include - -#ifdef DEBUG_DZ -#include -#include -#include - -extern int (*prom_printf) (char *,...); -#endif - - - -#include "dz.h" - -#define DZ_INTR_DEBUG 1 - -DECLARE_TASK_QUEUE(tq_serial); - -static struct dz_serial *lines[4]; -static unsigned char tmp_buffer[256]; - - - -#ifdef DEBUG_DZ -/* - * debugging code to send out chars via prom - */ -static void debug_console( const char *s,int count) -{ - unsigned i; - - for (i = 0; i < count; i++) { - if (*s == 10) - prom_printf("%c", 13); - prom_printf("%c", *s++); - } -} -#endif - -/* - * ------------------------------------------------------------ - * dz_in () and dz_out () - * - * These routines are used to access the registers of the DZ - * chip, hiding relocation differences between implementation. - * ------------------------------------------------------------ - */ - -static inline unsigned short dz_in (struct dz_serial *info, unsigned offset) -{ - volatile u16 *addr = (volatile u16 *)(info->port + offset); - - return *addr; -} - -static inline void dz_out (struct dz_serial *info, unsigned offset, - unsigned short value) -{ - volatile u16 *addr = (volatile u16 *)(info->port + offset); - *addr = value; -} - -/* - * ------------------------------------------------------------ - * rs_stop () and rs_start () - * - * These routines are called before setting or resetting - * tty->stopped. They enable or disable transmitter interrupts, - * as necessary. - * ------------------------------------------------------------ - */ - -static void dz_stop (struct tty_struct *tty) -{ - struct dz_serial *info; - unsigned short mask, tmp; - - if (!tty) - return; - - info = (struct dz_serial *)tty->driver_data; - - mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ - - tmp &= ~mask; /* clear the TX flag */ - dz_out (info, DZ_TCR, tmp); -} - -static void dz_start (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - unsigned short mask, tmp; - - mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ - - tmp |= mask; /* set the TX flag */ - dz_out (info, DZ_TCR, tmp); -} - -/* - * ------------------------------------------------------------ - * Here starts the interrupt handling routines. All of the - * following subroutines are declared as inline and are folded - * into dz_interrupt. They were separated out for readability's - * sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer dz.c - * - * and look at the resulting assemble code in serial.s. - * - * ------------------------------------------------------------ - */ - -/* - * ------------------------------------------------------------ - * dz_sched_event () - * - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - * ------------------------------------------------------------ - */ -static inline void dz_sched_event (struct dz_serial *info, int event) -{ - info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); -} - -/* - * ------------------------------------------------------------ - * receive_char () - * - * This routine deals with inputs from any lines. - * ------------------------------------------------------------ - */ -static inline void receive_chars (struct dz_serial *info_in) -{ - struct dz_serial *info; - struct tty_struct *tty = 0; - struct async_icount *icount; - int ignore = 0; - unsigned short status, tmp; - unsigned char ch; - - /* - * This code is going to be a problem... the call to tty_flip_buffer - * is going to need to be rethought... - */ - do { - status = dz_in (info_in, DZ_RBUF); - info = lines[LINE(status)]; - - /* punt so we don't get duplicate characters */ - if (!(status & DZ_DVAL)) - goto ignore_char; - - ch = UCHAR(status); /* grab the char */ - -#if 0 - if (info->is_console) { - if (ch == 0) - return; /* it's a break ... */ - } -#endif - - tty = info->tty; /* now tty points to the proper dev */ - icount = &info->icount; - - if (!tty) - break; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; - - *tty->flip.char_buf_ptr = ch; - *tty->flip.flag_buf_ptr = 0; - icount->rx++; - - /* keep track of the statistics */ - if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { - if (status & DZ_PERR) /* parity error */ - icount->parity++; - else if (status & DZ_FERR) /* frame error */ - icount->frame++; - if (status & DZ_OERR) /* overrun error */ - icount->overrun++; - - /* - * Check to see if we should ignore the character and - * mask off conditions that should be ignored - */ - - if (status & info->ignore_status_mask) { - if (++ignore > 100) - break; - goto ignore_char; - } - - /* mask off the error conditions we want to ignore */ - tmp = status & info->read_status_mask; - - if (tmp & DZ_PERR) { - *tty->flip.flag_buf_ptr = TTY_PARITY; -#ifdef DEBUG_DZ - debug_console("PERR\n",5); -#endif /* DEBUG_DZ */ - } else if (tmp & DZ_FERR) { - *tty->flip.flag_buf_ptr = TTY_FRAME; -#ifdef DEBUG_DZ - debug_console("FERR\n",5); -#endif /* DEBUG_DZ */ - } if (tmp & DZ_OERR) { -#ifdef DEBUG_DZ - debug_console("OERR\n",5); -#endif /* DEBUG_DZ */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } - } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; -ignore_char: - ; - } while (status & DZ_DVAL); - - if (tty) - tty_flip_buffer_push(tty); -} - -/* - * ------------------------------------------------------------ - * transmit_char () - * - * This routine deals with outputs to any lines. - * ------------------------------------------------------------ - */ -static inline void transmit_chars (struct dz_serial *info) -{ - unsigned char tmp; - - if (info->x_char) { /* XON/XOFF chars */ - dz_out(info, DZ_TDR, info->x_char); - info->icount.tx++; - info->x_char = 0; - return; - } - - /* if nothing to do or stopped or hardware stopped */ - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { - dz_stop(info->tty); - return; - } - - /* - * If something to do ... (rember the dz has no output fifo so we go - * one char at a time :-< - */ - tmp = (unsigned short) info->xmit_buf[info->xmit_tail++]; - dz_out(info, DZ_TDR, tmp); - info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1); - info->icount.tx++; - - if (--info->xmit_cnt < WAKEUP_CHARS) - dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); - - /* Are we done */ - if (info->xmit_cnt <= 0) - dz_stop(info->tty); -} - -/* - * ------------------------------------------------------------ - * check_modem_status () - * - * Only valid for the MODEM line duh ! - * ------------------------------------------------------------ - */ -static inline void check_modem_status (struct dz_serial *info) -{ - unsigned short status; - - /* if not ne modem line just return */ - if (info->line != DZ_MODEM) - return; - - status = dz_in(info, DZ_MSR); - - /* it's easy, since DSR2 is the only bit in the register */ - if (status) - info->icount.dsr++; -} - -/* - * ------------------------------------------------------------ - * dz_interrupt () - * - * this is the main interrupt routine for the DZ chip. - * It deals with the multiple ports. - * ------------------------------------------------------------ - */ -static void dz_interrupt (int irq, void *dev, struct pt_regs *regs) -{ - struct dz_serial *info; - unsigned short status; - - /* get the reason why we just got an irq */ - status = dz_in((struct dz_serial *)dev, DZ_CSR); - info = lines[LINE(status)]; /* re-arrange info the proper port */ - - if (status & DZ_RDONE) - receive_chars(info); /* the receive function */ - - if (status & DZ_TRDY) - transmit_chars (info); -} - -/* - * ------------------------------------------------------------------- - * Here ends the DZ interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ -static void do_serial_bh (void) -{ - run_task_queue (&tq_serial); -} - -static void do_softint (void *private_data) -{ - struct dz_serial *info = (struct dz_serial *) private_data; - struct tty_struct *tty = info->tty; - - if (!tty) - return; - - if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible (&tty->write_wait); - } -} - -/* - * ------------------------------------------------------------------- - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * ------------------------------------------------------------------- - */ -static void do_serial_hangup (void *private_data) -{ - struct dz_serial *info = (struct dz_serial *) private_data; - struct tty_struct *tty = info->tty; - - if (!tty) - return; - - tty_hangup(tty); -} - -/* - * ------------------------------------------------------------------- - * startup () - * - * various initialization tasks - * ------------------------------------------------------------------- - */ -static int startup (struct dz_serial *info) -{ - unsigned long page, flags; - unsigned short tmp; - - if (info->is_initialized) - return 0; - - save_and_cli(flags); - - if (!info->port) { - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - restore_flags(flags); - return -ENODEV; - } - - if (!info->xmit_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - restore_flags (flags); - return -ENOMEM; - } - info->xmit_buf = (unsigned char *)page; - } - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - - /* enable the interrupt and the scanning */ - tmp = dz_in(info, DZ_CSR); - tmp |= (DZ_RIE | DZ_TIE | DZ_MSE); - dz_out(info, DZ_CSR, tmp); - - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - change_speed(info); /* set up the speed */ - - /* - * Clear the line transmitter buffer I can't figure out why I need to - * do this - but its necessary - in order for the console portion and - * the interrupt portion to live happily side by side. - */ - - info->is_initialized = 1; - - restore_flags(flags); - - return 0; -} - -/* - * ------------------------------------------------------------------- - * shutdown () - * - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - * ------------------------------------------------------------------- - */ -static void shutdown (struct dz_serial *info) -{ - unsigned long flags; - unsigned short tmp; - - if (!info->is_initialized) - return; - - save_and_cli(flags); - - dz_stop (info->tty); - - info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ - dz_out(info, DZ_LPR, info->cflags); - - if (info->xmit_buf) { /* free Tx buffer */ - free_page((unsigned long)info->xmit_buf); - info->xmit_buf = 0; - } - - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - tmp = dz_in(info, DZ_TCR); - if (tmp & DZ_MODEM_DTR) { - tmp &= ~DZ_MODEM_DTR; - dz_out(info, DZ_TCR, tmp); - } - } - - if (info->tty) - set_bit (TTY_IO_ERROR, &info->tty->flags); - - info->is_initialized = 0; - - restore_flags (flags); -} - -/* - * ------------------------------------------------------------------- - * change_speed () - * - * set the baud rate. - * ------------------------------------------------------------------- - */ -static void change_speed (struct dz_serial *info) -{ - unsigned long flags; - unsigned cflag; - int baud; - - if (!info->tty || !info->tty->termios) - return; - - save_and_cli(flags); - - info->cflags = info->line; - - cflag = info->tty->termios->c_cflag; - - switch (cflag & CSIZE) { - case CS5: - info->cflags |= DZ_CS5; - break; - case CS6: - info->cflags |= DZ_CS6; - break; - case CS7: - info->cflags |= DZ_CS7; - break; - case CS8: - default: - info->cflags |= DZ_CS8; - } - - if (cflag & CSTOPB) - info->cflags |= DZ_CSTOPB; - if (cflag & PARENB) - info->cflags |= DZ_PARENB; - if (cflag & PARODD) - info->cflags |= DZ_PARODD; - - baud = tty_get_baud_rate(info->tty); - switch (baud) { - case 50: - info->cflags |= DZ_B50; - break; - case 75: - info->cflags |= DZ_B75; - break; - case 110: - info->cflags |= DZ_B110; - break; - case 134: - info->cflags |= DZ_B134; - break; - case 150: - info->cflags |= DZ_B150; - break; - case 300: - info->cflags |= DZ_B300; - break; - case 600: - info->cflags |= DZ_B600; - break; - case 1200: - info->cflags |= DZ_B1200; - break; - case 1800: - info->cflags |= DZ_B1800; - break; - case 2000: - info->cflags |= DZ_B2000; - break; - case 2400: - info->cflags |= DZ_B2400; - break; - case 3600: - info->cflags |= DZ_B3600; - break; - case 4800: - info->cflags |= DZ_B4800; - break; - case 7200: - info->cflags |= DZ_B7200; - break; - case 9600: - default: - info->cflags |= DZ_B9600; - } - - info->cflags |= DZ_RXENAB; - dz_out(info, DZ_LPR, info->cflags); - - /* setup accept flag */ - info->read_status_mask = DZ_OERR; - if (I_INPCK(info->tty)) - info->read_status_mask |= (DZ_FERR | DZ_PERR); - - /* characters to ignore */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= (DZ_FERR | DZ_PERR); - - restore_flags(flags); -} - -/* - * ------------------------------------------------------------------- - * dz_flush_char () - * - * Flush the buffer. - * ------------------------------------------------------------------- - */ -static void dz_flush_chars (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - unsigned long flags; - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) - return; - - save_and_cli(flags); - dz_start (info->tty); - restore_flags(flags); -} - - -/* - * ------------------------------------------------------------------- - * dz_write () - * - * main output routine. - * ------------------------------------------------------------------- - */ -static int dz_write (struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - unsigned long flags; - int c, ret = 0; - - if (!tty ) - return ret; - if (!info->xmit_buf) - return ret; - if (!tmp_buf) - tmp_buf = tmp_buffer; - - if (from_user) { - down (&tmp_buf_sem); - while (1) { - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - c -= copy_from_user (tmp_buf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - - save_and_cli(flags); - - c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE - 1)); - info->xmit_cnt += c; - restore_flags(flags); - - buf += c; - count -= c; - ret += c; - } - up(&tmp_buf_sem); - } else { - while (1) { - save_and_cli(flags); - - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); - if (c <= 0) { - restore_flags (flags); - break; - } - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE-1)); - info->xmit_cnt += c; - restore_flags(flags); - - buf += c; - count -= c; - ret += c; - } - } - - if (info->xmit_cnt) { - if (!tty->stopped) { - if (!tty->hw_stopped) { - dz_start (info->tty); - } - } - } - - return ret; -} - -/* - * ------------------------------------------------------------------- - * dz_write_room () - * - * compute the amount of space available for writing. - * ------------------------------------------------------------------- - */ -static int dz_write_room (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - int ret; - - ret = DZ_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - - return ret; -} - -/* - * ------------------------------------------------------------------- - * dz_chars_in_buffer () - * - * compute the amount of char left to be transmitted - * ------------------------------------------------------------------- - */ -static int dz_chars_in_buffer (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - return info->xmit_cnt; -} - -/* - * ------------------------------------------------------------------- - * dz_flush_buffer () - * - * Empty the output buffer - * ------------------------------------------------------------------- - */ -static void dz_flush_buffer (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); - - wake_up_interruptible (&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * dz_throttle () and dz_unthrottle () - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled (or not). - * ------------------------------------------------------------ - */ -static void dz_throttle (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); -} - -static void dz_unthrottle (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } -} - -static void dz_send_xchar (struct tty_struct *tty, char ch) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - info->x_char = ch; - - if (ch) - dz_start(info->tty); -} - -/* - * ------------------------------------------------------------ - * rs_ioctl () and friends - * ------------------------------------------------------------ - */ -static int get_serial_info(struct dz_serial *info, - struct serial_struct *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset (&tmp, 0, sizeof(tmp)); - - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->port; - tmp.irq = SERIAL; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - - return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; -} - -static int set_serial_info (struct dz_serial *info, - struct serial_struct *new_info) -{ - struct serial_struct new_serial; - struct dz_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; - - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - - retval = startup(info); - - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info (struct dz_serial *info, unsigned int *value) -{ - unsigned short status = dz_in (info, DZ_LPR); - - return put_user (status, value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break (struct dz_serial *info, int duration) -{ - unsigned long flags; - unsigned short tmp, mask; - - if (!info->port) - return; - - mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); - tmp |= mask; - - current->state = TASK_INTERRUPTIBLE; - - save_and_cli(flags); - dz_out(info, DZ_TCR, tmp); - schedule_timeout(duration); - tmp &= ~mask; - dz_out(info, DZ_TCR, tmp); - restore_flags(flags); -} - -static int dz_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int error; - struct dz_serial * info = (struct dz_serial *)tty->driver_data; - int retval; - - if (cmd != TIOCGSERIAL && cmd != TIOCSSERIAL && - cmd != TIOCSERCONFIG && cmd != TIOCSERGWILD && - cmd != TIOCSERSWILD && cmd != TIOCSERGSTRUCT) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - return 0; - - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - return 0; - - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - - case TIOCSSOFTCAR: - if (get_user (arg, (unsigned long *)arg)) - return -EFAULT; - - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0); - return 0; - - case TIOCGSERIAL: - return get_serial_info(info, (struct serial_struct *)arg); - - case TIOCSSERIAL: - return set_serial_info(info, (struct serial_struct *) arg); - - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info (info, (unsigned int *)arg); - - case TIOCSERGSTRUCT: - return copy_to_user((struct dz_serial *)arg, info, - sizeof(struct dz_serial)) ? -EFAULT : 0; - - default: - return -ENOIOCTLCMD; - } - - return 0; -} - -static void dz_set_termios (struct tty_struct *tty, - struct termios *old_termios) -{ - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - - change_speed (info); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - dz_start(tty); - } -} - -/* - * ------------------------------------------------------------ - * dz_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we turn off - * the transmit enable and receive enable flags. - * ------------------------------------------------------------ - */ -static void dz_close(struct tty_struct *tty, struct file *filp) -{ - struct dz_serial * info = (struct dz_serial *)tty->driver_data; - unsigned long flags; - - if (!info) - return; - - save_and_cli(flags); - - if (tty_hung_up_p(filp)) { - restore_flags(flags); - return; - } - - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty structure - * will be freed. Info->count should always be one in these - * conditions. If it's greater than one, we've got real - * problems, since it means the serial port won't be shutdown. - */ - printk("dz_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - - if (--info->count < 0) { - printk("ds_close: bad serial port count for ttyS%02d: %d\n", - info->line, info->count); - info->count = 0; - } - - if (info->count) { - restore_flags(flags); - return; - } - info->flags |= DZ_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify the line - * discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - - if (info->closing_wait != DZ_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - - /* - * At this point we stop accepting input. To do this, we disable the - * receive line status interrupts. - */ - shutdown(info); - - if (tty->driver->flush_buffer) - tty->driver->flush_buffer (tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); - tty->closing = 0; - info->event = 0; - info->tty = 0; - - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - tty->ldisc.close(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - tty->ldisc.open(tty); - } - if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); - } - wake_up_interruptible(&info->open_wait); - } - - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CLOSING); - wake_up_interruptible(&info->close_wait); - - restore_flags(flags); -} - -/* - * dz_hangup () --- called by tty_hangup() when a hangup is signaled. - */ -static void dz_hangup (struct tty_struct *tty) -{ - struct dz_serial *info = (struct dz_serial *) tty->driver_data; - - dz_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~DZ_NORMAL_ACTIVE; - info->tty = 0; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct dz_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & DZ_CLOSING) { - interruptible_sleep_on(&info->close_wait); - return -EAGAIN; - } - - /* - * If non-blocking mode is set, or the port is not enabled, then make - * the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= DZ_NORMAL_ACTIVE; - - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become free - * (i.e., not in use by the callout). While we are in this loop, - * info->count is dropped by one, so that dz_close() knows when to free - * things. We restore it upon exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); - - info->count--; - info->blocked_open++; - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p (filp) || !(info->is_initialized)) { - retval = -EAGAIN; - break; - } - if (!(info->flags & DZ_CLOSING) && do_clocal) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue (&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; - - if (retval) - return retval; - info->flags |= DZ_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port. It also performs the - * serial-specific initialization for the tty structure. - */ -static int dz_open (struct tty_struct *tty, struct file *filp) -{ - struct dz_serial *info; - int retval, line; - - line = tty->index; - - /* - * The dz lines for the mouse/keyboard must be opened using their - * respective drivers. - */ - if ((line < 0) || (line >= DZ_NB_PORT)) - return -ENODEV; - - if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE)) - return -ENODEV; - - info = lines[line]; - info->count++; - - tty->driver_data = info; - info->tty = tty; - - /* - * Start up serial port - */ - retval = startup (info); - if (retval) - return retval; - - retval = block_til_ready (tty, filp, info); - if (retval) - return retval; - - return 0; -} - -static void show_serial_version (void) -{ - printk("%s%s\n", dz_name, dz_version); -} - -static struct tty_driver *serial_driver; - -static struct tty_operations serial_ops = { - .open = dz_open, - .close = dz_close, - .write = dz_write, - .flush_chars = dz_flush_chars, - .write_room = dz_write_room, - .chars_in_buffer = dz_chars_in_buffer, - .flush_buffer = dz_flush_buffer, - .ioctl = dz_ioctl, - .throttle = dz_throttle, - .unthrottle = dz_unthrottle, - .send_xchar = dz_send_xchar, - .set_termios = dz_set_termios, - .stop = dz_stop, - .start = dz_start, - .hangup = dz_hangup, -}; - -int __init dz_init(void) -{ - int i, flags; - struct dz_serial *info; - - serial_driver = alloc_tty_driver(DZ_NB_PORT); - if (!serial_driver) - return -ENOMEM; - - /* Setup base handler, and timer table. */ - init_bh(SERIAL_BH, do_serial_bh); - - show_serial_version(); - - serial_driver->owner = THIS_MODULE; - serial_driver->devfs_name = "tts/"; - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | - CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - tty_set_operations(serial_driver, &serial_ops); - - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - save_flags(flags); cli(); - for (i=0; i < DZ_NB_PORT; i++) { - info = &multi[i]; - lines[i] = info; - info->magic = SERIAL_MAGIC; - - if ((mips_machtype == MACH_DS23100) || - (mips_machtype == MACH_DS5100)) - info->port = (unsigned long) KN01_DZ11_BASE; - else - info->port = (unsigned long) KN02_DZ11_BASE; - - info->line = i; - info->tty = 0; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - info->tqueue_hangup.routine = do_serial_hangup; - info->tqueue_hangup.data = info; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - - /* - * If we are pointing to address zero then punt - not correctly - * set up in setup.c to handle this. - */ - if (! info->port) - return 0; - - printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, - info->port, SERIAL); - - tty_register_device(serial_driver, info->line, NULL); - } - - /* Reset the chip */ -#ifndef CONFIG_SERIAL_CONSOLE - { - int tmp; - dz_out(info, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR); - wbflush(); - - /* Enable scanning */ - dz_out(info, DZ_CSR, DZ_MSE); - } -#endif - - /* - * Order matters here... the trick is that flags is updated... in - * request_irq - to immediatedly obliterate it is unwise. - */ - restore_flags(flags); - - if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) - panic("Unable to register DZ interrupt\n"); - - return 0; -} - -#ifdef CONFIG_SERIAL_CONSOLE -static void dz_console_put_char (unsigned char ch) -{ - unsigned long flags; - int loops = 2500; - unsigned short tmp = ch; - /* - * this code sends stuff out to serial device - spinning its wheels and - * waiting. - */ - - /* force the issue - point it at lines[3]*/ - dz_console = &multi[CONSOLE_LINE]; - - save_and_cli(flags); - - /* spin our wheels */ - while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) - ; - - /* Actually transmit the character. */ - dz_out(dz_console, DZ_TDR, tmp); - - restore_flags(flags); -} - -/* - * ------------------------------------------------------------------- - * dz_console_print () - * - * dz_console_print is registered for printk. - * The console must be locked when we get here. - * ------------------------------------------------------------------- - */ -static void dz_console_print (struct console *cons, - const char *str, - unsigned int count) -{ -#ifdef DEBUG_DZ - prom_printf((char *)str); -#endif - while (count--) { - if (*str == '\n') - dz_console_put_char('\r'); - dz_console_put_char(*str++); - } -} - -static struct tty_driver *dz_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - -static int __init dz_console_setup(struct console *co, char *options) -{ - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - char *s; - unsigned short mask,tmp; - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while (*s >= '0' && *s <= '9') - s++; - if (*s) - parity = *s++; - if (*s) - bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch (baud) { - case 1200: - cflag |= DZ_B1200; - break; - case 2400: - cflag |= DZ_B2400; - break; - case 4800: - cflag |= DZ_B4800; - break; - case 9600: - default: - cflag |= DZ_B9600; - break; - } - switch (bits) { - case 7: - cflag |= DZ_CS7; - break; - default: - case 8: - cflag |= DZ_CS8; - break; - } - switch (parity) { - case 'o': - case 'O': - cflag |= DZ_PARODD; - break; - case 'e': - case 'E': - cflag |= DZ_PARENB; - break; - } - co->cflag = cflag; - - /* TOFIX: force to console line */ - dz_console = &multi[CONSOLE_LINE]; - if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) - dz_console->port = KN01_DZ11_BASE; - else - dz_console->port = KN02_DZ11_BASE; - dz_console->line = CONSOLE_LINE; - - dz_out(dz_console, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) - ; - - /* enable scanning */ - dz_out(dz_console, DZ_CSR, DZ_MSE); - - /* Set up flags... */ - dz_console->cflags = 0; - dz_console->cflags |= DZ_B9600; - dz_console->cflags |= DZ_CS8; - dz_console->cflags |= DZ_PARENB; - dz_out(dz_console, DZ_LPR, dz_console->cflags); - - mask = 1 << dz_console->line; - tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ - if (!(tmp & mask)) { - tmp |= mask; /* set the TX flag */ - dz_out (dz_console, DZ_TCR, tmp); - } - - return 0; -} - -static struct console dz_sercons = { - .name = "ttyS", - .write = dz_console_print, - .device = dz_console_device, - .setup = dz_console_setup, - .flags = CON_CONSDEV | CON_PRINTBUFFER, - .index = CONSOLE_LINE, -}; - -void __init dz_serial_console_init(void) -{ - register_console(&dz_sercons); -} - -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ - -MODULE_LICENSE("GPL"); diff --git a/drivers/char/dz.h b/drivers/char/dz.h deleted file mode 100644 index 989f927a4..000000000 --- a/drivers/char/dz.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * dz.h: Serial port driver for DECStations equiped - * with the DZ chipset. - * - * Copyright (C) 1998 Olivier A. D. Lebaillif - * - * Email: olivier.lebaillif@ifrsys.com - * - */ -#ifndef DZ_SERIAL_H -#define DZ_SERIAL_H - -/* - * Definitions for the Control and Status Received. - */ -#define DZ_TRDY 0x8000 /* Transmitter empty */ -#define DZ_TIE 0x4000 /* Transmitter Interrupt Enable */ -#define DZ_RDONE 0x0080 /* Receiver data ready */ -#define DZ_RIE 0x0040 /* Receive Interrupt Enable */ -#define DZ_MSE 0x0020 /* Master Scan Enable */ -#define DZ_CLR 0x0010 /* Master reset */ -#define DZ_MAINT 0x0008 /* Loop Back Mode */ - -/* - * Definitions for the Received buffer. - */ -#define DZ_RBUF_MASK 0x00FF /* Data Mask in the Receive Buffer */ -#define DZ_LINE_MASK 0x0300 /* Line Mask in the Receive Buffer */ -#define DZ_DVAL 0x8000 /* Valid Data indicator */ -#define DZ_OERR 0x4000 /* Overrun error indicator */ -#define DZ_FERR 0x2000 /* Frame error indicator */ -#define DZ_PERR 0x1000 /* Parity error indicator */ - -#define LINE(x) (x & DZ_LINE_MASK) >> 8 /* Get the line number from the input buffer */ -#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK) - -/* - * Definitions for the Transmit Register. - */ -#define DZ_LINE_KEYBOARD 0x0001 -#define DZ_LINE_MOUSE 0x0002 -#define DZ_LINE_MODEM 0x0004 -#define DZ_LINE_PRINTER 0x0008 - -#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */ - -/* - * Definitions for the Modem Status Register. - */ -#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */ - -/* - * Definitions for the Transmit Data Register. - */ -#define DZ_BRK0 0x0100 /* Break assertion for line 0 */ -#define DZ_BRK1 0x0200 /* Break assertion for line 1 */ -#define DZ_BRK2 0x0400 /* Break assertion for line 2 */ -#define DZ_BRK3 0x0800 /* Break assertion for line 3 */ - -/* - * Definitions for the Line Parameter Register. - */ -#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */ -#define DZ_MOUSE 0x0001 /* line 1 = mouse */ -#define DZ_MODEM 0x0002 /* line 2 = modem */ -#define DZ_PRINTER 0x0003 /* line 3 = printer */ - -#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */ -#define DZ_CS5 0x0000 /* 5 bits per byte */ -#define DZ_CS6 0x0008 /* 6 bits per byte */ -#define DZ_CS7 0x0010 /* 7 bits per byte */ -#define DZ_CS8 0x0018 /* 8 bits per byte */ - -#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */ - -#define DZ_PARENB 0x0040 /* Parity enable */ -#define DZ_PARODD 0x0080 /* Odd parity instead of even */ - -#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */ -#define DZ_B50 0x0000 -#define DZ_B75 0x0100 -#define DZ_B110 0x0200 -#define DZ_B134 0x0300 -#define DZ_B150 0x0400 -#define DZ_B300 0x0500 -#define DZ_B600 0x0600 -#define DZ_B1200 0x0700 -#define DZ_B1800 0x0800 -#define DZ_B2000 0x0900 -#define DZ_B2400 0x0A00 -#define DZ_B3600 0x0B00 -#define DZ_B4800 0x0C00 -#define DZ_B7200 0x0D00 -#define DZ_B9600 0x0E00 - -#define DZ_CREAD 0x1000 /* Enable receiver */ -#define DZ_RXENAB 0x1000 /* enable receive char */ -/* - * Addresses for the DZ registers - */ -#define DZ_CSR 0x00 /* Control and Status Register */ -#define DZ_RBUF 0x08 /* Receive Buffer */ -#define DZ_LPR 0x08 /* Line Parameters Register */ -#define DZ_TCR 0x10 /* Transmitter Control Register */ -#define DZ_MSR 0x18 /* Modem Status Register */ -#define DZ_TDR 0x18 /* Transmit Data Register */ - - -#define DZ_NB_PORT 4 - -#define DZ_XMIT_SIZE 4096 /* buffer size */ -#define WAKEUP_CHARS DZ_XMIT_SIZE/4 - -#define DZ_EVENT_WRITE_WAKEUP 0 - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -#define DZ_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define DZ_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define DZ_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define DZ_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define DZ_CLOSING 0x08000000 /* Serial port is closing */ -#define DZ_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define DZ_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -#define DZ_CLOSING_WAIT_INF 0 -#define DZ_CLOSING_WAIT_NONE 65535 - -#define DZ_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ -#define DZ_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define DZ_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ - -struct dz_serial { - unsigned port; /* base address for the port */ - int type; - int flags; - int baud_base; - int blocked_open; - unsigned short close_delay; - unsigned short closing_wait; - unsigned short line; /* port/line number */ - unsigned short cflags; /* line configuration flag */ - unsigned short x_char; /* xon/xoff character */ - unsigned short read_status_mask; /* mask for read condition */ - unsigned short ignore_status_mask; /* mask for ignore condition */ - unsigned long event; /* mask used in BH */ - unsigned char *xmit_buf; /* Transmit buffer */ - int xmit_head; /* Position of the head */ - int xmit_tail; /* Position of the tail */ - int xmit_cnt; /* Count of the chars in the buffer */ - int count; /* indicates how many times it has been opened */ - int magic; - - struct async_icount icount; /* keep track of things ... */ - struct tty_struct *tty; /* tty associated */ - struct tq_struct tqueue; /* Queue for BH */ - struct tq_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - unsigned char is_console; /* flag indicating a serial console */ - unsigned char is_initialized; -}; - -static struct dz_serial multi[DZ_NB_PORT]; /* Four serial lines in the DZ chip */ -static struct dz_serial *dz_console; - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DECLARE_MUTEX(tmp_buf_sem); - -static char *dz_name = "DECstation DZ serial driver version "; -static char *dz_version = "1.02"; - -static inline unsigned short dz_in (struct dz_serial *, unsigned); -static inline void dz_out (struct dz_serial *, unsigned, unsigned short); - -static inline void dz_sched_event (struct dz_serial *, int); -static inline void receive_chars (struct dz_serial *); -static inline void transmit_chars (struct dz_serial *); -static inline void check_modem_status (struct dz_serial *); - -static void dz_stop (struct tty_struct *); -static void dz_start (struct tty_struct *); -static void dz_interrupt (int, void *, struct pt_regs *); -static void do_serial_bh (void); -static void do_softint (void *); -static void do_serial_hangup (void *); -static void change_speed (struct dz_serial *); -static void dz_flush_chars (struct tty_struct *); -static void dz_console_print (struct console *, const char *, unsigned int); -static void dz_flush_buffer (struct tty_struct *); -static void dz_throttle (struct tty_struct *); -static void dz_unthrottle (struct tty_struct *); -static void dz_send_xchar (struct tty_struct *, char); -static void shutdown (struct dz_serial *); -static void send_break (struct dz_serial *, int); -static void dz_set_termios (struct tty_struct *, struct termios *); -static void dz_close (struct tty_struct *, struct file *); -static void dz_hangup (struct tty_struct *); -static void show_serial_version (void); - -static int dz_write (struct tty_struct *, int, const unsigned char *, int); -static int dz_write_room (struct tty_struct *); -static int dz_chars_in_buffer (struct tty_struct *); -static int startup (struct dz_serial *); -static int get_serial_info (struct dz_serial *, struct serial_struct *); -static int set_serial_info (struct dz_serial *, struct serial_struct *); -static int get_lsr_info (struct dz_serial *, unsigned int *); -static int dz_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long); -static int block_til_ready (struct tty_struct *, struct file *, struct dz_serial *); -static int dz_open (struct tty_struct *, struct file *); - -#ifdef MODULE -int init_module (void) -void cleanup_module (void) -#endif - -#endif - -#endif /* DZ_SERIAL_H */ diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c new file mode 100644 index 000000000..cef6032b8 --- /dev/null +++ b/drivers/char/hpet.c @@ -0,0 +1,1076 @@ +/* + * Intel & MS High Precision Event Timer Implementation. + * Contributors: + * Venki Pallipadi + * Bob Picco + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * The High Precision Event Timer driver. + * This driver is closely modelled after the rtc.c driver. + * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm + */ +#define HPET_USER_FREQ (64) +#define HPET_DRIFT (500) + +static u32 hpet_ntimer, hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; + +/* A lock for concurrent access by app and isr hpet activity. */ +static spinlock_t hpet_lock = SPIN_LOCK_UNLOCKED; +/* A lock for concurrent intermodule access to hpet and isr hpet activity. */ +static spinlock_t hpet_task_lock = SPIN_LOCK_UNLOCKED; + +struct hpet_dev { + struct hpets *hd_hpets; + struct hpet *hd_hpet; + struct hpet_timer *hd_timer; + unsigned long hd_ireqfreq; + unsigned long hd_irqdata; + wait_queue_head_t hd_waitqueue; + struct fasync_struct *hd_async_queue; + struct hpet_task *hd_task; + unsigned int hd_flags; + unsigned int hd_irq; + unsigned int hd_hdwirq; +}; + +struct hpets { + struct hpets *hp_next; + struct hpet *hp_hpet; + unsigned long hp_period; + unsigned long hp_delta; + unsigned int hp_ntimer; + unsigned int hp_which; + struct hpet_dev hp_dev[1]; +}; + +static struct hpets *hpets; + +#define HPET_OPEN 0x0001 +#define HPET_IE 0x0002 /* interrupt enabled */ +#define HPET_PERIODIC 0x0004 + +#if BITS_PER_LONG == 64 +#define write_counter(V, MC) writeq(V, MC) +#define read_counter(MC) readq(MC) +#else +#define write_counter(V, MC) writel(V, MC) +#define read_counter(MC) readl(MC) +#endif + +#ifndef readq +static unsigned long long __inline readq(void *addr) +{ + return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static void __inline writeq(unsigned long long v, void *addr) +{ + writel(v & 0xffffffff, addr); + writel(v >> 32, addr + 4); +} +#endif + +static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) +{ + struct hpet_dev *devp; + unsigned long isr; + + devp = data; + + spin_lock(&hpet_lock); + devp->hd_irqdata++; + + /* + * For non-periodic timers, increment the accumulator. + * This has the effect of treating non-periodic like periodic. + */ + if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) { + unsigned long m, t; + + t = devp->hd_ireqfreq; + m = read_counter(&devp->hd_hpet->hpet_mc); + write_counter(t + m + devp->hd_hpets->hp_delta, + &devp->hd_timer->hpet_compare); + } + + isr = (1 << (devp - devp->hd_hpets->hp_dev)); + writeq(isr, &devp->hd_hpet->hpet_isr); + spin_unlock(&hpet_lock); + + spin_lock(&hpet_task_lock); + if (devp->hd_task) + devp->hd_task->ht_func(devp->hd_task->ht_data); + spin_unlock(&hpet_task_lock); + + wake_up_interruptible(&devp->hd_waitqueue); + + kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); + + return IRQ_HANDLED; +} + +static int hpet_open(struct inode *inode, struct file *file) +{ + struct hpet_dev *devp; + struct hpets *hpetp; + int i; + + spin_lock_irq(&hpet_lock); + + for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) + for (i = 0; i < hpetp->hp_ntimer; i++) + if (hpetp->hp_dev[i].hd_flags & HPET_OPEN + || hpetp->hp_dev[i].hd_task) + continue; + else { + devp = &hpetp->hp_dev[i]; + break; + } + + if (!devp) { + spin_unlock_irq(&hpet_lock); + return -EBUSY; + } + + file->private_data = devp; + devp->hd_irqdata = 0; + devp->hd_flags |= HPET_OPEN; + spin_unlock_irq(&hpet_lock); + + return 0; +} + +static ssize_t +hpet_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + struct hpet_dev *devp; + + devp = file->private_data; + if (!devp->hd_ireqfreq) + return -EIO; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&devp->hd_waitqueue, &wait); + + do { + __set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irq(&hpet_lock); + data = devp->hd_irqdata; + devp->hd_irqdata = 0; + spin_unlock_irq(&hpet_lock); + + if (data) + break; + else if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } else if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + + } while (1); + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + out: + current->state = TASK_RUNNING; + remove_wait_queue(&devp->hd_waitqueue, &wait); + + return retval; +} + +static unsigned int hpet_poll(struct file *file, poll_table * wait) +{ + unsigned long v; + struct hpet_dev *devp; + + devp = file->private_data; + + if (!devp->hd_ireqfreq) + return 0; + + poll_wait(file, &devp->hd_waitqueue, wait); + + spin_lock_irq(&hpet_lock); + v = devp->hd_irqdata; + spin_unlock_irq(&hpet_lock); + + if (v != 0) + return POLLIN | POLLRDNORM; + + return 0; +} + +static int hpet_mmap(struct file *file, struct vm_area_struct *vma) +{ +#ifdef CONFIG_HPET_NOMMAP + return -ENOSYS; +#else + struct hpet_dev *devp; + unsigned long addr; + + if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + devp = file->private_data; + addr = (unsigned long)devp->hd_hpet; + + if (addr & (PAGE_SIZE - 1)) + return -ENOSYS; + + vma->vm_flags |= VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + addr = __pa(addr); + + if (remap_page_range + (vma, vma->vm_start, addr, PAGE_SIZE, vma->vm_page_prot)) { + printk(KERN_ERR "remap_page_range failed in hpet.c\n"); + return -EAGAIN; + } + + return 0; +#endif +} + +static int hpet_fasync(int fd, struct file *file, int on) +{ + struct hpet_dev *devp; + + devp = file->private_data; + + if (fasync_helper(fd, file, on, &devp->hd_async_queue) >= 0) + return 0; + else + return -EIO; +} + +static int hpet_release(struct inode *inode, struct file *file) +{ + struct hpet_dev *devp; + struct hpet_timer *timer; + int irq = 0; + + devp = file->private_data; + timer = devp->hd_timer; + + spin_lock_irq(&hpet_lock); + + writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK), + &timer->hpet_config); + + irq = devp->hd_irq; + devp->hd_irq = 0; + + devp->hd_ireqfreq = 0; + + if (devp->hd_flags & HPET_PERIODIC + && readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) { + unsigned long v; + + v = readq(&timer->hpet_config); + v ^= Tn_TYPE_CNF_MASK; + writeq(v, &timer->hpet_config); + } + + devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC); + spin_unlock_irq(&hpet_lock); + + if (irq) + free_irq(irq, devp); + + if (file->f_flags & FASYNC) + hpet_fasync(-1, file, 0); + + file->private_data = 0; + return 0; +} + +static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int); + +static int +hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct hpet_dev *devp; + + devp = file->private_data; + return hpet_ioctl_common(devp, cmd, arg, 0); +} + +static int hpet_ioctl_ieon(struct hpet_dev *devp) +{ + struct hpet_timer *timer; + struct hpet *hpet; + struct hpets *hpetp; + int irq; + unsigned long g, v, t, m; + unsigned long flags, isr; + + timer = devp->hd_timer; + hpet = devp->hd_hpet; + hpetp = devp->hd_hpets; + + v = readq(&timer->hpet_config); + spin_lock_irq(&hpet_lock); + + if (devp->hd_flags & HPET_IE) { + spin_unlock_irq(&hpet_lock); + return -EBUSY; + } + + devp->hd_flags |= HPET_IE; + spin_unlock_irq(&hpet_lock); + + t = readq(&timer->hpet_config); + irq = devp->hd_hdwirq; + + if (irq) { + char name[7]; + + sprintf(name, "hpet%d", (int)(devp - hpetp->hp_dev)); + + if (request_irq + (irq, hpet_interrupt, SA_INTERRUPT, name, (void *)devp)) { + printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); + irq = 0; + } + } + + if (irq == 0) { + spin_lock_irq(&hpet_lock); + devp->hd_flags ^= HPET_IE; + spin_unlock_irq(&hpet_lock); + return -EIO; + } + + devp->hd_irq = irq; + t = devp->hd_ireqfreq; + v = readq(&timer->hpet_config); + g = v | Tn_INT_ENB_CNF_MASK; + + if (devp->hd_flags & HPET_PERIODIC) { + write_counter(t, &timer->hpet_compare); + g |= Tn_TYPE_CNF_MASK; + v |= Tn_TYPE_CNF_MASK; + writeq(v, &timer->hpet_config); + v |= Tn_VAL_SET_CNF_MASK; + writeq(v, &timer->hpet_config); + local_irq_save(flags); + m = read_counter(&hpet->hpet_mc); + write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); + } else { + local_irq_save(flags); + m = read_counter(&hpet->hpet_mc); + write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); + } + + isr = (1 << (devp - hpets->hp_dev)); + writeq(isr, &hpet->hpet_isr); + writeq(g, &timer->hpet_config); + local_irq_restore(flags); + + return 0; +} + +static inline unsigned long hpet_time_div(unsigned long dis) +{ + unsigned long long m = 1000000000000000ULL; + + do_div(m, dis); + + return (unsigned long)m; +} + +static int +hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) +{ + struct hpet_timer *timer; + struct hpet *hpet; + struct hpets *hpetp; + int err; + unsigned long v; + + switch (cmd) { + case HPET_IE_OFF: + case HPET_INFO: + case HPET_EPI: + case HPET_DPI: + case HPET_IRQFREQ: + timer = devp->hd_timer; + hpet = devp->hd_hpet; + hpetp = devp->hd_hpets; + break; + case HPET_IE_ON: + return hpet_ioctl_ieon(devp); + default: + return -EINVAL; + } + + err = 0; + + switch (cmd) { + case HPET_IE_OFF: + if ((devp->hd_flags & HPET_IE) == 0) + break; + v = readq(&timer->hpet_config); + v &= ~Tn_INT_ENB_CNF_MASK; + writeq(v, &timer->hpet_config); + if (devp->hd_irq) { + free_irq(devp->hd_irq, devp); + devp->hd_irq = 0; + } + devp->hd_flags ^= HPET_IE; + break; + case HPET_INFO: + { + struct hpet_info info; + + info.hi_ireqfreq = hpet_time_div(hpetp->hp_period * + devp->hd_ireqfreq); + info.hi_flags = + readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK; + info.hi_hpet = devp->hd_hpets->hp_which; + info.hi_timer = devp - devp->hd_hpets->hp_dev; + if (copy_to_user((void *)arg, &info, sizeof(info))) + err = -EFAULT; + break; + } + case HPET_EPI: + v = readq(&timer->hpet_config); + if ((v & Tn_PER_INT_CAP_MASK) == 0) { + err = -ENXIO; + break; + } + devp->hd_flags |= HPET_PERIODIC; + break; + case HPET_DPI: + v = readq(&timer->hpet_config); + if ((v & Tn_PER_INT_CAP_MASK) == 0) { + err = -ENXIO; + break; + } + if (devp->hd_flags & HPET_PERIODIC && + readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) { + v = readq(&timer->hpet_config); + v ^= Tn_TYPE_CNF_MASK; + writeq(v, &timer->hpet_config); + } + devp->hd_flags &= ~HPET_PERIODIC; + break; + case HPET_IRQFREQ: + if (!kernel && (arg > hpet_max_freq) && + !capable(CAP_SYS_RESOURCE)) { + err = -EACCES; + break; + } + + if (arg & (arg - 1)) { + err = -EINVAL; + break; + } + + devp->hd_ireqfreq = hpet_time_div(hpetp->hp_period * arg); + } + + return err; +} + +static struct file_operations hpet_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = hpet_read, + .poll = hpet_poll, + .ioctl = hpet_ioctl, + .open = hpet_open, + .release = hpet_release, + .fasync = hpet_fasync, + .mmap = hpet_mmap, +}; + +EXPORT_SYMBOL(hpet_alloc); +EXPORT_SYMBOL(hpet_register); +EXPORT_SYMBOL(hpet_unregister); +EXPORT_SYMBOL(hpet_control); + +int hpet_register(struct hpet_task *tp, int periodic) +{ + unsigned int i; + u64 mask; + struct hpet_timer *timer; + struct hpet_dev *devp; + struct hpets *hpetp; + + switch (periodic) { + case 1: + mask = Tn_PER_INT_CAP_MASK; + break; + case 0: + mask = 0; + break; + default: + return -EINVAL; + } + + spin_lock_irq(&hpet_task_lock); + spin_lock(&hpet_lock); + + for (devp = 0, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) + for (timer = hpetp->hp_hpet->hpet_timers, i = 0; + i < hpetp->hp_ntimer; i++, timer++) { + if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK) + != mask) + continue; + + devp = &hpetp->hp_dev[i]; + + if (devp->hd_flags & HPET_OPEN || devp->hd_task) { + devp = 0; + continue; + } + + tp->ht_opaque = devp; + devp->hd_task = tp; + break; + } + + spin_unlock(&hpet_lock); + spin_unlock_irq(&hpet_task_lock); + + if (tp->ht_opaque) + return 0; + else + return -EBUSY; +} + +static inline int hpet_tpcheck(struct hpet_task *tp) +{ + struct hpet_dev *devp; + struct hpets *hpetp; + + devp = tp->ht_opaque; + + if (!devp) + return -ENXIO; + + for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) + if (devp >= hpetp->hp_dev + && devp < (hpetp->hp_dev + hpetp->hp_ntimer) + && devp->hd_hpet == hpetp->hp_hpet) + return 0; + + return -ENXIO; +} + +int hpet_unregister(struct hpet_task *tp) +{ + struct hpet_dev *devp; + struct hpet_timer *timer; + int err; + + if ((err = hpet_tpcheck(tp))) + return err; + + spin_lock_irq(&hpet_task_lock); + spin_lock(&hpet_lock); + + devp = tp->ht_opaque; + if (devp->hd_task != tp) { + spin_unlock(&hpet_lock); + spin_unlock_irq(&hpet_task_lock); + return -ENXIO; + } + + timer = devp->hd_timer; + writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK), + &timer->hpet_config); + devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC); + devp->hd_task = 0; + spin_unlock(&hpet_lock); + spin_unlock_irq(&hpet_task_lock); + + return 0; +} + +int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) +{ + struct hpet_dev *devp; + int err; + + if ((err = hpet_tpcheck(tp))) + return err; + + spin_lock_irq(&hpet_lock); + devp = tp->ht_opaque; + if (devp->hd_task != tp) { + spin_unlock_irq(&hpet_lock); + return -ENXIO; + } + spin_unlock_irq(&hpet_lock); + return hpet_ioctl_common(devp, cmd, arg, 1); +} + +#ifdef CONFIG_TIME_INTERPOLATION + +static unsigned long hpet_offset, last_wall_hpet; +static long hpet_nsecs_per_cycle, hpet_cycles_per_sec; + +static unsigned long hpet_getoffset(void) +{ + return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) - + last_wall_hpet) * hpet_nsecs_per_cycle; +} + +static void hpet_update(long delta) +{ + unsigned long mc; + unsigned long offset; + + mc = read_counter(&hpets->hp_hpet->hpet_mc); + offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle; + + if (delta < 0 || (unsigned long)delta < offset) + hpet_offset = offset - delta; + else + hpet_offset = 0; + last_wall_hpet = mc; +} + +static void hpet_reset(void) +{ + hpet_offset = 0; + last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc); +} + +static struct time_interpolator hpet_interpolator = { + .get_offset = hpet_getoffset, + .update = hpet_update, + .reset = hpet_reset +}; + +#endif + +static ctl_table hpet_table[] = { + { + .ctl_name = 1, + .procname = "max-user-freq", + .data = &hpet_max_freq, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + {.ctl_name = 0} +}; + +static ctl_table hpet_root[] = { + { + .ctl_name = 1, + .procname = "hpet", + .maxlen = 0, + .mode = 0555, + .child = hpet_table, + }, + {.ctl_name = 0} +}; + +static ctl_table dev_root[] = { + { + .ctl_name = CTL_DEV, + .procname = "dev", + .maxlen = 0, + .mode = 0555, + .child = hpet_root, + }, + {.ctl_name = 0} +}; + +static struct ctl_table_header *sysctl_header; + +static void *hpet_start(struct seq_file *s, loff_t * pos) +{ + struct hpets *hpetp; + loff_t n; + + for (n = *pos, hpetp = hpets; hpetp; hpetp = hpetp->hp_next) + if (!n--) + return hpetp; + + return 0; +} + +static void *hpet_next(struct seq_file *s, void *v, loff_t * pos) +{ + struct hpets *hpetp; + + hpetp = v; + ++*pos; + return hpetp->hp_next; +} + +static void hpet_stop(struct seq_file *s, void *v) +{ + return; +} + +static int hpet_show(struct seq_file *s, void *v) +{ + struct hpets *hpetp; + struct hpet *hpet; + u64 cap, vendor, period; + + hpetp = v; + hpet = hpetp->hp_hpet; + + cap = readq(&hpet->hpet_cap); + period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> + HPET_COUNTER_CLK_PERIOD_SHIFT; + vendor = (cap & HPET_VENDOR_ID_MASK) >> HPET_VENDOR_ID_SHIFT; + + seq_printf(s, + "HPET%d period = %d 10**-15 vendor = 0x%x number timer = %d\n", + hpetp->hp_which, (u32) period, (u32) vendor, + hpetp->hp_ntimer); + + return 0; +} + +static struct seq_operations hpet_seq_ops = { + .start = hpet_start, + .next = hpet_next, + .stop = hpet_stop, + .show = hpet_show +}; + +static int hpet_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &hpet_seq_ops); +} + +static struct file_operations hpet_proc_fops = { + .open = hpet_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +/* + * Adjustment for when arming the timer with + * initial conditions. That is, main counter + * ticks expired before interrupts are enabled. + */ +#define TICK_CALIBRATE (1000UL) + +static unsigned long __init hpet_calibrate(struct hpets *hpetp) +{ + struct hpet_timer *timer; + unsigned long t, m, count, i, flags, start; + struct hpet_dev *devp; + int j; + struct hpet *hpet; + + for (timer = 0, j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer; + j++, devp++) + if ((devp->hd_flags & HPET_OPEN) == 0) { + timer = devp->hd_timer; + break; + } + + if (!timer) + return 0; + + hpet = hpets->hp_hpet; + t = read_counter(&timer->hpet_compare); + + i = 0; + count = hpet_time_div(hpetp->hp_period * TICK_CALIBRATE); + + local_irq_save(flags); + + start = read_counter(&hpet->hpet_mc); + + do { + m = read_counter(&hpet->hpet_mc); + write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); + } while (i++, (m - start) < count); + + local_irq_restore(flags); + + return (m - start) / i; +} + +int __init hpet_alloc(struct hpet_data *hdp) +{ + u64 cap, mcfg; + struct hpet_dev *devp; + u32 i, ntimer; + struct hpets *hpetp; + size_t siz; + struct hpet *hpet; + static struct hpets *last __initdata = (struct hpets *)0; + + /* + * hpet_alloc can be called by platform dependent code. + * if platform dependent code has allocated the hpet + * ACPI also reports hpet, then we catch it here. + */ + for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) + if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + return 0; + + siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) * + sizeof(struct hpet_dev)); + + hpetp = kmalloc(siz, GFP_KERNEL); + + if (!hpetp) + return -ENOMEM; + + memset(hpetp, 0, siz); + + hpetp->hp_which = hpet_nhpet++; + hpetp->hp_hpet = (struct hpet *)hdp->hd_address; + + hpetp->hp_ntimer = hdp->hd_nirqs; + + for (i = 0; i < hdp->hd_nirqs; i++) + hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; + + hpet = hpetp->hp_hpet; + + cap = readq(&hpet->hpet_cap); + + ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1; + + if (hpetp->hp_ntimer != ntimer) { + printk(KERN_WARNING "hpet: number irqs doesn't agree" + " with number of timers\n"); + kfree(hpetp); + return -ENODEV; + } + + if (last) + last->hp_next = hpetp; + else + hpets = hpetp; + + last = hpetp; + + hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> + HPET_COUNTER_CLK_PERIOD_SHIFT; + + mcfg = readq(&hpet->hpet_config); + if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { + write_counter(0L, &hpet->hpet_mc); + mcfg |= HPET_ENABLE_CNF_MASK; + writeq(mcfg, &hpet->hpet_config); + } + + for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; + i++, hpet_ntimer++, devp++) { + unsigned long v; + struct hpet_timer *timer; + + timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; + v = readq(&timer->hpet_config); + + devp->hd_hpets = hpetp; + devp->hd_hpet = hpet; + devp->hd_timer = timer; + + /* + * If the timer was reserved by platform code, + * then make timer unavailable for opens. + */ + if (hdp->hd_state & (1 << i)) { + devp->hd_flags = HPET_OPEN; + continue; + } + + init_waitqueue_head(&devp->hd_waitqueue); + } + + hpetp->hp_delta = hpet_calibrate(hpetp); + + return 0; +} + +static acpi_status __init hpet_resources(struct acpi_resource *res, void *data) +{ + struct hpet_data *hdp; + acpi_status status; + struct acpi_resource_address64 addr; + struct hpets *hpetp; + + hdp = data; + + status = acpi_resource_to_address64(res, &addr); + + if (ACPI_SUCCESS(status)) { + unsigned long size; + + size = addr.max_address_range - addr.min_address_range + 1; + hdp->hd_address = + (unsigned long)ioremap(addr.min_address_range, size); + + for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) + if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address)) + return -EBUSY; + } else if (res->id == ACPI_RSTYPE_EXT_IRQ) { + struct acpi_resource_ext_irq *irqp; + int i; + + irqp = &res->data.extended_irq; + + if (irqp->number_of_interrupts > 0) { + hdp->hd_nirqs = irqp->number_of_interrupts; + + for (i = 0; i < hdp->hd_nirqs; i++) +#ifdef CONFIG_IA64 + hdp->hd_irq[i] = + acpi_register_gsi(irqp->interrupts[i], + irqp->edge_level, + irqp->active_high_low); +#else + hdp->hd_irq[i] = irqp->interrupts[i]; +#endif + } + } + + return AE_OK; +} + +static int __init hpet_acpi_add(struct acpi_device *device) +{ + acpi_status result; + struct hpet_data data; + + memset(&data, 0, sizeof(data)); + + result = + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + hpet_resources, &data); + + if (ACPI_FAILURE(result)) + return -ENODEV; + + if (!data.hd_address || !data.hd_nirqs) { + printk("%s: no address or irqs in _CRS\n", __FUNCTION__); + return -ENODEV; + } + + return hpet_alloc(&data); +} + +static int __init hpet_acpi_remove(struct acpi_device *device, int type) +{ + return 0; +} + +static struct acpi_driver hpet_acpi_driver __initdata = { + .name = "hpet", + .class = "", + .ids = "PNP0103", + .ops = { + .add = hpet_acpi_add, + .remove = hpet_acpi_remove, + }, +}; + +static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops }; + +static int __init hpet_init(void) +{ + struct proc_dir_entry *entry; + + (void)acpi_bus_register_driver(&hpet_acpi_driver); + + if (hpets) { + if (misc_register(&hpet_misc)) + return -ENODEV; + + entry = create_proc_entry("driver/hpet", 0, 0); + + if (entry) + entry->proc_fops = &hpet_proc_fops; + + sysctl_header = register_sysctl_table(dev_root, 0); + +#ifdef CONFIG_TIME_INTERPOLATION + { + struct hpet *hpet; + + hpet = hpets->hp_hpet; + hpet_cycles_per_sec = hpet_time_div(hpets->hp_period); + hpet_interpolator.frequency = hpet_cycles_per_sec; + hpet_interpolator.drift = hpet_cycles_per_sec * + HPET_DRIFT / 1000000; + hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec; + register_time_interpolator(&hpet_interpolator); + } +#endif + return 0; + } else + return -ENODEV; +} + +static void __exit hpet_exit(void) +{ + acpi_bus_unregister_driver(&hpet_acpi_driver); + + if (hpets) { + unregister_sysctl_table(sysctl_header); + remove_proc_entry("driver/hpet", NULL); + } + + return; +} + +module_init(hpet_init); +module_exit(hpet_exit); +MODULE_AUTHOR("Bob Picco "); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 6110dbf40..a1c9cd056 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -225,8 +225,8 @@ static void lp_error (int minor) polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE; if (polling) lp_release_parport (&lp_table[minor]); - interruptible_sleep_on_timeout (&lp_table[minor].waitq, - LP_TIMEOUT_POLLED); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(LP_TIMEOUT_POLLED); if (polling) lp_claim_parport_or_block (&lp_table[minor]); else parport_yield_blocking (lp_table[minor].dev); } @@ -291,7 +291,7 @@ static int lp_wait_ready(int minor, int nonblock) return error; } -static ssize_t lp_write(struct file * file, const char __user * buf, +static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { unsigned int minor = iminor(file->f_dentry->d_inode); @@ -407,7 +407,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, #ifdef CONFIG_PARPORT_1284 /* Status readback conforming to ieee1284 */ -static ssize_t lp_read(struct file * file, char __user * buf, +static ssize_t lp_read(struct file * file, char * buf, size_t count, loff_t *ppos) { unsigned int minor=iminor(file->f_dentry->d_inode); @@ -560,7 +560,6 @@ static int lp_ioctl(struct inode *inode, struct file *file, unsigned int minor = iminor(inode); int status; int retval = 0; - void __user *argp = (void __user *)arg; #ifdef LP_DEBUG printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); @@ -604,7 +603,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, return -EINVAL; break; case LPGETIRQ: - if (copy_to_user(argp, &LP_IRQ(minor), + if (copy_to_user((int *) arg, &LP_IRQ(minor), sizeof(int))) return -EFAULT; break; @@ -613,7 +612,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, status = r_str(minor); lp_release_parport (&lp_table[minor]); - if (copy_to_user(argp, &status, sizeof(int))) + if (copy_to_user((int *) arg, &status, sizeof(int))) return -EFAULT; break; case LPRESET: @@ -621,7 +620,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, break; #ifdef LP_STATS case LPGETSTATS: - if (copy_to_user(argp, &LP_STAT(minor), + if (copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats))) return -EFAULT; if (capable(CAP_SYS_ADMIN)) @@ -631,12 +630,13 @@ static int lp_ioctl(struct inode *inode, struct file *file, #endif case LPGETFLAGS: status = LP_F(minor); - if (copy_to_user(argp, &status, sizeof(int))) + if (copy_to_user((int *) arg, &status, sizeof(int))) return -EFAULT; break; case LPSETTIMEOUT: - if (copy_from_user (&par_timeout, argp, + if (copy_from_user (&par_timeout, + (struct timeval *) arg, sizeof (struct timeval))) { return -EFAULT; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 50a32d17e..d0b4d4d0f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -115,6 +115,34 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t *count) } #endif +extern int page_is_ram(unsigned long pagenr); + +static inline int page_is_allowed(unsigned long pagenr) +{ + #ifdef CONFIG_X86 + if (pagenr <= 256) + return 1; + if (!page_is_ram(pagenr)) + return 1; + printk("Access to 0x%lx by %s denied \n", pagenr << PAGE_SHIFT, current->comm); + return 0; + #else + return 1; + #endif +} + +static inline int range_is_allowed(unsigned long from, unsigned long to) +{ + unsigned long cursor; + + cursor = from >> PAGE_SHIFT; + while ( (cursor << PAGE_SHIFT) < to) { + if (!page_is_allowed(cursor)) + return 0; + cursor++; + } + return 1; +} static ssize_t do_write_mem(void *p, unsigned long realp, const char __user * buf, size_t count, loff_t *ppos) { @@ -134,6 +162,8 @@ static ssize_t do_write_mem(void *p, unsigned long realp, written+=sz; } #endif + if (!range_is_allowed(realp, realp+count)) + return -EFAULT; copied = copy_from_user(p, buf, count); if (copied) { ssize_t ret = written + (count - copied); @@ -177,6 +207,8 @@ static ssize_t read_mem(struct file * file, char __user * buf, } } #endif + if (!range_is_allowed(p, p+count)) + return -EFAULT; if (copy_to_user(buf, __va(p), count)) return -EFAULT; read += count; @@ -198,6 +230,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int uncached; + unsigned long cursor; uncached = uncached_access(file, offset); #ifdef pgprot_noncached @@ -213,6 +246,13 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) */ if (uncached) vma->vm_flags |= VM_IO; + + cursor = vma->vm_pgoff; + while ((cursor << PAGE_SHIFT) < offset + vma->vm_end-vma->vm_start) { + if (!page_is_allowed(cursor)) + return -EFAULT; + cursor++; + } if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) @@ -233,6 +273,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, ssize_t read = 0; ssize_t virtr = 0; char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ + + return -EPERM; if (p < (unsigned long) high_memory) { read = count; @@ -297,6 +339,8 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, ssize_t virtr = 0; ssize_t written; char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ + + return -EPERM; if (p < (unsigned long) high_memory) { diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 5eda075c6..56ae1f09d 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -103,7 +103,7 @@ static inline void pp_enable_irq (struct pp_struct *pp) port->ops->enable_irq (port); } -static ssize_t pp_read (struct file * file, char __user * buf, size_t count, +static ssize_t pp_read (struct file * file, char * buf, size_t count, loff_t * ppos) { unsigned int minor = iminor(file->f_dentry->d_inode); @@ -186,8 +186,8 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count, return bytes_read; } -static ssize_t pp_write (struct file * file, const char __user * buf, - size_t count, loff_t * ppos) +static ssize_t pp_write (struct file * file, const char * buf, size_t count, + loff_t * ppos) { unsigned int minor = iminor(file->f_dentry->d_inode); struct pp_struct *pp = file->private_data; @@ -335,7 +335,6 @@ static int pp_ioctl(struct inode *inode, struct file *file, unsigned int minor = iminor(inode); struct pp_struct *pp = file->private_data; struct parport * port; - void __user *argp = (void __user *)arg; /* First handle the cases that don't take arguments. */ switch (cmd) { @@ -397,7 +396,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, case PPSETMODE: { int mode; - if (copy_from_user (&mode, argp, sizeof (mode))) + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; /* FIXME: validate mode */ pp->state.mode = mode; @@ -419,7 +418,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, } else { mode = pp->state.mode; } - if (copy_to_user (argp, &mode, sizeof (mode))) { + if (copy_to_user ((int *)arg, &mode, sizeof (mode))) { return -EFAULT; } return 0; @@ -427,7 +426,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, case PPSETPHASE: { int phase; - if (copy_from_user (&phase, argp, sizeof (phase))) { + if (copy_from_user (&phase, (int *) arg, sizeof (phase))) { return -EFAULT; } /* FIXME: validate phase */ @@ -448,7 +447,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, } else { phase = pp->state.phase; } - if (copy_to_user (argp, &phase, sizeof (phase))) { + if (copy_to_user ((int *)arg, &phase, sizeof (phase))) { return -EFAULT; } return 0; @@ -462,7 +461,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, return -ENODEV; modes = port->modes; - if (copy_to_user (argp, &modes, sizeof (modes))) { + if (copy_to_user ((unsigned int *)arg, &modes, sizeof (modes))) { return -EFAULT; } return 0; @@ -471,7 +470,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, { int uflags; - if (copy_from_user (&uflags, argp, sizeof (uflags))) { + if (copy_from_user (&uflags, (int *)arg, sizeof (uflags))) { return -EFAULT; } pp->flags &= ~PP_FLAGMASK; @@ -483,7 +482,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, int uflags; uflags = pp->flags & PP_FLAGMASK; - if (copy_to_user (argp, &uflags, sizeof (uflags))) { + if (copy_to_user ((int *)arg, &uflags, sizeof (uflags))) { return -EFAULT; } return 0; @@ -510,17 +509,17 @@ static int pp_ioctl(struct inode *inode, struct file *file, case PPRSTATUS: reg = parport_read_status (port); - if (copy_to_user (argp, ®, sizeof (reg))) + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) return -EFAULT; return 0; case PPRDATA: reg = parport_read_data (port); - if (copy_to_user (argp, ®, sizeof (reg))) + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) return -EFAULT; return 0; case PPRCONTROL: reg = parport_read_control (port); - if (copy_to_user (argp, ®, sizeof (reg))) + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) return -EFAULT; return 0; case PPYIELD: @@ -539,29 +538,29 @@ static int pp_ioctl(struct inode *inode, struct file *file, return 0; case PPWCONTROL: - if (copy_from_user (®, argp, sizeof (reg))) + if (copy_from_user (®, (unsigned char *) arg, sizeof (reg))) return -EFAULT; parport_write_control (port, reg); return 0; case PPWDATA: - if (copy_from_user (®, argp, sizeof (reg))) + if (copy_from_user (®, (unsigned char *) arg, sizeof (reg))) return -EFAULT; parport_write_data (port, reg); return 0; case PPFCONTROL: - if (copy_from_user (&mask, argp, + if (copy_from_user (&mask, (unsigned char *) arg, sizeof (mask))) return -EFAULT; - if (copy_from_user (®, 1 + (unsigned char __user *) arg, + if (copy_from_user (®, 1 + (unsigned char *) arg, sizeof (reg))) return -EFAULT; parport_frob_control (port, mask, reg); return 0; case PPDATADIR: - if (copy_from_user (&mode, argp, sizeof (mode))) + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; if (mode) port->ops->data_reverse (port); @@ -570,7 +569,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, return 0; case PPNEGOT: - if (copy_from_user (&mode, argp, sizeof (mode))) + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; switch ((ret = parport_negotiate (port, mode))) { case 0: break; @@ -585,7 +584,8 @@ static int pp_ioctl(struct inode *inode, struct file *file, return ret; case PPWCTLONIRQ: - if (copy_from_user (®, argp, sizeof (reg))) + if (copy_from_user (®, (unsigned char *) arg, + sizeof (reg))) return -EFAULT; /* Remember what to set the control lines to, for next @@ -596,13 +596,14 @@ static int pp_ioctl(struct inode *inode, struct file *file, case PPCLRIRQ: ret = atomic_read (&pp->irqc); - if (copy_to_user (argp, &ret, sizeof (ret))) + if (copy_to_user ((int *) arg, &ret, sizeof (ret))) return -EFAULT; atomic_sub (ret, &pp->irqc); return 0; case PPSETTIME: - if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) { + if (copy_from_user (&par_timeout, (struct timeval *)arg, + sizeof(struct timeval))) { return -EFAULT; } /* Convert to jiffies, place in pp->pdev->timeout */ @@ -621,8 +622,10 @@ static int pp_ioctl(struct inode *inode, struct file *file, to_jiffies = pp->pdev->timeout; par_timeout.tv_sec = to_jiffies / HZ; par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ); - if (copy_to_user (argp, &par_timeout, sizeof(struct timeval))) + if (copy_to_user ((struct timeval *)arg, &par_timeout, + sizeof(struct timeval))) { return -EFAULT; + } return 0; default: diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c deleted file mode 100644 index d3894a6f9..000000000 --- a/drivers/char/sh-sci.c +++ /dev/null @@ -1,1646 +0,0 @@ -/* $Id: sh-sci.c,v 1.16 2004/02/10 17:04:17 lethal Exp $ - * - * linux/drivers/char/sh-sci.c - * - * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2000 Sugioka Toshinobu - * Modified to support multiple serial ports. Stuart Menefy (May 2000). - * Modified to support SH7760 SCIF. Paul Mundt (Oct 2003). - * Modified to support H8/300 Series. Yoshinori Sato (Feb 2004). - * - * TTY code is based on sx.c (Specialix SX driver) by: - * - * (C) 1998 R.E.Wolff@BitWizard.nl - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SH_KGDB_CONSOLE) -#include -#endif -#ifdef CONFIG_CPU_FREQ -#include -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_SH_STANDARD_BIOS -#include -#endif - -#include "sh-sci.h" - -#ifdef CONFIG_SH_KGDB -#include - -int kgdb_sci_setup(void); -static int kgdb_get_char(struct sci_port *port); -static void kgdb_put_char(struct sci_port *port, char c); -static void kgdb_handle_error(struct sci_port *port); -static struct sci_port *kgdb_sci_port; - -#ifdef CONFIG_SH_KGDB_CONSOLE -static struct console kgdbcons; -void __init kgdb_console_init(void); -#endif /* CONFIG_SH_KGDB_CONSOLE */ - -#endif /* CONFIG_SH_KGDB */ - -#ifdef CONFIG_SERIAL_CONSOLE -static struct console sercons; -static struct sci_port* sercons_port=0; -static int sercons_baud; -#ifdef CONFIG_MAGIC_SYSRQ -#include -static int break_pressed; -#endif /* CONFIG_MAGIC_SYSRQ */ -#endif /* CONFIG_SERIAL_CONSOLE */ - -/* Function prototypes */ -static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag); -#ifndef SCI_ONLY -static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag); -#if defined(CONFIG_CPU_SH3) -static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag); -#endif -#endif -static void sci_disable_tx_interrupts(void *ptr); -static void sci_enable_tx_interrupts(void *ptr); -static void sci_disable_rx_interrupts(void *ptr); -static void sci_enable_rx_interrupts(void *ptr); -static int sci_get_CD(void *ptr); -static void sci_shutdown_port(void *ptr); -static int sci_set_real_termios(void *ptr); -static void sci_hungup(void *ptr); -static void sci_close(void *ptr); -static int sci_chars_in_buffer(void *ptr); -static int sci_request_irq(struct sci_port *port); -static void sci_free_irq(struct sci_port *port); -static int sci_init_drivers(void); - -static struct tty_driver *sci_driver; - -static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT; - -static int sci_debug = 0; - -#ifdef MODULE -MODULE_PARM(sci_debug, "i"); -#endif - -#define dprintk(x...) do { if (sci_debug) printk(x); } while(0) - -#ifdef CONFIG_SERIAL_CONSOLE -static void put_char(struct sci_port *port, char c) -{ - unsigned long flags; - unsigned short status; - - local_irq_save(flags); - - do - status = sci_in(port, SCxSR); - while (!(status & SCxSR_TDxE(port))); - - sci_out(port, SCxTDR, c); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - - local_irq_restore(flags); -} -#endif - -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - -static void handle_error(struct sci_port *port) -{ /* Clear error flags */ - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); -} - -static int get_char(struct sci_port *port) -{ - unsigned long flags; - unsigned short status; - int c; - - local_irq_save(flags); - do { - status = sci_in(port, SCxSR); - if (status & SCxSR_ERRORS(port)) { - handle_error(port); - continue; - } - } while (!(status & SCxSR_RDxF(port))); - c = sci_in(port, SCxRDR); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - local_irq_restore(flags); - - return c; -} - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; - -static __inline__ char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static __inline__ char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ - -/* - * Send the packet in buffer. The host gets one chance to read it. - * This routine does not wait for a positive acknowledge. - */ - -#ifdef CONFIG_SERIAL_CONSOLE -static void put_string(struct sci_port *port, const char *buffer, int count) -{ - int i; - const unsigned char *p = buffer; - -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - int checksum; - int usegdb=0; - -#ifdef CONFIG_SH_STANDARD_BIOS - /* This call only does a trap the first time it is - * called, and so is safe to do here unconditionally - */ - usegdb |= sh_bios_in_gdb_mode(); -#endif -#ifdef CONFIG_SH_KGDB - usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); -#endif - - if (usegdb) { - /* $#. */ - do { - unsigned char c; - put_char(port, '$'); - put_char(port, 'O'); /* 'O'utput to console */ - checksum = 'O'; - - for (i=0; ibase - SMR0) >> 3; - /* set DDR regs */ - H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT); - H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT); - /* tx mark output*/ - H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; -} - -#if defined(__H8300S__) -enum {sci_disable,sci_enable}; - -static void h8300_sci_enable(struct sci_port* port, unsigned int ctrl) -{ - volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL; - int ch = (port->base - SMR0) >> 3; - unsigned char mask = 1 << (ch+1); - if (ctrl == sci_disable) - *mstpcrl |= mask; - else - *mstpcrl &= ~mask; -} -#endif -#endif - -static void sci_setsignals(struct sci_port *port, int dtr, int rts) -{ - /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ - /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ - /* If you have signals for DTR and DCD, please implement here. */ - ; -} - -static int sci_getsignals(struct sci_port *port) -{ - /* This routine is used for geting signals of: DTR, DCD, DSR, RI, - and CTS/RTS */ - - return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR; -/* - (((o_stat & OP_DTR)?TIOCM_DTR:0) | - ((o_stat & OP_RTS)?TIOCM_RTS:0) | - ((i_stat & IP_CTS)?TIOCM_CTS:0) | - ((i_stat & IP_DCD)?TIOCM_CAR:0) | - ((i_stat & IP_DSR)?TIOCM_DSR:0) | - ((i_stat & IP_RI) ?TIOCM_RNG:0) -*/ -} - -static void sci_set_baud(struct sci_port *port, int baud) -{ - int t; - - switch (baud) { - case 0: - t = -1; - break; - case 2400: - t = BPS_2400; - break; - case 4800: - t = BPS_4800; - break; - case 9600: - t = BPS_9600; - break; - case 19200: - t = BPS_19200; - break; - case 38400: - t = BPS_38400; - break; - case 57600: - t = BPS_57600; - break; - default: - printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud); - case 115200: - t = BPS_115200; - break; - } - - if (t > 0) { - sci_setsignals (port, 1, -1); - if(t >= 256) { - sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); - t >>= 2; - } else { - sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); - } - sci_out(port, SCBRR, t); - udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ - } else { - sci_setsignals (port, 0, -1); - } -} - -static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud) -{ - unsigned int status; - unsigned int smr_val; - - do - status = sci_in(port, SCxSR); - while (!(status & SCxSR_TEND(port))); - - sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ - -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { - sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); - } -#endif - - smr_val = sci_in(port, SCSMR) & 3; - if ((cflag & CSIZE) == CS7) - smr_val |= 0x40; - if (cflag & PARENB) - smr_val |= 0x20; - if (cflag & PARODD) - smr_val |= 0x30; - if (cflag & CSTOPB) - smr_val |= 0x08; - sci_out(port, SCSMR, smr_val); - sci_set_baud(port, baud); - - port->init_pins(port, cflag); - sci_out(port, SCSCR, SCSCR_INIT(port)); -} - -static int sci_set_real_termios(void *ptr) -{ - struct sci_port *port = ptr; - - if (port->old_cflag != port->gs.tty->termios->c_cflag) { - port->old_cflag = port->gs.tty->termios->c_cflag; - sci_set_termios_cflag(port, port->old_cflag, port->gs.baud); - sci_enable_rx_interrupts(port); - } - - return 0; -} - -/* ********************************************************************** * - * the interrupt related routines * - * ********************************************************************** */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static inline void sci_sched_event(struct sci_port *port, int event) -{ - port->event |= 1 << event; - schedule_work(&port->tqueue); -} - -static void sci_transmit_chars(struct sci_port *port) -{ - int count, i; - int txroom; - unsigned long flags; - unsigned short status; - unsigned short ctrl; - unsigned char c; - - status = sci_in(port, SCxSR); - if (!(status & SCxSR_TDxE(port))) { - local_irq_save(flags); - ctrl = sci_in(port, SCSCR); - if (port->gs.xmit_cnt == 0) { - ctrl &= ~SCI_CTRL_FLAGS_TIE; - port->gs.flags &= ~GS_TX_INTEN; - } else - ctrl |= SCI_CTRL_FLAGS_TIE; - sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); - return; - } - - while (1) { - count = port->gs.xmit_cnt; -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { - txroom = 16 - (sci_in(port, SCFDR)>>8); - } else { - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; - } -#else - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; -#endif - if (count > txroom) - count = txroom; - - /* Don't copy past the end of the source buffer */ - if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail) - count = SERIAL_XMIT_SIZE - port->gs.xmit_tail; - - /* If for one reason or another, we can't copy more data, we're done! */ - if (count == 0) - break; - - for (i=0; igs.xmit_buf[port->gs.xmit_tail + i]; - sci_out(port, SCxTDR, c); - } - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - - port->icount.tx += count; - - /* Update the kernel buffer end */ - port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); - - /* This one last. (this is essential) - It would allow others to start putting more data into the buffer! */ - port->gs.xmit_cnt -= count; - } - - if (port->gs.xmit_cnt <= port->gs.wakeup_chars) - sci_sched_event(port, SCI_EVENT_WRITE_WAKEUP); - - local_irq_save(flags); - ctrl = sci_in(port, SCSCR); - if (port->gs.xmit_cnt == 0) { - ctrl &= ~SCI_CTRL_FLAGS_TIE; - port->gs.flags &= ~GS_TX_INTEN; - } else { -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - } -#endif - ctrl |= SCI_CTRL_FLAGS_TIE; - } - sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); -} - -/* On SH3, SCIF may read end-of-break as a space->mark char */ -#define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); }) - -static inline void sci_receive_chars(struct sci_port *port, - struct pt_regs *regs) -{ - int i, count; - struct tty_struct *tty; - int copied=0; - unsigned short status; - - status = sci_in(port, SCxSR); - if (!(status & SCxSR_RDxF(port))) - return; - - tty = port->gs.tty; - while (1) { -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { - count = sci_in(port, SCFDR)&0x001f; - } else { - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; - } -#else - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; -#endif - - /* Don't copy more bytes than there is room for in the buffer */ - if (tty->flip.count + count > TTY_FLIPBUF_SIZE) - count = TTY_FLIPBUF_SIZE - tty->flip.count; - - /* If for any reason we can't copy more data, we're done! */ - if (count == 0) - break; - - if (port->type == PORT_SCI) { - tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR); - tty->flip.flag_buf_ptr[0] = TTY_NORMAL; - } else { - for (i=0; ibreak_flag) { - if ((c == 0) && - (status & SCxSR_FER(port))) { - count--; i--; - continue; - } - /* Nonzero => end-of-break */ - dprintk("scif: debounce<%02x>\n", c); - port->break_flag = 0; - if (STEPFN(c)) { - count--; i--; - continue; - } - } -#endif /* __SH3__ */ -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (break_pressed && (port == sercons_port)) { - if (c != 0 && - time_before(jiffies, - break_pressed + HZ*5)) { - handle_sysrq(c, regs, NULL); - break_pressed = 0; - count--; i--; - continue; - } else if (c != 0) { - break_pressed = 0; - } - } -#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ - - /* Store data and status */ - tty->flip.char_buf_ptr[i] = c; - if (status&SCxSR_FER(port)) { - tty->flip.flag_buf_ptr[i] = TTY_FRAME; - dprintk("sci: frame error\n"); - } else if (status&SCxSR_PER(port)) { - tty->flip.flag_buf_ptr[i] = TTY_PARITY; - dprintk("sci: parity error\n"); - } else { - tty->flip.flag_buf_ptr[i] = TTY_NORMAL; - } - } - } - - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - - /* Update the kernel buffer end */ - tty->flip.count += count; - tty->flip.char_buf_ptr += count; - tty->flip.flag_buf_ptr += count; - - copied += count; - port->icount.rx += count; - } - - if (copied) - /* Tell the rest of the system the news. New characters! */ - tty_flip_buffer_push(tty); - else { - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } -} - -static inline int sci_handle_errors(struct sci_port *port) -{ - int copied = 0; - unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->gs.tty; - - if (status&SCxSR_ORER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; - dprintk("sci: overrun error\n"); - } - - if (status&SCxSR_FER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_BREAK; - dprintk("sci: BREAK detected\n"); - } - else { - /* frame error */ - copied++; - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - dprintk("sci: frame error\n"); - } - } - - if (status&SCxSR_PER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_PARITY; - dprintk("sci: parity error\n"); - } - - if (copied) { - tty->flip.count += copied; - tty_flip_buffer_push(tty); - } - - return copied; -} - -static inline int sci_handle_breaks(struct sci_port *port) -{ - int copied = 0; - unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->gs.tty; - - if (status&SCxSR_BRK(port) && tty->flip.countbreak_flag) - goto break_continue; - port->break_flag = 1; -#endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (port == sercons_port) { - if (break_pressed == 0) { - break_pressed = jiffies; - dprintk("sci: implied sysrq\n"); - goto break_continue; - } - /* Double break implies a real break */ - break_pressed = 0; - } -#endif - /* Notify of BREAK */ - copied++; - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - dprintk("sci: BREAK detected\n"); - } - break_continue: - -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) || \ - defined(CONFIG_CPU_SUBTYPE_SH7760) - /* XXX: Handle SCIF overrun error */ - if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { - sci_out(port, SCLSR, 0); - if(tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; - dprintk("sci: overrun error\n"); - } - } -#endif - - if (copied) { - tty->flip.count += copied; - tty_flip_buffer_push(tty); - } - - return copied; -} - -static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - - if (port->gs.flags & GS_ACTIVE) - if (!(port->gs.flags & SCI_RX_THROTTLE)) { - sci_receive_chars(port, regs); - return IRQ_HANDLED; - - } - sci_disable_rx_interrupts(port); - - return IRQ_HANDLED; -} - -static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - - if (port->gs.flags & GS_ACTIVE) - sci_transmit_chars(port); - else { - sci_disable_tx_interrupts(port); - } - - return IRQ_HANDLED; -} - -static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - - /* Handle errors */ - if (port->type == PORT_SCI) { - if(sci_handle_errors(port)) { - /* discard character in rx buffer */ - sci_in(port, SCxSR); - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } - } - else - sci_rx_interrupt(irq, ptr, regs); - - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); - - /* Kick the transmission */ - sci_tx_interrupt(irq, ptr, regs); - - return IRQ_HANDLED; -} - -#if !defined(SCI_ONLY) -static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - - /* Handle BREAKs */ - sci_handle_breaks(port); - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); - - return IRQ_HANDLED; -} -#endif - -static void do_softint(void *private_) -{ - struct sci_port *port = (struct sci_port *) private_; - struct tty_struct *tty; - - tty = port->gs.tty; - if (!tty) - return; - - if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } -} - -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the generic_serial driver * - * ********************************************************************** */ - -static void sci_disable_tx_interrupts(void *ptr) -{ - struct sci_port *port = ptr; - unsigned long flags; - unsigned short ctrl; - - /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); - ctrl = sci_in(port, SCSCR); - ctrl &= ~SCI_CTRL_FLAGS_TIE; - sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); -} - -static void sci_enable_tx_interrupts(void *ptr) -{ - struct sci_port *port = ptr; - - disable_irq(port->irqs[SCIx_TXI_IRQ]); - sci_transmit_chars(port); - enable_irq(port->irqs[SCIx_TXI_IRQ]); -} - -static void sci_disable_rx_interrupts(void * ptr) -{ - struct sci_port *port = ptr; - unsigned long flags; - unsigned short ctrl; - - /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); - ctrl = sci_in(port, SCSCR); - ctrl &= ~SCI_CTRL_FLAGS_RIE; - sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); -} - -static void sci_enable_rx_interrupts(void * ptr) -{ - struct sci_port *port = ptr; - unsigned long flags; - unsigned short ctrl; - - /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); - ctrl = sci_in(port, SCSCR); - ctrl |= SCI_CTRL_FLAGS_RIE; - sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); -} - -static int sci_get_CD(void * ptr) -{ - /* If you have signal for CD (Carrier Detect), please change here. */ - return 1; -} - -static int sci_chars_in_buffer(void * ptr) -{ - struct sci_port *port = ptr; - -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { - return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1); - } else { - return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1; - } -#else - return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1; -#endif -} - -static void sci_shutdown_port(void * ptr) -{ - struct sci_port *port = ptr; - - port->gs.flags &= ~ GS_ACTIVE; - if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) - sci_setsignals(port, 0, 0); - sci_free_irq(port); -#if defined(__H8300S__) - h8300_sci_enable(port,sci_disable); -#endif -} - -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ - -static int sci_open(struct tty_struct * tty, struct file * filp) -{ - struct sci_port *port; - int retval, line; - - line = tty->index; - - if ((line < 0) || (line >= SCI_NPORTS)) - return -ENODEV; - - port = &sci_ports[line]; - - tty->driver_data = port; - port->gs.tty = tty; - port->gs.count++; - - port->event = 0; - INIT_WORK(&port->tqueue, do_softint, port); - -#if defined(__H8300S__) - h8300_sci_enable(port,sci_enable); -#endif - - /* - * Start up serial port - */ - retval = gs_init_port(&port->gs); - if (retval) { - goto failed_1; - } - - port->gs.flags |= GS_ACTIVE; - sci_setsignals(port, 1,1); - - if (port->gs.count == 1) { - retval = sci_request_irq(port); - } - - retval = gs_block_til_ready(port, filp); - - if (retval) { - goto failed_3; - } - -#ifdef CONFIG_SERIAL_CONSOLE - if (sercons.cflag && sercons.index == line) { - tty->termios->c_cflag = sercons.cflag; - port->gs.baud = sercons_baud; - sercons.cflag = 0; - sci_set_real_termios(port); - } -#endif - -#ifdef CONFIG_SH_KGDB_CONSOLE - if (kgdbcons.cflag && kgdbcons.index == line) { - tty->termios->c_cflag = kgdbcons.cflag; - port->gs.baud = kgdb_baud; - sercons.cflag = 0; - sci_set_real_termios(port); - } -#endif - - sci_enable_rx_interrupts(port); - - return 0; - -failed_3: - sci_free_irq(port); -failed_1: - port->gs.count--; - return retval; -} - -static void sci_hungup(void *ptr) -{ - return; -} - -static void sci_close(void *ptr) -{ - return; -} - -static int sci_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct sci_port *port = tty->driver_data; - return sci_getsignals(port); -} - -static int sci_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct sci_port *port = tty->driver_data; - int rts = -1, dtr = -1; - - if (set & TIOCM_RTS) - rts = 1; - if (set & TIOCM_DTR) - dtr = 1; - if (clear & TIOCM_RTS) - rts = 0; - if (clear & TIOCM_DTR) - dtr = 0; - - sci_setsignals(port, dtr, rts); - return 0; -} - -static int sci_ioctl(struct tty_struct * tty, struct file * filp, - unsigned int cmd, unsigned long arg) -{ - int rc; - struct sci_port *port = tty->driver_data; - int ival; - - rc = 0; - switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned int __user *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = get_user(ival, (unsigned int __user *) arg)) == 0) - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void __user *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_getserial(&port->gs, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void __user *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, - (struct serial_struct *) arg); - break; - default: - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static void sci_throttle(struct tty_struct * tty) -{ - struct sci_port *port = (struct sci_port *)tty->driver_data; - - /* If the port is using any type of input flow - * control then throttle the port. - */ - if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) - port->gs.flags |= SCI_RX_THROTTLE; -} - -static void sci_unthrottle(struct tty_struct * tty) -{ - struct sci_port *port = (struct sci_port *)tty->driver_data; - - /* Always unthrottle even if flow control is not enabled on - * this port in case we disabled flow control while the port - * was throttled - */ - port->gs.flags &= ~SCI_RX_THROTTLE; - sci_enable_rx_interrupts(port); - return; -} - -#ifdef CONFIG_PROC_FS -static int sci_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i; - struct sci_port *port; - int len = 0; - - len += sprintf(page, "sciinfo:0.1\n"); - for (i = 0; i < SCI_NPORTS && len < 4000; i++) { - port = &sci_ports[i]; - len += sprintf(page+len, "%d: uart:%s address: %08x", i, - (port->type == PORT_SCI) ? "SCI" : "SCIF", - port->base); - len += sprintf(page+len, " baud:%d", port->gs.baud); - len += sprintf(page+len, " tx:%d rx:%d", - port->icount.tx, port->icount.rx); - - if (port->icount.frame) - len += sprintf(page+len, " fe:%d", port->icount.frame); - if (port->icount.parity) - len += sprintf(page+len, " pe:%d", port->icount.parity); - if (port->icount.brk) - len += sprintf(page+len, " brk:%d", port->icount.brk); - if (port->icount.overrun) - len += sprintf(page+len, " oe:%d", port->icount.overrun); - len += sprintf(page+len, "\n"); - } - return len; -} -#endif - -#ifdef CONFIG_CPU_FREQ -/* - * Here we define a transistion notifier so that we can update all of our - * ports' baud rate when the peripheral clock changes. - */ - -static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) -{ - struct cpufreq_freqs *freqs = p; - int i; - - if (phase == CPUFREQ_POSTCHANGE) { - for (i = 0; i < SCI_NPORTS; i++) { - /* - * This will force a baud rate change in hardware. - */ - if (sci_ports[i].gs.tty != NULL) { - sci_set_baud(&sci_ports[i], sci_ports[i].gs.baud); - } - } - printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n", - __FUNCTION__, freqs->cpu, freqs->old, freqs->new); - } - - return NOTIFY_OK; -} - -static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; -#endif /* CONFIG_CPU_FREQ */ - -static struct tty_operations sci_ops = { - .open = sci_open, - .close = gs_close, - .write = gs_write, - .put_char = gs_put_char, - .flush_chars = gs_flush_chars, - .write_room = gs_write_room, - .chars_in_buffer = gs_chars_in_buffer, - .flush_buffer = gs_flush_buffer, - .ioctl = sci_ioctl, - .throttle = sci_throttle, - .unthrottle = sci_unthrottle, - .set_termios = gs_set_termios, - .stop = gs_stop, - .start = gs_start, - .hangup = gs_hangup, -#ifdef CONFIG_PROC_FS - .read_proc = sci_read_proc, -#endif - .tiocmget = sci_tiocmget, - .tiocmset = sci_tiocmset, -}; - -/* ********************************************************************** * - * Here are the initialization routines. * - * ********************************************************************** */ - -static int sci_init_drivers(void) -{ - int error; - struct sci_port *port; - sci_driver = alloc_tty_driver(SCI_NPORTS); - if (!sci_driver) - return -ENOMEM; - - sci_driver->owner = THIS_MODULE; - sci_driver->driver_name = "sci"; - sci_driver->name = "ttySC"; - sci_driver->devfs_name = "ttsc/"; - sci_driver->major = SCI_MAJOR; - sci_driver->minor_start = SCI_MINOR_START; - sci_driver->type = TTY_DRIVER_TYPE_SERIAL; - sci_driver->subtype = SERIAL_TYPE_NORMAL; - sci_driver->init_termios = tty_std_termios; - sci_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; - sci_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(sci_driver, &sci_ops); - if ((error = tty_register_driver(sci_driver))) { - printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n", - error); - put_tty_driver(sci_driver); - return 1; - } - - for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) { - port->gs.magic = SCI_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &sci_real_driver; - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - port->old_cflag = 0; - port->icount.cts = port->icount.dsr = - port->icount.rng = port->icount.dcd = 0; - port->icount.rx = port->icount.tx = 0; - port->icount.frame = port->icount.parity = 0; - port->icount.overrun = port->icount.brk = 0; - } - -#ifdef CONFIG_CPU_FREQ - /* Setup transition notifier */ - if (cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER) < 0) { - printk(KERN_ERR "sci: Unable to register CPU frequency notifier\n"); - return 1; - } - printk("sci: CPU frequency notifier registered\n"); -#endif - return 0; -} - -static int sci_request_irq(struct sci_port *port) -{ - int i; -#if !defined(SCI_ONLY) - irqreturn_t (*handlers[4])(int irq, void *p, struct pt_regs *regs) = { - sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, - sci_br_interrupt, - }; -#else - void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = { - sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, - }; -#endif - for (i=0; i<(sizeof(handlers)/sizeof(handlers[0])); i++) { - if (!port->irqs[i]) continue; - if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, - "sci", port)) { - printk(KERN_ERR "sci: Cannot allocate irq.\n"); - return -ENODEV; - } - } - return 0; -} - -static void sci_free_irq(struct sci_port *port) -{ - int i; - - for (i=0; i<4; i++) { - if (!port->irqs[i]) continue; - free_irq(port->irqs[i], port); - } -} - -static char banner[] __initdata = - KERN_INFO "SuperH SCI(F) driver initialized\n"; - -int __init sci_init(void) -{ - struct sci_port *port; - int j; - - printk("%s", banner); - - for (j=0; jbase, - (port->type == PORT_SCI) ? "SCI" : "SCIF"); - } - - sci_init_drivers(); - -#ifdef CONFIG_SH_STANDARD_BIOS - sh_bios_gdb_detach(); -#endif - return 0; /* Return -EIO when not detected */ -} - -module_init(sci_init); - -#ifdef MODULE -#undef func_enter -#undef func_exit - -void cleanup_module(void) -{ - tty_unregister_driver(sci_driver); - put_tty_driver(sci_driver); -} - -#include "generic_serial.c" -#endif - -#ifdef CONFIG_SERIAL_CONSOLE -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void serial_console_write(struct console *co, const char *s, - unsigned count) -{ - put_string(sercons_port, s, count); -} - -static struct tty_driver *serial_console_device(struct console *c, int *index) -{ - *index = c->index; - return sci_driver; -} - -/* - * Setup initial baud/bits/parity. We do two things here: - * - construct a cflag setting for the first rs_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init serial_console_setup(struct console *co, char *options) -{ - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - char *s; - - sercons_port = &sci_ports[co->index]; - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while(*s >= '0' && *s <= '9') - s++; - if (*s) parity = *s++; - if (*s) bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch (baud) { - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - case 9600: - default: - cflag |= B9600; - baud = 9600; - break; - } - switch (bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; - } - switch (parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; - } - - co->cflag = cflag; - sercons_baud = baud; - -#if defined(__H8300S__) - h8300_sci_enable(sercons_port,sci_enable); -#endif - sci_set_termios_cflag(sercons_port, cflag, baud); - sercons_port->old_cflag = cflag; - - return 0; -} - -static struct console sercons = { - .name = "ttySC", - .write = serial_console_write, - .device = serial_console_device, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* - * Register console. - */ - -#ifdef CONFIG_SH_EARLY_PRINTK -extern void sh_console_unregister (void); -#endif - -static int __init sci_console_init(void) -{ - register_console(&sercons); -#ifdef CONFIG_SH_EARLY_PRINTK - /* Now that the real console is available, unregister the one we - * used while first booting. - */ - sh_console_unregister(); -#endif - return 0; -} -console_initcall(sci_console_init); - -#endif /* CONFIG_SERIAL_CONSOLE */ - - -#ifdef CONFIG_SH_KGDB - -/* Initialise the KGDB serial port */ -int kgdb_sci_setup(void) -{ - int cflag = CREAD | HUPCL | CLOCAL; - - if ((kgdb_portnum < 0) || (kgdb_portnum >= SCI_NPORTS)) - return -1; - - kgdb_sci_port = &sci_ports[kgdb_portnum]; - - switch (kgdb_baud) { - case 115200: - cflag |= B115200; - break; - case 57600: - cflag |= B57600; - break; - case 38400: - cflag |= B38400; - break; - case 19200: - cflag |= B19200; - break; - case 9600: - default: - cflag |= B9600; - kgdb_baud = 9600; - break; - } - - switch (kgdb_bits) { - case '7': - cflag |= CS7; - break; - default: - case '8': - cflag |= CS8; - break; - } - - switch (kgdb_parity) { - case 'O': - cflag |= PARODD; - break; - case 'E': - cflag |= PARENB; - break; - } - - kgdb_cflag = cflag; - sci_set_termios_cflag(kgdb_sci_port, kgdb_cflag, kgdb_baud); - - /* Set up the interrupt for BREAK from GDB */ - /* Commented out for now since it may not be possible yet... - request_irq(kgdb_sci_port->irqs[0], kgdb_break_interrupt, - SA_INTERRUPT, "sci", kgdb_sci_port); - sci_enable_rx_interrupts(kgdb_sci_port); - */ - - /* Setup complete: initialize function pointers */ - kgdb_getchar = kgdb_sci_getchar; - kgdb_putchar = kgdb_sci_putchar; - - return 0; -} - -#ifdef CONFIG_SH_KGDB_CONSOLE - -/* Create a console device */ -static kdev_t kgdb_console_device(struct console *c) -{ - return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); -} - -/* Set up the KGDB console */ -static int __init kgdb_console_setup(struct console *co, char *options) -{ - /* NB we ignore 'options' because we've already done the setup */ - co->cflag = kgdb_cflag; - - return 0; -} - -/* Register the KGDB console so we get messages (d'oh!) */ -void __init kgdb_console_init(void) -{ - register_console(&kgdbcons); -} - -/* The console structure for KGDB */ -static struct console kgdbcons = { - name:"ttySC", - write:kgdb_console_write, - device:kgdb_console_device, - wait_key:serial_console_wait_key, - setup:kgdb_console_setup, - flags:CON_PRINTBUFFER | CON_ENABLED, - index:-1, -}; - -#endif /* CONFIG_SH_KGDB_CONSOLE */ - -#endif /* CONFIG_SH_KGDB */ diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h deleted file mode 100644 index 5d07cd107..000000000 --- a/drivers/char/sh-sci.h +++ /dev/null @@ -1,478 +0,0 @@ -/* $Id: sh-sci.h,v 1.7 2004/02/10 17:04:17 lethal Exp $ - * - * linux/drivers/char/sh-sci.h - * - * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2000 Greg Banks - * Modified to support multiple serial ports. Stuart Menefy (May 2000). - * Modified to support SH7760 SCIF. Paul Mundt (Oct 2003). - * Modified to support H8/300 Serise Yoshinori Sato (Feb 2004). - * - */ -#include - -#if defined(__H8300H__) || defined(__H8300S__) -#include -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) -#include -#endif -#if defined(CONFIG_H8S2678) -#include -#endif -#endif - -/* Values for sci_port->type */ -#define PORT_SCI 0 -#define PORT_SCIF 1 -#define PORT_IRDA 1 /* XXX: temporary assignment */ - -/* Offsets into the sci_port->irqs array */ -#define SCIx_ERI_IRQ 0 -#define SCIx_RXI_IRQ 1 -#define SCIx_TXI_IRQ 2 - -/* ERI, RXI, TXI, BRI */ -#define SCI_IRQS { 23, 24, 25, 0 } -#define SH3_SCIF_IRQS { 56, 57, 59, 58 } -#define SH3_IRDA_IRQS { 52, 53, 55, 54 } -#define SH4_SCIF_IRQS { 40, 41, 43, 42 } -#define STB1_SCIF1_IRQS {23, 24, 26, 25 } -#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 } -#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 } -#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 } -#define H8300H_SCI_IRQS0 {52, 53, 54, 0 } -#define H8300H_SCI_IRQS1 {56, 57, 58, 0 } -#define H8300H_SCI_IRQS2 {60, 61, 62, 0 } -#define H8S_SCI_IRQS0 {88, 89, 90, 0 } -#define H8S_SCI_IRQS1 {92, 93, 94, 0 } -#define H8S_SCI_IRQS2 {96, 97, 98, 0 } - -#if defined(CONFIG_CPU_SUBTYPE_SH7708) -# define SCI_NPORTS 1 -# define SCI_INIT { \ - { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci } \ -} -# define SCSPTR 0xffffff7c /* 8 bit */ -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define SCI_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -# define SCI_NPORTS 3 -# define SCI_INIT { \ - { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \ - { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif }, \ - { {}, PORT_SCIF, 0xA4000140, SH3_IRDA_IRQS, sci_init_pins_irda } \ -} -# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ -# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define SCI_AND_SCIF -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) -# define SCI_NPORTS 2 -# define SCI_INIT { \ - { {}, PORT_SCI, 0xffe00000, SCI_IRQS, sci_init_pins_sci }, \ - { {}, PORT_SCIF, 0xFFE80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ -} -# define SCSPTR1 0xffe0001c /* 8 bit SCI */ -# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ - 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ - 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) -# define SCI_AND_SCIF -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -# define SCI_NPORTS 3 -# define SCI_INIT { \ - { {}, PORT_SCIF, 0xfe600000, SH7760_SCIF0_IRQS, sci_init_pins_scif }, \ - { {}, PORT_SCIF, 0xfe610000, SH7760_SCIF1_IRQS, sci_init_pins_scif }, \ - { {}, PORT_SCIF, 0xfe620000, SH7760_SCIF2_IRQS, sci_init_pins_scif } \ -} -# define SCSPTR0 0xfe600024 /* 16 bit SCIF */ -# define SCSPTR1 0xfe610024 /* 16 bit SCIF */ -# define SCSPTR2 0xfe620024 /* 16 bit SCIF */ -# define SCIF_ORDER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -# define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) -# define SCI_NPORTS 2 -# define SCI_INIT { \ - { {}, PORT_SCIF, 0xffe00000, STB1_SCIF1_IRQS, sci_init_pins_scif }, \ - { {}, PORT_SCIF, 0xffe80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ -} -# define SCSPTR1 0xffe00020 /* 16 bit SCIF */ -# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -# define SCIF_ONLY -#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) -# define SCI_NPORTS 3 -# define SCI_INIT { \ - { {}, PORT_SCI, 0x00ffffb0, H8300H_SCI_IRQS0, sci_init_pins_sci }, \ - { {}, PORT_SCI, 0x00ffffb8, H8300H_SCI_IRQS1, sci_init_pins_sci }, \ - { {}, PORT_SCI, 0x00ffffc0, H8300H_SCI_IRQS2, sci_init_pins_sci } \ -} -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define SCI_ONLY -# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) -#elif defined(CONFIG_H8S2678) -# define SCI_NPORTS 3 -# define SCI_INIT { \ - { {}, PORT_SCI, 0x00ffff78, H8S_SCI_IRQS0, sci_init_pins_sci }, \ - { {}, PORT_SCI, 0x00ffff80, H8S_SCI_IRQS1, sci_init_pins_sci }, \ - { {}, PORT_SCI, 0x00ffff88, H8S_SCI_IRQS2, sci_init_pins_sci } \ -} -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define SCI_ONLY -# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) -#else -# error CPU subtype not defined -#endif - -/* SCSCR */ -#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ -#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ -#define SCI_CTRL_FLAGS_TE 0x20 /* all */ -#define SCI_CTRL_FLAGS_RE 0x10 /* all */ -/* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */ -/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ -/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ - -/* SCxSR SCI */ -#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ - -#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) - -/* SCxSR SCIF */ -#define SCIF_ER 0x0080 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_TEND 0x0040 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_TDFE 0x0020 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_BRK 0x0010 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_FER 0x0008 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_PER 0x0004 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_RDF 0x0002 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_DR 0x0001 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ - -#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) - -#if defined(SCI_ONLY) -# define SCxSR_TEND(port) SCI_TEND -# define SCxSR_ERRORS(port) SCI_ERRORS -# define SCxSR_RDxF(port) SCI_RDRF -# define SCxSR_TDxE(port) SCI_TDRE -# define SCxSR_ORER(port) SCI_ORER -# define SCxSR_FER(port) SCI_FER -# define SCxSR_PER(port) SCI_PER -# define SCxSR_BRK(port) 0x00 -# define SCxSR_RDxF_CLEAR(port) 0xbc -# define SCxSR_ERROR_CLEAR(port) 0xc4 -# define SCxSR_TDxE_CLEAR(port) 0x78 -# define SCxSR_BREAK_CLEAR(port) 0xc4 -#elif defined(SCIF_ONLY) -# define SCxSR_TEND(port) SCIF_TEND -# define SCxSR_ERRORS(port) SCIF_ERRORS -# define SCxSR_RDxF(port) SCIF_RDF -# define SCxSR_TDxE(port) SCIF_TDFE -# define SCxSR_ORER(port) 0x0000 -# define SCxSR_FER(port) SCIF_FER -# define SCxSR_PER(port) SCIF_PER -# define SCxSR_BRK(port) SCIF_BRK -# define SCxSR_RDxF_CLEAR(port) 0x00fc -# define SCxSR_ERROR_CLEAR(port) 0x0073 -# define SCxSR_TDxE_CLEAR(port) 0x00df -# define SCxSR_BREAK_CLEAR(port) 0x00e3 -#else -# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) -# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) -# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) -# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) -# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000) -# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) -# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) -# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) -# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) -# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) -#endif - -/* SCFCR */ -#define SCFCR_RFRST 0x0002 -#define SCFCR_TFRST 0x0004 -#define SCFCR_MCE 0x0008 - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 - -/* Generic serial flags */ -#define SCI_RX_THROTTLE 0x0000001 - -#define SCI_MAGIC 0xbabeface - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define SCI_EVENT_WRITE_WAKEUP 0 - -struct sci_port { - struct gs_port gs; - int type; - unsigned int base; - unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */ - void (*init_pins)(struct sci_port* port, unsigned int cflag); - unsigned int old_cflag; - struct async_icount icount; - struct work_struct tqueue; - unsigned long event; - int break_flag; -}; - -#define SCI_IN(size, offset) \ - unsigned int addr = port->base + (offset); \ - if ((size) == 8) { \ - return ctrl_inb(addr); \ - } else { \ - return ctrl_inw(addr); \ - } -#define SCI_OUT(size, offset, value) \ - unsigned int addr = port->base + (offset); \ - if ((size) == 8) { \ - ctrl_outb(value, addr); \ - } else { \ - ctrl_outw(value, addr); \ - } - -#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ - static inline unsigned int sci_##name##_in(struct sci_port* port) \ - { \ - if (port->type == PORT_SCI) { \ - SCI_IN(sci_size, sci_offset) \ - } else { \ - SCI_IN(scif_size, scif_offset); \ - } \ - } \ - static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ - { \ - if (port->type == PORT_SCI) { \ - SCI_OUT(sci_size, sci_offset, value) \ - } else { \ - SCI_OUT(scif_size, scif_offset, value); \ - } \ - } - -#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ - static inline unsigned int sci_##name##_in(struct sci_port* port) \ - { \ - SCI_IN(scif_size, scif_offset); \ - } \ - static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ - { \ - SCI_OUT(scif_size, scif_offset, value); \ - } - -#define CPU_SCI_FNS(name, sci_offset, sci_size) \ - static inline unsigned int sci_##name##_in(struct sci_port* port) \ - { \ - SCI_IN(sci_size, sci_offset); \ - } \ - static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ - { \ - SCI_OUT(sci_size, sci_offset, value); \ - } - -#ifdef CONFIG_CPU_SH3 -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) -#elif defined(__H8300H__) || defined(__H8300S__) -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) -#else -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#endif - -/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ -/* name off sz off sz off sz off sz off sz*/ -SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8) -SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8) -SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8) -SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) -SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) -SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) -SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) -SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) -SCIF_FNS(SCLSR, 0, 0, 0x24, 16) - -#define sci_in(port, reg) sci_##reg##_in(port) -#define sci_out(port, reg, value) sci_##reg##_out(port, value) - -/* H8/300 series SCI pins assignment */ -#if defined(__H8300H__) || defined(__H8300S__) -static const struct __attribute__((packed)) -{ - int port; /* GPIO port no */ - unsigned short rx,tx; /* GPIO bit no */ -} h8300_sci_pins[] = -{ -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) - { /* SCI0 */ - .port = H8300_GPIO_P9, - .rx = H8300_GPIO_B2, - .tx = H8300_GPIO_B0, - }, - { /* SCI1 */ - .port = H8300_GPIO_P9, - .rx = H8300_GPIO_B3, - .tx = H8300_GPIO_B1, - }, - { /* SCI2 */ - .port = H8300_GPIO_PB, - .rx = H8300_GPIO_B7, - .tx = H8300_GPIO_B6, - } -#elif defined(CONFIG_H8S2678) - { /* SCI0 */ - .port = H8300_GPIO_P3, - .rx = H8300_GPIO_B2, - .tx = H8300_GPIO_B0, - }, - { /* SCI1 */ - .port = H8300_GPIO_P3, - .rx = H8300_GPIO_B3, - .tx = H8300_GPIO_B1, - }, - { /* SCI2 */ - .port = H8300_GPIO_P5, - .rx = H8300_GPIO_B1, - .tx = H8300_GPIO_B0, - } -#endif -}; -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7708) -static inline int sci_rxd_in(struct sci_port *port) -{ - if (port->base == 0xfffffe80) - return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -static inline int sci_rxd_in(struct sci_port *port) -{ - if (port->base == 0xfffffe80) - return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */ - if (port->base == 0xa4000150) - return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ - if (port->base == 0xa4000140) - return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) -static inline int sci_rxd_in(struct sci_port *port) -{ -#ifndef SCIF_ONLY - if (port->base == 0xffe00000) - return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ -#endif -#ifndef SCI_ONLY - if (port->base == 0xffe80000) - return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ -#endif - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -static inline int sci_rxd_in(struct sci_port *port) -{ - if (port->base == 0xfe600000) - return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->base == 0xfe610000) - return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ - if (port->base == 0xfe620000) - return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ -} -#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) -static inline int sci_rxd_in(struct sci_port *port) -{ - if (port->base == 0xffe00000) - return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */ - else - return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ - -} -#elif defined(__H8300H__) || defined(__H8300S__) -static inline int sci_rxd_in(struct sci_port *port) -{ - int ch = (port->base - SMR0) >> 3; - return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; -} -#endif - -/* - * Values for the BitRate Register (SCBRR) - * - * The values are actually divisors for a frequency which can - * be internal to the SH3 (14.7456MHz) or derived from an external - * clock source. This driver assumes the internal clock is used; - * to support using an external clock source, config options or - * possibly command-line options would need to be added. - * - * Also, to support speeds below 2400 (why?) the lower 2 bits of - * the SCSMR register would also need to be set to non-zero values. - * - * -- Greg Banks 27Feb2000 - * - * Answer: The SCBRR register is only eight bits, and the value in - * it gets larger with lower baud rates. At around 2400 (depending on - * the peripherial module clock) you run out of bits. However the - * lower two bits of SCSMR allow the module clock to be divided down, - * scaling the value which is needed in SCBRR. - * - * -- Stuart Menefy - 23 May 2000 - * - * I meant, why would anyone bother with bitrates below 2400. - * - * -- Greg Banks - 7Jul2000 - * - * You "speedist"! How will I use my 110bps ASR-33 teletype with paper - * tape reader as a console! - * - * -- Mitch Davis - 15 Jul 2000 - */ - -#define PCLK (current_cpu_data.module_clock) - -#if !defined(__H8300H__) && !defined(__H8300S__) -#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1) -#else -#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) -#endif -#define BPS_2400 SCBRR_VALUE(2400) -#define BPS_4800 SCBRR_VALUE(4800) -#define BPS_9600 SCBRR_VALUE(9600) -#define BPS_19200 SCBRR_VALUE(19200) -#define BPS_38400 SCBRR_VALUE(38400) -#define BPS_57600 SCBRR_VALUE(57600) -#define BPS_115200 SCBRR_VALUE(115200) -#define BPS_230400 SCBRR_VALUE(230400) - diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a7fa79f5b..a6f3510a1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -722,12 +722,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - int retval = -EINVAL; - lock_cpu_hotplug(); - if (cpu_online(policy->cpu)) - retval = cpufreq_driver->target(policy, target_freq, relation); - unlock_cpu_hotplug(); - return retval; + return cpufreq_driver->target(policy, target_freq, relation); } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 510214470..666c71790 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -206,7 +206,7 @@ cpufreq_sysctl(ctl_table *table, int __user *name, int nlen, if (oldlen != sizeof(unsigned int)) return -EINVAL; - if (put_user(cpufreq_get(cpu), (unsigned int __user *)oldval) || + if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) || put_user(sizeof(unsigned int), oldlenp)) return -EFAULT; } @@ -216,7 +216,7 @@ cpufreq_sysctl(ctl_table *table, int __user *name, int nlen, if (newlen != sizeof(unsigned int)) return -EINVAL; - if (get_user(freq, (unsigned int __user *)newval)) + if (get_user(freq, (unsigned int *)newval)) return -EFAULT; cpufreq_set(freq, cpu); diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 40257f7ef..34792880c 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -320,7 +320,7 @@ edd_show_info_flags(struct edd_device *edev, char *buf) } static ssize_t -edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf) +edd_show_legacy_cylinders(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -330,12 +330,12 @@ edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "%u\n", info->legacy_max_cylinder); + p += snprintf(p, left, "0x%x\n", info->legacy_cylinders); return (p - buf); } static ssize_t -edd_show_legacy_max_head(struct edd_device *edev, char *buf) +edd_show_legacy_heads(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -345,12 +345,12 @@ edd_show_legacy_max_head(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "%u\n", info->legacy_max_head); + p += snprintf(p, left, "0x%x\n", info->legacy_heads); return (p - buf); } static ssize_t -edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf) +edd_show_legacy_sectors(struct edd_device *edev, char *buf) { struct edd_info *info; char *p = buf; @@ -360,7 +360,7 @@ edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track); + p += snprintf(p, left, "0x%x\n", info->legacy_sectors); return (p - buf); } @@ -375,7 +375,7 @@ edd_show_default_cylinders(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders); + p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders); return (p - buf); } @@ -390,7 +390,7 @@ edd_show_default_heads(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "%u\n", info->params.num_default_heads); + p += scnprintf(p, left, "0x%x\n", info->params.num_default_heads); return (p - buf); } @@ -405,7 +405,7 @@ edd_show_default_sectors_per_track(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "%u\n", info->params.sectors_per_track); + p += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track); return (p - buf); } @@ -420,7 +420,7 @@ edd_show_sectors(struct edd_device *edev, char *buf) if (!info || !buf) return -EINVAL; - p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors); + p += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors); return (p - buf); } @@ -436,7 +436,7 @@ edd_show_sectors(struct edd_device *edev, char *buf) */ static int -edd_has_legacy_max_cylinder(struct edd_device *edev) +edd_has_legacy_cylinders(struct edd_device *edev) { struct edd_info *info; if (!edev) @@ -444,11 +444,11 @@ edd_has_legacy_max_cylinder(struct edd_device *edev) info = edd_dev_get_info(edev); if (!info) return -EINVAL; - return info->legacy_max_cylinder > 0; + return info->legacy_cylinders > 0; } static int -edd_has_legacy_max_head(struct edd_device *edev) +edd_has_legacy_heads(struct edd_device *edev) { struct edd_info *info; if (!edev) @@ -456,11 +456,11 @@ edd_has_legacy_max_head(struct edd_device *edev) info = edd_dev_get_info(edev); if (!info) return -EINVAL; - return info->legacy_max_head > 0; + return info->legacy_heads > 0; } static int -edd_has_legacy_sectors_per_track(struct edd_device *edev) +edd_has_legacy_sectors(struct edd_device *edev) { struct edd_info *info; if (!edev) @@ -468,7 +468,7 @@ edd_has_legacy_sectors_per_track(struct edd_device *edev) info = edd_dev_get_info(edev); if (!info) return -EINVAL; - return info->legacy_sectors_per_track > 0; + return info->legacy_sectors > 0; } static int @@ -555,14 +555,12 @@ static EDD_DEVICE_ATTR(version, 0444, edd_show_version, NULL); static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL); static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL); static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL); -static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444, - edd_show_legacy_max_cylinder, - edd_has_legacy_max_cylinder); -static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head, - edd_has_legacy_max_head); -static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444, - edd_show_legacy_sectors_per_track, - edd_has_legacy_sectors_per_track); +static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders, + edd_has_legacy_cylinders); +static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads, + edd_has_legacy_heads); +static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors, + edd_has_legacy_sectors); static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders, edd_has_default_cylinders); static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads, @@ -589,9 +587,9 @@ static struct attribute * def_attrs[] = { /* These attributes are conditional and only added for some devices. */ static struct edd_attribute * edd_attrs[] = { - &edd_attr_legacy_max_cylinder, - &edd_attr_legacy_max_head, - &edd_attr_legacy_sectors_per_track, + &edd_attr_legacy_cylinders, + &edd_attr_legacy_heads, + &edd_attr_legacy_sectors, &edd_attr_default_cylinders, &edd_attr_default_heads, &edd_attr_default_sectors_per_track, diff --git a/drivers/i2c/busses/i2c-ixp42x.c b/drivers/i2c/busses/i2c-ixp42x.c deleted file mode 100644 index 59fcb70fd..000000000 --- a/drivers/i2c/busses/i2c-ixp42x.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * drivers/i2c/i2c-adap-ixp42x.c - * - * Intel's IXP42x XScale NPU chipsets (IXP420, 421, 422, 425) do not have - * an on board I2C controller but provide 16 GPIO pins that are often - * used to create an I2C bus. This driver provides an i2c_adapter - * interface that plugs in under algo_bit and drives the GPIO pins - * as instructed by the alogorithm driver. - * - * Author: Deepak Saxena - * - * Copyright (c) 2003-2004 MontaVista Software Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * - * NOTE: Since different platforms will use different GPIO pins for - * I2C, this driver uses an IXP42x-specific platform_data - * pointer to pass the GPIO numbers to the driver. This - * allows us to support all the different IXP42x platforms - * w/o having to put #ifdefs in this driver. - * - * See arch/arm/mach-ixp42x/ixdp425.c for an example of building a - * device list and filling in the ixp42x_i2c_pins data structure - * that is passed as the platform_data to this driver. - */ - -#include -#include -#include -#include -#include -#include - -#include /* Pick up IXP42x-specific bits */ - -static inline int ixp42x_scl_pin(void *data) -{ - return ((struct ixp42x_i2c_pins*)data)->scl_pin; -} - -static inline int ixp42x_sda_pin(void *data) -{ - return ((struct ixp42x_i2c_pins*)data)->sda_pin; -} - -static void ixp42x_bit_setscl(void *data, int val) -{ - gpio_line_set(ixp42x_scl_pin(data), 0); - gpio_line_config(ixp42x_scl_pin(data), - val ? IXP425_GPIO_IN : IXP425_GPIO_OUT ); -} - -static void ixp42x_bit_setsda(void *data, int val) -{ - gpio_line_set(ixp42x_sda_pin(data), 0); - gpio_line_config(ixp42x_sda_pin(data), - val ? IXP425_GPIO_IN : IXP425_GPIO_OUT ); -} - -static int ixp42x_bit_getscl(void *data) -{ - int scl; - - gpio_line_config(ixp42x_scl_pin(data), IXP425_GPIO_IN ); - gpio_line_get(ixp42x_scl_pin(data), &scl); - - return scl; -} - -static int ixp42x_bit_getsda(void *data) -{ - int sda; - - gpio_line_config(ixp42x_sda_pin(data), IXP425_GPIO_IN ); - gpio_line_get(ixp42x_sda_pin(data), &sda); - - return sda; -} - -struct ixp42x_i2c_data { - struct ixp42x_i2c_pins *gpio_pins; - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo_data; -}; - -static int ixp42x_i2c_remove(struct device *dev) -{ - struct platform_device *plat_dev = to_platform_device(dev); - struct ixp42x_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev); - - dev_set_drvdata(&plat_dev->dev, NULL); - - i2c_bit_del_bus(&drv_data->adapter); - - kfree(drv_data); - - return 0; -} - -static int ixp42x_i2c_probe(struct device *dev) -{ - int err; - struct platform_device *plat_dev = to_platform_device(dev); - struct ixp42x_i2c_pins *gpio = plat_dev->dev.platform_data; - struct ixp42x_i2c_data *drv_data = - kmalloc(sizeof(struct ixp42x_i2c_data), GFP_KERNEL); - - if(!drv_data) - return -ENOMEM; - - memzero(drv_data, sizeof(struct ixp42x_i2c_data)); - drv_data->gpio_pins = gpio; - - /* - * We could make a lot of these structures static, but - * certain platforms may have multiple GPIO-based I2C - * buses for various device domains, so we need per-device - * algo_data->data. - */ - drv_data->algo_data.data = gpio; - drv_data->algo_data.setsda = ixp42x_bit_setsda; - drv_data->algo_data.setscl = ixp42x_bit_setscl; - drv_data->algo_data.getsda = ixp42x_bit_getsda; - drv_data->algo_data.getscl = ixp42x_bit_getscl; - drv_data->algo_data.udelay = 10; - drv_data->algo_data.mdelay = 10; - drv_data->algo_data.timeout = 100; - - drv_data->adapter.id = I2C_HW_B_IXP425, - drv_data->adapter.algo_data = &drv_data->algo_data, - - drv_data->adapter.dev.parent = &plat_dev->dev; - - gpio_line_config(gpio->scl_pin, IXP425_GPIO_IN); - gpio_line_config(gpio->sda_pin, IXP425_GPIO_IN); - gpio_line_set(gpio->scl_pin, 0); - gpio_line_set(gpio->sda_pin, 0); - - if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) { - printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id); - - kfree(drv_data); - return err; - } - - dev_set_drvdata(&plat_dev->dev, drv_data); - - return 0; -} - -static struct device_driver ixp42x_i2c_driver = { - .name = "IXP42X-I2C", - .bus = &platform_bus_type, - .probe = ixp42x_i2c_probe, - .remove = ixp42x_i2c_remove, -}; - -static int __init ixp42x_i2c_init(void) -{ - return driver_register(&ixp42x_i2c_driver); -} - -static void __exit ixp42x_i2c_exit(void) -{ - driver_unregister(&ixp42x_i2c_driver); -} - -module_init(ixp42x_i2c_init); -module_exit(ixp42x_i2c_exit); - -MODULE_DESCRIPTION("GPIO-based I2C driver for IXP42x systems"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Deepak Saxena "); - diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 91e9282b4..c43ac493d 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -157,6 +157,20 @@ config IDEDISK_MULTI_MODE If in doubt, say N. +config IDEDISK_STROKE + bool "Auto-Geometry Resizing support" + depends on BLK_DEV_IDEDISK + help + Should you have a system w/ an AWARD Bios and your drives are larger + than 32GB and it will not boot, one is required to perform a few OEM + operations first. The option is called "STROKE" because it allows + one to "soft clip" the drive to work around a barrier limit. For + Maxtor drives it is called "jumpon.exe". Please search Maxtor's + web-site for "JUMPON.EXE". IBM has a similar tool at: + . + + If you are unsure, say N here. + config BLK_DEV_IDECS tristate "PCMCIA IDE support" depends on PCMCIA @@ -424,6 +438,48 @@ config BLK_DEV_IDEDMA_PCI if BLK_DEV_IDEDMA_PCI +# TCQ is disabled for now +config BLK_DEV_IDE_TCQ + bool "ATA tagged command queueing (EXPERIMENTAL)" + depends on EXPERIMENTAL && n + help + Support for tagged command queueing on ATA disk drives. This enables + the IDE layer to have multiple in-flight requests on hardware that + supports it. For now this includes the IBM Deskstar series drives, + such as the 22GXP, 75GXP, 40GV, 60GXP, and 120GXP (ie any Deskstar made + in the last couple of years), and at least some of the Western + Digital drives in the Expert series (by nature of really being IBM + drives). + + If you have such a drive, say Y here. + +config BLK_DEV_IDE_TCQ_DEFAULT + bool "TCQ on by default" + depends on BLK_DEV_IDE_TCQ + ---help--- + Enable tagged command queueing unconditionally on drives that report + support for it. Regardless of the chosen value here, tagging can be + controlled at run time: + + echo "using_tcq:32" > /proc/ide/hdX/settings + + where any value between 1-32 selects chosen queue depth and enables + TCQ, and 0 disables it. hdparm version 4.7 an above also support + TCQ manipulations. + + Generally say Y here. + +config BLK_DEV_IDE_TCQ_DEPTH + int "Default queue depth" + depends on BLK_DEV_IDE_TCQ + default "8" + help + Maximum size of commands to enable per-drive. Any value between 1 + and 32 is valid, with 32 being the maxium that the hardware supports. + + You probably just want the default of 32 here. If you enter an invalid + number, the default value will be used. + config BLK_DEV_IDEDMA_FORCED bool "Force enable legacy 2.0.X HOSTS to use DMA" help diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 6f14bbfc3..1bb668b4f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -535,7 +535,9 @@ static void cdrom_prepare_request(struct request *rq) rq->flags = REQ_PC; } -static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, +static void cdrom_queue_request_sense(ide_drive_t *drive, + struct completion *wait, + void *sense, struct request *failed_command) { struct cdrom_info *info = drive->driver_data; @@ -552,6 +554,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, rq->cmd[4] = rq->data_len = 18; rq->flags = REQ_SENSE; + rq->waiting = wait; /* NOTE! Save the failed command in "rq->buffer" */ rq->buffer = (void *) failed_command; @@ -571,7 +574,7 @@ ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat) if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; @@ -605,7 +608,7 @@ ide_startstop_t ide_cdrom_abort (ide_drive_t *drive, const char *msg) if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; @@ -628,21 +631,10 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate) struct request *failed = (struct request *) rq->buffer; struct cdrom_info *info = drive->driver_data; void *sense = &info->sense_data; - unsigned long flags; - - if (failed) { - if (failed->sense) { - sense = failed->sense; - failed->sense_len = rq->sense_len; - } - - /* - * now end failed request - */ - spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, failed->data_len); - end_that_request_last(failed); - spin_unlock_irqrestore(&ide_lock, flags); + + if (failed && failed->sense) { + sense = failed->sense; + failed->sense_len = rq->sense_len; } cdrom_analyze_sense_data(drive, failed, sense); @@ -650,9 +642,6 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate) if (!rq->current_nr_sectors && blk_fs_request(rq)) uptodate = 1; - /* make sure it's fully ended */ - if (blk_pc_request(rq)) - nsectors = (rq->data_len + 511) >> 9; if (!nsectors) nsectors = 1; @@ -695,7 +684,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) { /* All other functions, except for READ. */ - unsigned long flags; + struct completion *wait = NULL; /* * if we have an error, pass back CHECK_CONDITION as the @@ -717,23 +706,30 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) ide_dump_status(drive, "packet command error", stat); } - rq->flags |= REQ_FAILED; + /* Set the error flag and complete the request. + Then, if we have a CHECK CONDITION status, + queue a request sense command. We must be careful, + though: we don't want the thread in + cdrom_queue_packet_command to wake up until + the request sense has completed. We do this + by transferring the semaphore from the packet + command request to the request sense request. */ - /* - * instead of playing games with moving completions around, - * remove failed request completely and end it when the - * request sense has completed - */ - if (stat & ERR_STAT) { - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); + rq->flags |= REQ_FAILED; + if ((stat & ERR_STAT) != 0) { + wait = rq->waiting; + rq->waiting = NULL; + if ((rq->flags & REQ_BLOCK_PC) != 0) { + cdrom_queue_request_sense(drive, wait, + rq->sense, rq); + return 1; /* REQ_BLOCK_PC self-cares */ + } + } - cdrom_queue_request_sense(drive, rq->sense, rq); - } else - cdrom_end_request(drive, 0); + cdrom_end_request(drive, 0); + if ((stat & ERR_STAT) != 0) + cdrom_queue_request_sense(drive, wait, rq->sense, rq); } else if (blk_fs_request(rq)) { int do_end_request = 0; @@ -822,7 +818,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) /* If we got a CHECK_CONDITION status, queue a request sense command. */ if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, NULL, NULL, NULL); } else { blk_dump_rq_flags(rq, "ide-cd: bad rq"); cdrom_end_request(drive, 0); @@ -1670,8 +1666,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) dma_error = HWIF(drive)->ide_dma_end(drive); } - if (cdrom_decode_status(drive, 0, &stat)) + if (cdrom_decode_status(drive, 0, &stat)) { + if ((stat & ERR_STAT) != 0) { + end_that_request_chunk(rq, 0, rq->data_len); + goto end_request; /* purge the whole thing... */ + } + end_that_request_chunk(rq, 1, rq->data_len); return ide_stopped; + } /* * using dma, transfer is complete now diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 9217f0ced..47761a0a5 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -45,8 +45,6 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ -//#define DEBUG - #include #include #include @@ -120,6 +118,20 @@ static int lba_capacity_is_ok (struct hd_driveid *id) return 0; /* lba_capacity value may be bad */ } +static int idedisk_start_tag(ide_drive_t *drive, struct request *rq) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + + if (ata_pending_commands(drive) < drive->queue_depth) + ret = blk_queue_start_tag(drive->queue, rq); + + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} + #ifndef CONFIG_IDE_TASKFILE_IO /* @@ -353,12 +365,18 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector if (drive->addressing == 1) { task_ioreg_t tasklets[10]; - pr_debug("%s: LBA=0x%012llx\n", drive->name, block); + if (blk_rq_tagged(rq)) { + tasklets[0] = nsectors.b.low; + tasklets[1] = nsectors.b.high; + tasklets[2] = rq->tag << 3; + tasklets[3] = 0; + } else { + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = nsectors.b.low; + tasklets[3] = nsectors.b.high; + } - tasklets[0] = 0; - tasklets[1] = 0; - tasklets[2] = nsectors.b.low; - tasklets[3] = nsectors.b.high; tasklets[4] = (task_ioreg_t) block; tasklets[5] = (task_ioreg_t) (block>>8); tasklets[6] = (task_ioreg_t) (block>>16); @@ -371,6 +389,14 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector tasklets[9] = (task_ioreg_t)((u64)block >> 40); } #ifdef DEBUG + printk("%s: %sing: LBAsect=%lu, sectors=%ld, " + "buffer=0x%08lx, LBAsect=0x%012lx\n", + drive->name, + rq_data_dir(rq)==READ?"read":"writ", + block, + rq->nr_sectors, + (unsigned long) rq->buffer, + block); printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", drive->name, tasklets[3], tasklets[2], tasklets[9], tasklets[8], tasklets[7], @@ -389,8 +415,22 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector hwif->OUTB(tasklets[6], IDE_HCYL_REG); hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG); } else { - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); +#ifdef DEBUG + printk("%s: %sing: LBAsect=%llu, sectors=%ld, " + "buffer=0x%08lx\n", + drive->name, + rq_data_dir(rq)==READ?"read":"writ", + (unsigned long long)block, rq->nr_sectors, + (unsigned long) rq->buffer); +#endif + if (blk_rq_tagged(rq)) { + hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG); + hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG); + } else { + hwif->OUTB(0x00, IDE_FEATURE_REG); + hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); + } + hwif->OUTB(block, IDE_SECTOR_REG); hwif->OUTB(block>>=8, IDE_LCYL_REG); hwif->OUTB(block>>=8, IDE_HCYL_REG); @@ -404,16 +444,29 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector head = track % drive->head; cyl = track / drive->head; - pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); + if (blk_rq_tagged(rq)) { + hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG); + hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG); + } else { + hwif->OUTB(0x00, IDE_FEATURE_REG); + hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); + } - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); hwif->OUTB(cyl, IDE_LCYL_REG); hwif->OUTB(cyl>>8, IDE_HCYL_REG); hwif->OUTB(head|drive->select.all,IDE_SELECT_REG); +#ifdef DEBUG + printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n", + drive->name, rq_data_dir(rq)==READ?"read":"writ", cyl, + head, sect, rq->nr_sectors, (unsigned long) rq->buffer); +#endif } if (rq_data_dir(rq) == READ) { +#ifdef CONFIG_BLK_DEV_IDE_TCQ + if (blk_rq_tagged(rq)) + return __ide_dma_queued_read(drive); +#endif if (drive->using_dma && !hwif->ide_dma_read(drive)) return ide_started; @@ -424,7 +477,10 @@ ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector return ide_started; } else { ide_startstop_t startstop; - +#ifdef CONFIG_BLK_DEV_IDE_TCQ + if (blk_rq_tagged(rq)) + return __ide_dma_queued_write(drive); +#endif if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) return ide_started; @@ -494,6 +550,8 @@ static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) if (cmd == READ) { task->command_type = IDE_DRIVE_TASK_IN; + if (drive->using_tcq) + return lba48 ? WIN_READDMA_QUEUED_EXT : WIN_READDMA_QUEUED; if (drive->using_dma) return lba48 ? WIN_READDMA_EXT : WIN_READDMA; if (drive->mult_count) { @@ -504,6 +562,8 @@ static u8 get_command(ide_drive_t *drive, int cmd, ide_task_t *task) return lba48 ? WIN_READ_EXT : WIN_READ; } else { task->command_type = IDE_DRIVE_TASK_RAW_WRITE; + if (drive->using_tcq) + return lba48 ? WIN_WRITEDMA_QUEUED_EXT : WIN_WRITEDMA_QUEUED; if (drive->using_dma) return lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (drive->mult_count) { @@ -529,13 +589,23 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi nsectors.all = (u16) rq->nr_sectors; - pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ"); + printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif memset(&args, 0, sizeof(ide_task_t)); sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors; - args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + if (blk_rq_tagged(rq)) { + args.tfRegister[IDE_FEATURE_OFFSET] = sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3; + } else + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.tfRegister[IDE_SECTOR_OFFSET] = sect; args.tfRegister[IDE_LCYL_OFFSET] = cyl; args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8); @@ -555,11 +625,23 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u nsectors.all = (u16) rq->nr_sectors; +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ"); + printk("LBAsect=%lld, ", block); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + memset(&args, 0, sizeof(ide_task_t)); sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors; - args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + if (blk_rq_tagged(rq)) { + args.tfRegister[IDE_FEATURE_OFFSET] = sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3; + } else + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.tfRegister[IDE_SECTOR_OFFSET] = block; args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); @@ -585,12 +667,27 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u nsectors.all = (u16) rq->nr_sectors; +#ifdef DEBUG + printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ"); + printk("LBAsect=%lld, ", block); + printk("sectors=%ld, ", rq->nr_sectors); + printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); +#endif + memset(&args, 0, sizeof(ide_task_t)); sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors; - args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; - args.hobRegister[IDE_NSECTOR_OFFSET] = sectors >> 8; + if (blk_rq_tagged(rq)) { + args.tfRegister[IDE_FEATURE_OFFSET] = sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3; + args.hobRegister[IDE_FEATURE_OFFSET] = sectors >> 8; + args.hobRegister[IDE_NSECTOR_OFFSET] = 0; + } else { + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.hobRegister[IDE_NSECTOR_OFFSET] = sectors >> 8; + } + args.tfRegister[IDE_SECTOR_OFFSET] = block; /* low lba */ args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ @@ -620,9 +717,12 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s return ide_stopped; } - pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", - drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - block, rq->nr_sectors, (unsigned long)rq->buffer); + if (drive->using_tcq && idedisk_start_tag(drive, rq)) { + if (!ata_pending_commands(drive)) + BUG(); + + return ide_started; + } if (hwif->rw_disk) return hwif->rw_disk(drive, rq, block); @@ -711,6 +811,7 @@ ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat) ide_hwif_t *hwif; struct request *rq; u8 err; + int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; err = idedisk_dump_status(drive, msg, stat); @@ -750,8 +851,22 @@ ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat) rq->errors |= ERROR_RECAL; } } - if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) - try_to_flush_leftover_data(drive); + if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) { + /* + * try_to_flush_leftover_data() is invoked in response to + * a drive unexpectedly having its DRQ_STAT bit set. As + * an alternative to resetting the drive, this routine + * tries to clear the condition by read a sector's worth + * of data from the drive. Of course, this may not help + * if the drive is *waiting* for data from *us*. + */ + while (i > 0) { + u32 buffer[16]; + unsigned int wcount = (i > 16) ? 16 : i; + i -= wcount; + taskfile_input_data(drive, buffer, wcount); + } + } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); @@ -848,6 +963,7 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive return addr; } +#ifdef CONFIG_IDEDISK_STROKE /* * Sets maximum virtual LBA address of the drive. * Returns new maximum virtual LBA address (> 0) or 0 on failure. @@ -916,6 +1032,8 @@ static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsign return addr_set; } +#endif /* CONFIG_IDEDISK_STROKE */ + static unsigned long long sectors_to_MB(unsigned long long n) { n <<= 9; /* make it bytes */ @@ -962,10 +1080,7 @@ static inline void idedisk_check_hpa(ide_drive_t *drive) drive->name, capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - - if (!drive->stroke) - return; - +#ifdef CONFIG_IDEDISK_STROKE if (lba48) set_max = idedisk_set_max_address_ext(drive, set_max); else @@ -975,6 +1090,7 @@ static inline void idedisk_check_hpa(ide_drive_t *drive) printk(KERN_INFO "%s: Host Protected Area disabled.\n", drive->name); } +#endif } /* @@ -1287,6 +1403,34 @@ static int set_acoustic (ide_drive_t *drive, int arg) return 0; } +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static int set_using_tcq(ide_drive_t *drive, int arg) +{ + int ret; + + if (!drive->driver) + return -EPERM; + if (arg == drive->queue_depth && drive->using_tcq) + return 0; + + /* + * set depth, but check also id for max supported depth + */ + drive->queue_depth = arg ? arg : 1; + if (drive->id) { + if (drive->queue_depth > drive->id->queue_depth + 1) + drive->queue_depth = drive->id->queue_depth + 1; + } + + if (arg) + ret = __ide_dma_queued_on(drive); + else + ret = __ide_dma_queued_off(drive); + + return ret ? -EIO : 0; +} +#endif + /* * drive->addressing: * 0: 28-bit @@ -1322,6 +1466,9 @@ static void idedisk_add_settings(ide_drive_t *drive) ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic); ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL); ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); +#ifdef CONFIG_BLK_DEV_IDE_TCQ + ide_add_setting(drive, "using_tcq", SETTING_RW, HDIO_GET_QDMA, HDIO_SET_QDMA, TYPE_BYTE, 0, IDE_MAX_TAG, 1, 1, &drive->using_tcq, set_using_tcq); +#endif } /* @@ -1532,6 +1679,11 @@ static void idedisk_setup (ide_drive_t *drive) drive->wcache = 1; write_cache(drive, 1); + +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT + if (drive->using_dma) + __ide_dma_queued_on(drive); +#endif } static void ide_cacheflush_p(ide_drive_t *drive) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ff5b16a87..37f95e14b 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -97,7 +97,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); - blkdev_dequeue_request(rq); + if (!blk_rq_tagged(rq)) + blkdev_dequeue_request(rq); + else + blk_queue_end_tag(drive->queue, rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; @@ -852,7 +855,18 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) drive->sleep = 0; drive->service_start = jiffies; +queue_next: + if (!ata_can_queue(drive)) { + if (!ata_pending_commands(drive)) + hwgroup->busy = 0; + + break; + } + if (blk_queue_plugged(drive->queue)) { + if (drive->using_tcq) + break; + printk(KERN_ERR "ide: huh? queue was plugged!\n"); break; } @@ -863,7 +877,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) */ rq = elv_next_request(drive->queue); if (!rq) { - hwgroup->busy = 0; + hwgroup->busy = !!ata_pending_commands(drive); break; } @@ -886,6 +900,9 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) break; } + if (!rq->bio && ata_pending_commands(drive)) + break; + hwgroup->rq = rq; /* @@ -905,6 +922,8 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) spin_lock_irq(&ide_lock); if (hwif->irq != masked_irq) enable_irq(hwif->irq); + if (startstop == ide_released) + goto queue_next; if (startstop == ide_stopped) hwgroup->busy = 0; } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 4ffaf9016..ed26518c1 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -241,6 +241,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) drive->media = ide_disk; printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" ); QUIRK_LIST(drive); + + /* Initialize queue depth settings */ + drive->queue_depth = 1; +#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH + drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH; +#else + drive->queue_depth = drive->id->queue_depth + 1; +#endif + if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG) + drive->queue_depth = IDE_MAX_TAG; + return; err_misc: @@ -635,6 +646,8 @@ static void hwif_register (ide_hwif_t *hwif) device_register(&hwif->gendev); } +//EXPORT_SYMBOL(hwif_register); + #ifdef CONFIG_PPC static int wait_hwif_ready(ide_hwif_t *hwif) { @@ -677,7 +690,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif) * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ -static void probe_hwif(ide_hwif_t *hwif) +void probe_hwif (ide_hwif_t *hwif) { unsigned int unit; unsigned long flags; @@ -821,7 +834,9 @@ static void probe_hwif(ide_hwif_t *hwif) } } -static int hwif_init(ide_hwif_t *hwif); +EXPORT_SYMBOL(probe_hwif); + +int hwif_init (ide_hwif_t *hwif); int probe_hwif_init (ide_hwif_t *hwif) { probe_hwif(hwif); @@ -856,7 +871,7 @@ EXPORT_SYMBOL(probe_hwif_init); * * This routine detects and reports such situations, but does not fix them. */ -static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match) +void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match) { ide_hwif_t *m = *match; @@ -869,6 +884,7 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match) if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */ *match = new; } +EXPORT_SYMBOL(save_match); #endif /* MAX_HWIFS > 1 */ /* @@ -1215,7 +1231,9 @@ static void init_gendisk (ide_hwif_t *hwif) THIS_MODULE, ata_probe, ata_lock, hwif); } -static int hwif_init(ide_hwif_t *hwif) +EXPORT_SYMBOL(init_gendisk); + +int hwif_init (ide_hwif_t *hwif) { int old_irq, unit; @@ -1283,6 +1301,8 @@ out: return 0; } +EXPORT_SYMBOL(hwif_init); + int ideprobe_init (void) { unsigned int index; diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 96c8e0021..4b799d01a 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -233,6 +233,27 @@ static int proc_ide_write_config(struct file *file, const char __user *buffer, } #endif /* CONFIG_BLK_DEV_IDEPCI */ } else { /* not pci */ +#if !defined(__mc68000__) && !defined(CONFIG_APUS) + +/* +* Geert Uytterhoeven +* +* unless you can explain me what it really does. +* On m68k, we don't have outw() and outl() yet, +* and I need a good reason to implement it. +* +* BTW, IMHO the main remaining portability problem with the IDE driver +* is that it mixes IO (ioport) and MMIO (iomem) access on different platforms. +* +* I think all accesses should be done using +* +* ide_in[bwl](ide_device_instance, offset) +* ide_out[bwl](ide_device_instance, value, offset) +* +* so the architecture specific code can #define ide_{in,out}[bwl] to the +* appropriate function. +* +*/ switch (r->size) { case 1: hwif->OUTB(val, reg); break; @@ -241,6 +262,7 @@ static int proc_ide_write_config(struct file *file, const char __user *buffer, case 4: hwif->OUTL(val, reg); break; } +#endif /* !__mc68000__ && !CONFIG_APUS */ } } spin_unlock_irqrestore(&ide_lock, flags); @@ -258,7 +280,7 @@ parse_error: goto out1; } -static int proc_ide_read_config +int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { char *out = page; @@ -295,6 +317,8 @@ static int proc_ide_read_config PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +EXPORT_SYMBOL(proc_ide_read_config); + static int proc_ide_read_imodel (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -328,7 +352,9 @@ static int proc_ide_read_imodel PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_mate +EXPORT_SYMBOL(proc_ide_read_imodel); + +int proc_ide_read_mate (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_hwif_t *hwif = (ide_hwif_t *) data; @@ -341,7 +367,9 @@ static int proc_ide_read_mate PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_channel +EXPORT_SYMBOL(proc_ide_read_mate); + +int proc_ide_read_channel (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_hwif_t *hwif = (ide_hwif_t *) data; @@ -353,7 +381,9 @@ static int proc_ide_read_channel PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_identify +EXPORT_SYMBOL(proc_ide_read_channel); + +int proc_ide_read_identify (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *)data; @@ -395,7 +425,9 @@ static int proc_ide_read_identify PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_settings +EXPORT_SYMBOL(proc_ide_read_identify); + +int proc_ide_read_settings (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; @@ -427,10 +459,12 @@ static int proc_ide_read_settings PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +EXPORT_SYMBOL(proc_ide_read_settings); + #define MAX_LEN 30 -static int proc_ide_write_settings(struct file *file, const char __user *buffer, - unsigned long count, void *data) +int proc_ide_write_settings(struct file *file, const char __user *buffer, + unsigned long count, void *data) { ide_drive_t *drive = (ide_drive_t *) data; char name[MAX_LEN + 1]; @@ -521,6 +555,8 @@ parse_error: return -EINVAL; } +EXPORT_SYMBOL(proc_ide_write_settings); + int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -532,6 +568,8 @@ int proc_ide_read_capacity PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +EXPORT_SYMBOL(proc_ide_read_capacity); + int proc_ide_read_geometry (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -550,7 +588,7 @@ int proc_ide_read_geometry EXPORT_SYMBOL(proc_ide_read_geometry); -static int proc_ide_read_dmodel +int proc_ide_read_dmodel (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; @@ -562,7 +600,9 @@ static int proc_ide_read_dmodel PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_driver +EXPORT_SYMBOL(proc_ide_read_dmodel); + +int proc_ide_read_driver (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; @@ -574,7 +614,9 @@ static int proc_ide_read_driver PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_write_driver +EXPORT_SYMBOL(proc_ide_read_driver); + +int proc_ide_write_driver (struct file *file, const char __user *buffer, unsigned long count, void *data) { ide_drive_t *drive = (ide_drive_t *) data; @@ -592,7 +634,9 @@ static int proc_ide_write_driver return count; } -static int proc_ide_read_media +EXPORT_SYMBOL(proc_ide_write_driver); + +int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; @@ -616,6 +660,8 @@ static int proc_ide_read_media PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +EXPORT_SYMBOL(proc_ide_read_media); + static ide_proc_entry_t generic_drive_entries[] = { { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver }, { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL }, @@ -642,6 +688,8 @@ void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void } } +EXPORT_SYMBOL(ide_add_proc_entries); + void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) { if (!dir || !p) @@ -652,7 +700,9 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) } } -static void create_proc_ide_drives(ide_hwif_t *hwif) +EXPORT_SYMBOL(ide_remove_proc_entries); + +void create_proc_ide_drives(ide_hwif_t *hwif) { int d; struct proc_dir_entry *ent; @@ -676,7 +726,9 @@ static void create_proc_ide_drives(ide_hwif_t *hwif) } } -static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) +EXPORT_SYMBOL(create_proc_ide_drives); + +void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) { ide_driver_t *driver = drive->driver; @@ -689,6 +741,8 @@ static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) } } +EXPORT_SYMBOL(destroy_proc_ide_device); + void destroy_proc_ide_drives(ide_hwif_t *hwif) { int d; @@ -700,6 +754,8 @@ void destroy_proc_ide_drives(ide_hwif_t *hwif) } } +EXPORT_SYMBOL(destroy_proc_ide_drives); + static ide_proc_entry_t hwif_entries[] = { { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL }, { "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config }, @@ -787,9 +843,13 @@ void proc_ide_create(void) entry->proc_fops = &ide_drivers_operations; } +EXPORT_SYMBOL(proc_ide_create); + void proc_ide_destroy(void) { remove_proc_entry("ide/drivers", proc_ide_root); destroy_proc_ide_interfaces(); remove_proc_entry("ide", 0); } + +EXPORT_SYMBOL(proc_ide_destroy); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 98f4f3e4d..c684ad5da 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -201,6 +201,14 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) if (!hwif->ide_dma_read(drive)) return ide_started; break; +#ifdef CONFIG_BLK_DEV_IDE_TCQ + case WIN_READDMA_QUEUED: + case WIN_READDMA_QUEUED_EXT: + return __ide_dma_queued_read(drive); + case WIN_WRITEDMA_QUEUED: + case WIN_WRITEDMA_QUEUED_EXT: + return __ide_dma_queued_write(drive); +#endif default: if (task->handler == NULL) return ide_stopped; @@ -301,18 +309,38 @@ EXPORT_SYMBOL(task_no_data_intr); */ #ifndef CONFIG_IDE_TASKFILE_IO +#define task_map_rq(rq, flags) ide_map_buffer((rq), (flags)) +#define task_unmap_rq(rq, buf, flags) ide_unmap_buffer((rq), (buf), (flags)) + /* * Handler for command with PIO data-in phase, READ */ +/* + * FIXME before 2.4 enable ... + * DATA integrity issue upon error. + */ ide_startstop_t task_in_intr (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); char *pBuf = NULL; u8 stat; + unsigned long flags; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { +#if 0 + DTF("%s: attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + /* + * Expect a BUG BOMB if we attempt to rewind the + * offset in the BH aka PAGE in the current BLOCK + * segment. This is different than the HOST segment. + */ +#endif + if (!rq->bio) + rq->current_nr_sectors++; return DRIVER(drive)->error(drive, "task_in_intr", stat); } if (!(stat & BUSY_STAT)) { @@ -322,13 +350,39 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) return ide_started; } } +#if 0 - pBuf = rq->buffer + task_rq_offset(rq); + /* + * Holding point for a brain dump of a thought :-/ + */ + + if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { + DTF("%s: READ attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + rq->current_nr_sectors++; + return DRIVER(drive)->error(drive, "task_in_intr", stat); + } + if (!rq->current_nr_sectors) + if (!DRIVER(drive)->end_request(drive, 1, 0)) + return ide_stopped; + + if (--rq->current_nr_sectors <= 0) + if (!DRIVER(drive)->end_request(drive, 1, 0)) + return ide_stopped; +#endif + + pBuf = task_map_rq(rq, &flags); DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n", pBuf, (int) rq->current_nr_sectors, stat); taskfile_input_data(drive, pBuf, SECTOR_WORDS); - - /* FIXME: check drive status */ + task_unmap_rq(rq, pBuf, &flags); + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we have a good + * hwif->INB(IDE_STATUS_REG); return. + */ if (--rq->current_nr_sectors <= 0) if (!DRIVER(drive)->end_request(drive, 1, 0)) return ide_stopped; @@ -353,10 +407,21 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive) char *pBuf = NULL; unsigned int msect = drive->mult_count; unsigned int nsect; + unsigned long flags; u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { + if (!rq->bio) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk(KERN_ERR "%s: MULTI-READ assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } return DRIVER(drive)->error(drive, "task_mulin_intr", stat); } /* no data yet, so wait for another interrupt */ @@ -369,16 +434,21 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive) nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; - pBuf = rq->buffer + task_rq_offset(rq); + pBuf = task_map_rq(rq, &flags); DTF("Multiread: %p, nsect: %d, msect: %d, " \ " rq->current_nr_sectors: %d\n", pBuf, nsect, msect, rq->current_nr_sectors); taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors -= nsect; msect -= nsect; - - /* FIXME: check drive status */ + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we have a + * good hwif->INB(IDE_STATUS_REG); return. + */ if (!rq->current_nr_sectors) { if (!DRIVER(drive)->end_request(drive, 1, 0)) return ide_stopped; @@ -397,6 +467,8 @@ EXPORT_SYMBOL(task_mulin_intr); */ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { + char *pBuf = NULL; + unsigned long flags; ide_startstop_t startstop; if (ide_wait_stat(&startstop, drive, DATA_READY, @@ -407,8 +479,10 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) return startstop; } /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, rq->buffer + task_rq_offset(rq), SECTOR_WORDS); + pBuf = task_map_rq(rq, &flags); + taskfile_output_data(drive, pBuf, SECTOR_WORDS); rq->current_nr_sectors--; + task_unmap_rq(rq, pBuf, &flags); return ide_started; } @@ -424,9 +498,14 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned long flags; u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) { + DTF("%s: WRITE attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + rq->current_nr_sectors++; return DRIVER(drive)->error(drive, "task_out_intr", stat); } /* @@ -438,10 +517,11 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) return ide_stopped; if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { rq = HWGROUP(drive)->rq; - pBuf = rq->buffer + task_rq_offset(rq); + pBuf = task_map_rq(rq, &flags); DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); taskfile_output_data(drive, pBuf, SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors--; } @@ -452,11 +532,28 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) EXPORT_SYMBOL(task_out_intr); +#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT + ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) { +#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT + ide_hwif_t *hwif = HWIF(drive); + char *pBuf = NULL; + unsigned int nsect = 0, msect = drive->mult_count; + u8 stat; + unsigned long flags; +#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ + ide_task_t *args = rq->special; ide_startstop_t startstop; +#if 0 + /* + * assign private copy for multi-write + */ + memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request)); +#endif + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing %s\n", @@ -464,6 +561,31 @@ ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); return startstop; } +#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT + + do { + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + pBuf = task_map_rq(rq, &flags); + DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \ + "rq->current_nr_sectors: %ld\n", + pBuf, nsect, msect, rq->current_nr_sectors); + msect -= nsect; + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); + rq->current_nr_sectors -= nsect; + if (!rq->current_nr_sectors) { + if (!DRIVER(drive)->end_request(drive, 1, 0)) + if (!rq->bio) { + stat = hwif->INB(IDE_STATUS_REG); + return ide_stopped; + } + } + } while (msect); + rq->errors = 0; + return ide_started; +#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ if (!(drive_is_ready(drive))) { int i; for (i=0; i<100; i++) { @@ -477,10 +599,14 @@ ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) * move the DATA-TRANSFER T-Bar as BSY != 0. */ return args->handler(drive); +#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ } EXPORT_SYMBOL(pre_task_mulout_intr); +/* + * FIXME before enabling in 2.4 ... DATA integrity issue upon error. + */ /* * Handler for command write multiple * Called directly from execute_drive_cmd for the first bunch of sectors, @@ -492,17 +618,49 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive) u8 stat = hwif->INB(IDE_STATUS_REG); struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + ide_startstop_t startstop = ide_stopped; unsigned int msect = drive->mult_count; unsigned int nsect; + unsigned long flags; - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT) || !rq->current_nr_sectors) { + /* + * (ks/hs): Handle last IRQ on multi-sector transfer, + * occurs after all data was sent in this chunk + */ + if (rq->current_nr_sectors == 0) { if (stat & (ERR_STAT|DRQ_STAT)) { + if (!rq->bio) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk(KERN_ERR "%s: MULTI-WRITE assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } return DRIVER(drive)->error(drive, "task_mulout_intr", stat); } - /* Handle last IRQ, occurs after all data was sent. */ - if (!rq->current_nr_sectors) { + if (!rq->bio) DRIVER(drive)->end_request(drive, 1, 0); - return ide_stopped; + return startstop; + } + /* + * DON'T be lazy code the above and below togather !!! + */ + if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + if (!rq->bio) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk("%s: MULTI-WRITE assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } + return DRIVER(drive)->error(drive, "task_mulout_intr", stat); } /* no data yet, so wait for another interrupt */ if (HWGROUP(drive)->handler == NULL) @@ -510,6 +668,7 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive) return ide_started; } +#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT if (HWGROUP(drive)->handler != NULL) { unsigned long lflags; spin_lock_irqsave(&ide_lock, lflags); @@ -517,20 +676,26 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive) del_timer(&HWGROUP(drive)->timer); spin_unlock_irqrestore(&ide_lock, lflags); } +#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; - pBuf = rq->buffer + task_rq_offset(rq); + pBuf = task_map_rq(rq, &flags); DTF("Multiwrite: %p, nsect: %d, msect: %d, " \ "rq->current_nr_sectors: %ld\n", pBuf, nsect, msect, rq->current_nr_sectors); msect -= nsect; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); rq->current_nr_sectors -= nsect; - - /* FIXME: check drive status */ + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we + * have a good hwif->INB(IDE_STATUS_REG); return. + */ if (!rq->current_nr_sectors) { if (!DRIVER(drive)->end_request(drive, 1, 0)) if (!rq->bio) @@ -846,12 +1011,6 @@ int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_ else rq.nr_sectors = data_size / SECTOR_SIZE; - if (!rq.nr_sectors) { - printk(KERN_ERR "%s: in/out command without data\n", - drive->name); - return -EFAULT; - } - rq.hard_nr_sectors = rq.nr_sectors; rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; } @@ -1336,6 +1495,9 @@ ide_startstop_t flagged_task_in_intr (ide_drive_t *drive) char *pBuf = NULL; int retries = 5; + if (rq->current_nr_sectors == 0) + return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); + if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & ERR_STAT) { return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat); @@ -1382,6 +1544,9 @@ ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive) int retries = 5; unsigned int msect, nsect; + if (rq->current_nr_sectors == 0) + return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); + msect = drive->mult_count; if (msect == 0) return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); @@ -1433,8 +1598,14 @@ ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive) */ ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq) { + ide_hwif_t *hwif = HWIF(drive); + u8 stat = hwif->INB(IDE_STATUS_REG); ide_startstop_t startstop; + if (!rq->current_nr_sectors) { + return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat); + } + if (ide_wait_stat(&startstop, drive, DATA_READY, BAD_W_STAT, WAIT_DRQ)) { printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name); @@ -1496,6 +1667,9 @@ ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request ide_startstop_t startstop; unsigned int msect, nsect; + if (!rq->current_nr_sectors) + return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat); + msect = drive->mult_count; if (msect == 0) return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 2714aa1a3..bc60dfb78 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -188,6 +188,7 @@ int noautodma = 1; #endif EXPORT_SYMBOL(noautodma); +EXPORT_SYMBOL(ide_bus_type); /* * This is declared extern in ide.h, for access by other IDE modules: @@ -553,6 +554,8 @@ control_region_busy: return -EBUSY; } +EXPORT_SYMBOL(ide_hwif_request_regions); + /** * ide_hwif_release_regions - free IDE resources * @@ -581,6 +584,8 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) release_region(hwif->io_ports[i], 1); } +EXPORT_SYMBOL(ide_hwif_release_regions); + /* restore hwif to a sane state */ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) { @@ -931,6 +936,8 @@ void ide_setup_ports ( hw_regs_t *hw, */ } +EXPORT_SYMBOL(ide_setup_ports); + /* * Register an IDE interface, specifying exactly the registers etc * Set init=1 iff calling before probes have taken place. @@ -991,6 +998,7 @@ EXPORT_SYMBOL(ide_register_hw); */ DECLARE_MUTEX(ide_setting_sem); +EXPORT_SYMBOL(ide_setting_sem); /** * ide_add_setting - add an ide setting option @@ -1083,6 +1091,26 @@ static void __ide_remove_setting (ide_drive_t *drive, char *name) kfree(setting); } +/** + * ide_remove_setting - remove an ide setting option + * @drive: drive to use + * @name: setting name + * + * Removes the setting named from the device if it is present. + * The function takes the settings_lock to protect against + * parallel changes. This function must not be called from IRQ + * context. + */ + +void ide_remove_setting (ide_drive_t *drive, char *name) +{ + down(&ide_setting_sem); + __ide_remove_setting(drive, name); + up(&ide_setting_sem); +} + +EXPORT_SYMBOL(ide_remove_setting); + /** * ide_find_setting_by_ioctl - find a drive specific ioctl * @drive: drive to scan @@ -1264,6 +1292,8 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) return 0; } +EXPORT_SYMBOL(ide_write_setting); + static int set_io_32bit(ide_drive_t *drive, int arg) { drive->io_32bit = arg; @@ -1391,6 +1421,8 @@ abort: return 1; } +EXPORT_SYMBOL(ide_replace_subdriver); + int ata_attach(ide_drive_t *drive) { struct list_head *p; @@ -1415,6 +1447,8 @@ int ata_attach(ide_drive_t *drive) return 1; } +EXPORT_SYMBOL(ata_attach); + static int generic_ide_suspend(struct device *dev, u32 state) { ide_drive_t *drive = dev->driver_data; @@ -1772,7 +1806,7 @@ int __init ide_setup (char *s) if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "serialize", - "autotune", "noautotune", "stroke", "swapdata", "bswap", + "autotune", "noautotune", "minus8", "swapdata", "bswap", "minus11", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; @@ -1806,9 +1840,6 @@ int __init ide_setup (char *s) case -7: /* "noautotune" */ drive->autotune = IDE_TUNE_NOAUTO; goto done; - case -8: /* stroke */ - drive->stroke = 1; - goto done; case -9: /* "swapdata" */ case -10: /* "bswap" */ drive->bswap = 1; @@ -2003,7 +2034,6 @@ done: return 1; } -extern void pnpide_init(void); extern void h8300_ide_init(void); /* @@ -2070,9 +2100,12 @@ static void __init probe_for_hwifs (void) buddha_init(); } #endif /* CONFIG_BLK_DEV_BUDDHA */ -#ifdef CONFIG_BLK_DEV_IDEPNP - pnpide_init(); -#endif +#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP) + { + extern void pnpide_init(int enable); + pnpide_init(1); + } +#endif /* CONFIG_BLK_DEV_IDEPNP */ #ifdef CONFIG_H8300 h8300_ide_init(); #endif @@ -2210,6 +2243,9 @@ int ide_unregister_subdriver (ide_drive_t *drive) up(&ide_setting_sem); return 1; } +#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP) && defined(MODULE) + pnpide_init(0); +#endif /* CONFIG_BLK_DEV_IDEPNP */ #ifdef CONFIG_PROC_FS ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); ide_remove_proc_entries(drive->proc, generic_subdriver_entries); diff --git a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c index 73e833d0f..0addbae18 100644 --- a/drivers/ide/legacy/pdc4030.c +++ b/drivers/ide/legacy/pdc4030.c @@ -756,6 +756,12 @@ static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, BUG_ON(rq->nr_sectors > 127); +#ifdef DEBUG + printk(KERN_DEBUG "%s: %sing: LBAsect=%lu, sectors=%lu\n", + drive->name, rq_data_dir(rq) ? "writ" : "read", + block, rq->nr_sectors); +#endif + #ifndef CONFIG_IDE_TASKFILE_IO if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index b032d2459..0c3b227fe 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -409,7 +409,7 @@ static int aec62xx_irq_timeout (ide_drive_t *drive) return 0; } -static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name) { int bus_speed = system_bus_clock(); @@ -435,7 +435,7 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch return dev->irq; } -static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) +static void __init init_hwif_aec62xx (ide_hwif_t *hwif) { hwif->autodma = 0; hwif->tuneproc = &aec62xx_tune_drive; @@ -468,7 +468,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static void __devinit init_dma_aec62xx(ide_hwif_t *hwif, unsigned long dmabase) +static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase) { struct pci_dev *dev = hwif->pci_dev; @@ -490,12 +490,12 @@ static void __devinit init_dma_aec62xx(ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } -static void __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_aec62xx (struct pci_dev *dev, ide_pci_device_t *d) { ide_setup_pci_device(dev, d); } -static void __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d) { unsigned long bar4reg = pci_resource_start(dev, 4); diff --git a/drivers/ide/pci/alim15x3.h b/drivers/ide/pci/alim15x3.h index 439bd5031..989bb9be2 100644 --- a/drivers/ide/pci/alim15x3.h +++ b/drivers/ide/pci/alim15x3.h @@ -14,23 +14,13 @@ static void init_dma_ali15x3(ide_hwif_t *, unsigned long); static ide_pci_device_t ali15x3_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_AL, - .device = PCI_DEVICE_ID_AL_M5229, .name = "ALI15X3", .init_chipset = init_chipset_ali15x3, - .init_iops = NULL, .init_hwif = init_hwif_ali15x3, .init_dma = init_dma_ali15x3, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0 - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/amd74xx.h b/drivers/ide/pci/amd74xx.h deleted file mode 100644 index cb265c8b7..000000000 --- a/drivers/ide/pci/amd74xx.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef AMD74XX_H -#define AMD74XX_H - -#include -#include -#include - -#define DISPLAY_AMD_TIMINGS - -static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *); -static void init_hwif_amd74xx(ide_hwif_t *); - -static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { - { /* 0 */ - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_DEVICE_ID_AMD_COBRA_7401, - .name = "AMD7401", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0 - },{ /* 1 */ - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_DEVICE_ID_AMD_VIPER_7409, - .name = "AMD7409", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0 - },{ /* 2 */ - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_DEVICE_ID_AMD_VIPER_7411, - .name = "AMD7411", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0 - },{ /* 3 */ - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_DEVICE_ID_AMD_OPUS_7441, - .name = "AMD7441", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0 - },{ /* 4 */ - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_DEVICE_ID_AMD_8111_IDE, - .name = "AMD8111", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .autodma = AUTODMA, - .channels = 2, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0 - }, - { /* 5 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, - .name = "NFORCE", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0, - }, - { /* 6 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, - .name = "NFORCE2", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0, - }, - { /* 7 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, - .name = "NFORCE2S", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 8 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, - .name = "NFORCE2S-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 9 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, - .name = "NFORCE3", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 10 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, - .name = "NFORCE3S", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 11 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, - .name = "NFORCE3S-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 12 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, - .name = "NFORCE3S-SATA2", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, - } -}; - -#endif /* AMD74XX_H */ diff --git a/drivers/ide/pci/cmd640.h b/drivers/ide/pci/cmd640.h deleted file mode 100644 index 28b6e0452..000000000 --- a/drivers/ide/pci/cmd640.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CMD640_H -#define CMD640_H - -#include -#include -#include - -#define IDE_IGNORE ((void *)-1) - -static ide_pci_device_t cmd640_chipsets[] __initdata = { - { - .vendor = PCI_VENDOR_ID_CMD, - .device = PCI_DEVICE_ID_CMD_640, - .name = "CMD640", - .init_setup = NULL, - .init_chipset = NULL, - .init_iops = NULL, - .init_hwif = IDE_IGNORE, - .init_dma = NULL, - .channels = 2, - .autodma = NODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, - .bootable = ON_BOARD, - .extra = 0 - },{ - .vendor = 0, - .device = 0, - .bootable = EOL, - } -} - -#endif /* CMD640_H */ diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 06b00a3c3..1f4d08425 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -586,7 +586,7 @@ static int cmd646_1_ide_dma_end (ide_drive_t *drive) return (dma_stat & 7) != 4; } -static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name) { u32 class_rev = 0; u8 mrdmode = 0; @@ -674,7 +674,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha return 0; } -static unsigned int __devinit ata66_cmd64x(ide_hwif_t *hwif) +static unsigned int __init ata66_cmd64x (ide_hwif_t *hwif) { u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01; @@ -689,7 +689,7 @@ static unsigned int __devinit ata66_cmd64x(ide_hwif_t *hwif) return (ata66 & mask) ? 1 : 0; } -static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) +static void __init init_hwif_cmd64x (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; unsigned int class_rev; diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 5882693d0..588ac3a00 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -51,7 +51,7 @@ #include #include -#define DISPLAY_CS5520_TIMINGS +#include "cs5520.h" #if defined(DISPLAY_CS5520_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -251,24 +251,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; } - -#define DECLARE_CS_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_cs5520, \ - .init_setup_dma = cs5520_init_setup_dma, \ - .init_hwif = init_hwif_cs5520, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - .flags = IDEPCI_FLAG_ISA_PORTS, \ - } - -static ide_pci_device_t cyrix_chipsets[] __devinitdata = { - /* 0 */ DECLARE_CS_DEV("Cyrix 5510"), - /* 1 */ DECLARE_CS_DEV("Cyrix 5520") -}; - + /* * The 5510/5520 are a bit weird. They don't quite set up the way * the PCI helper layer expects so we must do much of the set up @@ -290,7 +273,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic return 1; } pci_set_master(dev); - pci_set_dma_mask(dev, 0xFFFFFFFF); + if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { + printk(KERN_WARNING "cs5520: No suitable DMA available.\n"); + return -ENODEV; + } init_chipset_cs5520(dev, d->name); index.all = 0xf0f0; diff --git a/drivers/ide/pci/cs5520.h b/drivers/ide/pci/cs5520.h index 21e8cb39d..f2cdc5343 100644 --- a/drivers/ide/pci/cs5520.h +++ b/drivers/ide/pci/cs5520.h @@ -13,32 +13,24 @@ static void cs5520_init_setup_dma(struct pci_dev *dev, struct ide_pci_device_s * static ide_pci_device_t cyrix_chipsets[] __devinitdata = { { - .vendor = PCI_VENDOR_ID_CYRIX, - .device = PCI_DEVICE_ID_CYRIX_5510, .name = "Cyrix 5510", .init_chipset = init_chipset_cs5520, .init_setup_dma = cs5520_init_setup_dma, - .init_iops = NULL, .init_hwif = init_hwif_cs5520, - .isa_ports = 1, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - .extra = 0, + .flags = IDEPCI_FLAG_ISA_PORTS, }, { - .vendor = PCI_VENDOR_ID_CYRIX, - .device = PCI_DEVICE_ID_CYRIX_5520, .name = "Cyrix 5520", .init_chipset = init_chipset_cs5520, .init_setup_dma = cs5520_init_setup_dma, - .init_iops = NULL, .init_hwif = init_hwif_cs5520, - .isa_ports = 1, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - .extra = 0, + .flags = IDEPCI_FLAG_ISA_PORTS, } }; diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index b63e2d611..19c97e89a 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -31,7 +31,7 @@ #include #include -#define DISPLAY_CS5530_TIMINGS +#include "cs5530.h" #if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -404,19 +404,9 @@ static void __init init_hwif_cs5530 (ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static ide_pci_device_t cs5530_chipset __devinitdata = { - .name = "CS5530", - .init_chipset = init_chipset_cs5530, - .init_hwif = init_hwif_cs5530, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - .flags = IDEPCI_FLAG_FORCE_MASTER, -}; - static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &cs5530_chipset); + ide_setup_pci_device(dev, &cs5530_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/cs5530.h b/drivers/ide/pci/cs5530.h index 89f448e98..08fe18a09 100644 --- a/drivers/ide/pci/cs5530.h +++ b/drivers/ide/pci/cs5530.h @@ -12,22 +12,13 @@ static void init_hwif_cs5530(ide_hwif_t *); static ide_pci_device_t cs5530_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_CYRIX, - .device = PCI_DEVICE_ID_CYRIX_5530_IDE, .name = "CS5530", .init_chipset = init_chipset_cs5530, - .init_iops = NULL, .init_hwif = init_hwif_cs5530, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, + .flags = IDEPCI_FLAG_FORCE_MASTER, } }; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 77bc20861..5ca4a581f 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -795,7 +795,7 @@ static int hpt370_busproc(ide_drive_t * drive, int state) return 0; } -static int __devinit init_hpt37x(struct pci_dev *dev) +static int __init init_hpt37x(struct pci_dev *dev) { int adjust, i; u16 freq; @@ -923,7 +923,7 @@ init_hpt37X_done: return 0; } -static int __devinit init_hpt366(struct pci_dev *dev) +static int __init init_hpt366 (struct pci_dev *dev) { u32 reg1 = 0; u8 drive_fast = 0; @@ -958,7 +958,7 @@ static int __devinit init_hpt366(struct pci_dev *dev) return 0; } -static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_hpt366 (struct pci_dev *dev, const char *name) { int ret = 0; u8 test = 0; @@ -1004,7 +1004,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha return dev->irq; } -static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) +static void __init init_hwif_hpt366 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; @@ -1116,7 +1116,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) +static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) { u8 masterdma = 0, slavedma = 0; u8 dma_new = 0, dma_old = 0; @@ -1151,7 +1151,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } -static void __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_hpt374 (struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *findev = NULL; @@ -1176,12 +1176,12 @@ static void __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d ide_setup_pci_device(dev, d); } -static void __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_hpt37x (struct pci_dev *dev, ide_pci_device_t *d) { ide_setup_pci_device(dev, d); } -static void __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_hpt366 (struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *findev = NULL; u8 pin1 = 0, pin2 = 0; diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index a5b6e7e5c..1809edddb 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -25,6 +25,8 @@ #include +#include "ns87415.h" + static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; /* @@ -215,17 +217,9 @@ static void __init init_hwif_ns87415 (ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static ide_pci_device_t ns87415_chipset __devinitdata = { - .name = "NS87415", - .init_hwif = init_hwif_ns87415, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &ns87415_chipset); + ide_setup_pci_device(dev, &ns87415_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/ns87415.h b/drivers/ide/pci/ns87415.h index 597803e40..a2594c7fd 100644 --- a/drivers/ide/pci/ns87415.h +++ b/drivers/ide/pci/ns87415.h @@ -9,22 +9,11 @@ static void init_hwif_ns87415(ide_hwif_t *); static ide_pci_device_t ns87415_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_NS, - .device = PCI_DEVICE_ID_NS_87415, .name = "NS87415", - .init_chipset = NULL, - .init_iops = NULL, .init_hwif = init_hwif_ns87415, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index f493b29ce..fbc0bd81e 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -404,7 +404,7 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev) } #endif /* CONFIG_PPC_PMAC */ -static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name) { if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, @@ -429,7 +429,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha return dev->irq; } -static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) +static void __init init_hwif_pdc202new (ide_hwif_t *hwif) { hwif->autodma = 0; @@ -457,12 +457,12 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) #endif /* PDC202_DEBUG_CABLE */ } -static void __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d) { ide_setup_pci_device(dev, d); } -static void __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *findev = NULL; @@ -488,7 +488,7 @@ static void __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t ide_setup_pci_device(dev, d); } -static void __devinit init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d) { if ((dev->bus->self) && (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index cf6082ad7..99fbe04ec 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -670,7 +670,7 @@ static int pdc202xx_tristate (ide_drive_t * drive, int state) return 0; } -static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name) { if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, @@ -715,7 +715,7 @@ static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const c return dev->irq; } -static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) +static void __init init_hwif_pdc202xx (ide_hwif_t *hwif) { hwif->autodma = 0; hwif->tuneproc = &config_chipset_for_pio; @@ -755,7 +755,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) #endif /* PDC202_DEBUG_CABLE */ } -static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) +static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase) { u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; @@ -807,7 +807,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } -static void __devinit init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d) { if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { u8 irq = 0, irq2 = 0; @@ -837,7 +837,7 @@ static void __devinit init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_ ide_setup_pci_device(dev, d); } -static void __devinit init_setup_pdc20265(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d) { if ((dev->bus->self) && (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && @@ -866,7 +866,7 @@ static void __devinit init_setup_pdc20265(struct pci_dev *dev, ide_pci_device_t ide_setup_pci_device(dev, d); } -static void __devinit init_setup_pdc202xx(struct pci_dev *dev, ide_pci_device_t *d) +static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d) { ide_setup_pci_device(dev, d); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index fec700bba..3d21a5b5e 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -49,9 +49,9 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); - * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); * * Documentation * Publically available from Intel web site. Errata documentation @@ -432,14 +432,15 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) int w_flag = 0x10 << drive->dn; int u_speed = 0; int sitre; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; + u16 reg4042, reg44, reg48, reg4a, reg54; + u8 reg55; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_word(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { @@ -461,26 +462,30 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); + pci_write_config_word(dev, 0x48, reg48|u_flag); if (speed == XFER_UDMA_5) { pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); } else { pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } + } else { + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + } } else { if (reg48 & u_flag) - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); if (reg54 & v_flag) - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); if (reg55 & w_flag) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } @@ -650,8 +655,8 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char * Set up the ide_hwif_t for the PIIX interface according to the * capabilities of the hardware. */ - -static void __devinit init_hwif_piix(ide_hwif_t *hwif) + +static void __init init_hwif_piix (ide_hwif_t *hwif) { u8 reg54h = 0, reg55h = 0, ata66 = 0; u8 mask = hwif->channel ? 0xc0 : 0x30; @@ -720,8 +725,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) * Enable the xp fixup for the PIIX controller and then perform * a standard ide PCI setup */ - -static void __devinit init_setup_piix(struct pci_dev *dev, ide_pci_device_t *d) + +static void __init init_setup_piix (struct pci_dev *dev, ide_pci_device_t *d) { ide_setup_pci_device(dev, d); } @@ -749,8 +754,8 @@ static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_ * Check for the present of 450NX errata #19 and errata #25. If * they are found, disable use of DMA IDE */ - -static void __devinit piix_check_450nx(void) + +static void __init piix_check_450nx(void) { struct pci_dev *pdev = NULL; u16 cfg; diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index 3405e6a1b..78669068d 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -33,6 +33,8 @@ #include +#include "rz1000.h" + static void __init init_hwif_rz1000 (ide_hwif_t *hwif) { u16 reg; @@ -52,23 +54,15 @@ static void __init init_hwif_rz1000 (ide_hwif_t *hwif) } } -static ide_pci_device_t rz1000_chipset __devinitdata = { - .name = "RZ100x", - .init_hwif = init_hwif_rz1000, - .channels = 2, - .autodma = NODMA, - .bootable = ON_BOARD, -}; - static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &rz1000_chipset); + ide_setup_pci_device(dev, &rz1000_chipsets[id->driver_data]); return 0; } static struct pci_device_id rz1000_pci_tbl[] = { { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { 0, }, }; MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); diff --git a/drivers/ide/pci/rz1000.h b/drivers/ide/pci/rz1000.h index 30823afe6..5c7c611c5 100644 --- a/drivers/ide/pci/rz1000.h +++ b/drivers/ide/pci/rz1000.h @@ -8,37 +8,18 @@ static void init_hwif_rz1000(ide_hwif_t *); static ide_pci_device_t rz1000_chipsets[] __devinitdata = { -{ - .vendor = PCI_VENDOR_ID_PCTECH, - .device = PCI_DEVICE_ID_PCTECH_RZ1000, + { .name = "RZ1000", - .init_chipset = NULL, - .init_iops = NULL, .init_hwif = init_hwif_rz1000, - .init_dma = NULL, .channels = 2, .autodma = NODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, },{ - .vendor = PCI_VENDOR_ID_PCTECH, - .device = PCI_DEVICE_ID_PCTECH_RZ1001, .name = "RZ1001", - .init_chipset = NULL, - .init_iops = NULL, .init_hwif = init_hwif_rz1000, - .init_dma = NULL, .channels = 2, .autodma = NODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 902408d18..58d1e5874 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -29,6 +29,8 @@ #include #include +#include "sc1200.h" + #define SC1200_REV_A 0x00 #define SC1200_REV_B1 0x01 #define SC1200_REV_B3 0x02 @@ -543,18 +545,9 @@ static void __init init_hwif_sc1200 (ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static ide_pci_device_t sc1200_chipset __devinitdata = { - .name = "SC1200", - .init_chipset = init_chipset_sc1200, - .init_hwif = init_hwif_sc1200, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &sc1200_chipset); + ide_setup_pci_device(dev, &sc1200_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/sc1200.h b/drivers/ide/pci/sc1200.h index dc422a805..c58e68988 100644 --- a/drivers/ide/pci/sc1200.h +++ b/drivers/ide/pci/sc1200.h @@ -12,22 +12,12 @@ static void init_hwif_sc1200(ide_hwif_t *); static ide_pci_device_t sc1200_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_NS, - .device = PCI_DEVICE_ID_NS_SCx200_IDE, .name = "SC1200", .init_chipset = init_chipset_sc1200, - .init_iops = NULL, .init_hwif = init_hwif_sc1200, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 5a7483ef6..5b2ab769b 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -31,8 +31,7 @@ #include -#undef SIIMAGE_VIRTUAL_DMAPIO -#undef SIIMAGE_LARGE_DMA +#include "siimage.h" /** * pdev_is_sata - check if device is SATA @@ -813,7 +812,7 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) * to 133MHz clocking if the system isn't already set up to do it. */ -static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name) { u32 class_rev = 0; u8 tmpbyte = 0; @@ -878,8 +877,8 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch * The hardware supports buffered taskfiles and also some rather nice * extended PRD tables. Unfortunately right now we don't. */ - -static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) + +static void __init init_mmio_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; void *addr = pci_get_drvdata(dev); @@ -997,8 +996,8 @@ static int is_dev_seagate_sata(ide_drive_t *drive) * look in we get for setting up the hwif so that we * can get the iops right before using them. */ - -static void __devinit init_iops_siimage(ide_hwif_t *hwif) + +static void __init init_iops_siimage (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; u32 class_rev = 0; @@ -1024,8 +1023,8 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif) * Check for the presence of an ATA66 capable cable on the * interface. */ - -static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif) + +static unsigned int __init ata66_siimage (ide_hwif_t *hwif) { unsigned long addr = siimage_selreg(hwif, 0); if (pci_get_drvdata(hwif->pci_dev) == NULL) { @@ -1045,8 +1044,8 @@ static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif) * requires several custom handlers so we override the default * ide DMA handlers appropriately */ - -static void __devinit init_hwif_siimage(ide_hwif_t *hwif) + +static void __init init_hwif_siimage (ide_hwif_t *hwif) { hwif->autodma = 0; @@ -1093,23 +1092,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -#define DECLARE_SII_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_siimage, \ - .init_iops = init_iops_siimage, \ - .init_hwif = init_hwif_siimage, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - } - -static ide_pci_device_t siimage_chipsets[] __devinitdata = { - /* 0 */ DECLARE_SII_DEV("SiI680"), - /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"), - /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA") -}; - /** * siimage_init_one - pci layer discovery entry * @dev: PCI device diff --git a/drivers/ide/pci/siimage.h b/drivers/ide/pci/siimage.h index a47aae5b9..b83b4c336 100644 --- a/drivers/ide/pci/siimage.h +++ b/drivers/ide/pci/siimage.h @@ -1,14 +1,11 @@ #ifndef SIIMAGE_H #define SIIMAGE_H -#include #include #include #include -#define DISPLAY_SIIMAGE_TIMINGS - #undef SIIMAGE_VIRTUAL_DMAPIO #undef SIIMAGE_BUFFERED_TASKFILE #undef SIIMAGE_LARGE_DMA @@ -27,46 +24,29 @@ static void init_hwif_siimage(ide_hwif_t *); static ide_pci_device_t siimage_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_CMD, - .device = PCI_DEVICE_ID_SII_680, .name = "SiI680", .init_chipset = init_chipset_siimage, .init_iops = init_iops_siimage, .init_hwif = init_hwif_siimage, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, },{ /* 1 */ - .vendor = PCI_VENDOR_ID_CMD, - .device = PCI_DEVICE_ID_SII_3112, .name = "SiI3112 Serial ATA", .init_chipset = init_chipset_siimage, .init_iops = init_iops_siimage, .init_hwif = init_hwif_siimage, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, },{ /* 2 */ - .vendor = PCI_VENDOR_ID_CMD, - .device = PCI_DEVICE_ID_SII_1210SA, .name = "Adaptec AAR-1210SA", .init_chipset = init_chipset_siimage, .init_iops = init_iops_siimage, .init_hwif = init_hwif_siimage, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index d06b1fd8c..6254eab6d 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -63,8 +63,7 @@ #include #include "ide-timing.h" - -#define DISPLAY_SIS_TIMINGS +#include "sis5513.h" /* registers layout and init values are chipset family dependant */ @@ -945,19 +944,9 @@ static void __init init_hwif_sis5513 (ide_hwif_t *hwif) return; } -static ide_pci_device_t sis5513_chipset __devinitdata = { - .name = "SIS5513", - .init_chipset = init_chipset_sis5513, - .init_hwif = init_hwif_sis5513, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .bootable = ON_BOARD, -}; - static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &sis5513_chipset); + ide_setup_pci_device(dev, &sis5513_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/sis5513.h b/drivers/ide/pci/sis5513.h index 79f3aa8b6..d66e9a74b 100644 --- a/drivers/ide/pci/sis5513.h +++ b/drivers/ide/pci/sis5513.h @@ -12,22 +12,13 @@ static void init_hwif_sis5513(ide_hwif_t *); static ide_pci_device_t sis5513_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5513, .name = "SIS5513", .init_chipset = init_chipset_sis5513, - .init_iops = NULL, .init_hwif = init_hwif_sis5513, .channels = 2, .autodma = NOAUTODMA, .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, .bootable = ON_BOARD, - .extra = 0 - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 38bd8077b..4706ebfba 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -29,6 +29,8 @@ #include #include +#include "sl82c105.h" + #undef DEBUG #ifdef DEBUG @@ -479,20 +481,9 @@ static void __init init_hwif_sl82c105(ide_hwif_t *hwif) #endif /* CONFIG_BLK_DEV_IDEDMA */ } -static ide_pci_device_t sl82c105_chipset __devinitdata = { - .name = "W82C105", - .init_chipset = init_chipset_sl82c105, - .init_hwif = init_hwif_sl82c105, - .init_dma = init_dma_sl82c105, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, - .bootable = ON_BOARD, -}; - static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &sl82c105_chipset); + ide_setup_pci_device(dev, &sl82c105_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/sl82c105.h b/drivers/ide/pci/sl82c105.h index f71ee701d..f2d34a254 100644 --- a/drivers/ide/pci/sl82c105.h +++ b/drivers/ide/pci/sl82c105.h @@ -11,23 +11,14 @@ static void init_dma_sl82c105(ide_hwif_t *, unsigned long); static ide_pci_device_t sl82c105_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_WINBOND, - .device = PCI_DEVICE_ID_WINBOND_82C105, .name = "W82C105", .init_chipset = init_chipset_sl82c105, - .init_iops = NULL, .init_hwif = init_hwif_sl82c105, .init_dma = init_dma_sl82c105, .channels = 2, .autodma = NOAUTODMA, .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 1a0183d1b..784224270 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -21,7 +21,7 @@ #include -#define DISPLAY_SLC90E66_TIMINGS +#include "slc90e66.h" #if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -364,19 +364,9 @@ static void __init init_hwif_slc90e66 (ide_hwif_t *hwif) #endif /* !CONFIG_BLK_DEV_IDEDMA */ } -static ide_pci_device_t slc90e66_chipset __devinitdata = { - .name = "SLC90E66", - .init_chipset = init_chipset_slc90e66, - .init_hwif = init_hwif_slc90e66, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, - .bootable = ON_BOARD, -}; - static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &slc90e66_chipset); + ide_setup_pci_device(dev, &slc90e66_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/slc90e66.h b/drivers/ide/pci/slc90e66.h index 2f15858cd..57017958c 100644 --- a/drivers/ide/pci/slc90e66.h +++ b/drivers/ide/pci/slc90e66.h @@ -14,22 +14,13 @@ static void init_hwif_slc90e66(ide_hwif_t *); static ide_pci_device_t slc90e66_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_EFAR, - .device = PCI_DEVICE_ID_EFAR_SLC90E66_1, .name = "SLC90E66", .init_chipset = init_chipset_slc90e66, - .init_iops = NULL, .init_hwif = init_hwif_slc90e66, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 52e088e25..fc6186531 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -41,6 +41,8 @@ #include #include +#include "triflex.h" + static struct pci_dev *triflex_dev; #ifdef CONFIG_PROC_FS @@ -215,32 +217,15 @@ static unsigned int __init init_chipset_triflex(struct pci_dev *dev, return 0; } -static ide_pci_device_t triflex_device __devinitdata = { - .name = "TRIFLEX", - .init_chipset = init_chipset_triflex, - .init_hwif = init_hwif_triflex, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, - .bootable = ON_BOARD, -}; - static int __devinit triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &triflex_device); + ide_setup_pci_device(dev, &triflex_devices[id->driver_data]); triflex_dev = dev; return 0; } -static struct pci_device_id triflex_pci_tbl[] = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); - static struct pci_driver driver = { .name = "TRIFLEX IDE", .id_table = triflex_pci_tbl, diff --git a/drivers/ide/pci/triflex.h b/drivers/ide/pci/triflex.h index 7f6f73783..f826608f5 100644 --- a/drivers/ide/pci/triflex.h +++ b/drivers/ide/pci/triflex.h @@ -17,18 +17,13 @@ static void init_hwif_triflex(ide_hwif_t *); static ide_pci_device_t triflex_devices[] __devinitdata = { { - .vendor = PCI_VENDOR_ID_COMPAQ, - .device = PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, .name = "TRIFLEX", .init_chipset = init_chipset_triflex, - .init_iops = NULL, .init_hwif = init_hwif_triflex, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, .bootable = ON_BOARD, - },{ - .bootable = EOL, } }; diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index d482d8310..c07408908 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -140,6 +140,8 @@ #include +#include "trm290.h" + static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { ide_hwif_t *hwif = HWIF(drive); @@ -300,7 +302,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive) /* * Invoked from ide-dma.c at boot time. */ -void __devinit init_hwif_trm290(ide_hwif_t *hwif) +void __init init_hwif_trm290 (ide_hwif_t *hwif) { unsigned int cfgbase = 0; unsigned long flags; @@ -393,17 +395,9 @@ void __devinit init_hwif_trm290(ide_hwif_t *hwif) #endif } -static ide_pci_device_t trm290_chipset __devinitdata = { - .name = "TRM290", - .init_hwif = init_hwif_trm290, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, -}; - static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &trm290_chipset); + ide_setup_pci_device(dev, &trm290_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/trm290.h b/drivers/ide/pci/trm290.h index e18b29e03..6c001d4d5 100644 --- a/drivers/ide/pci/trm290.h +++ b/drivers/ide/pci/trm290.h @@ -9,23 +9,11 @@ extern void init_hwif_trm290(ide_hwif_t *); static ide_pci_device_t trm290_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_TEKRAM, - .device = PCI_DEVICE_ID_TEKRAM_DC290, .name = "TRM290", - .init_chipset = NULL, - .init_iops = NULL, .init_hwif = init_hwif_trm290, - .init_dma = NULL, .channels = 2, .autodma = NOAUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 9aa563300..47c241d26 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -37,8 +37,7 @@ #include #include "ide-timing.h" - -#define DISPLAY_VIA_TIMINGS +#include "via82cxxx.h" #define VIA_IDE_ENABLE 0x40 #define VIA_IDE_CONFIG 0x41 @@ -608,19 +607,9 @@ static void __init init_hwif_via82cxxx(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static ide_pci_device_t via82cxxx_chipset __devinitdata = { - .name = "VP_IDE", - .init_chipset = init_chipset_via82cxxx, - .init_hwif = init_hwif_via82cxxx, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, -}; - static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &via82cxxx_chipset); + ide_setup_pci_device(dev, &via82cxxx_chipsets[id->driver_data]); return 0; } diff --git a/drivers/ide/pci/via82cxxx.h b/drivers/ide/pci/via82cxxx.h index a47f040e8..6504ca08a 100644 --- a/drivers/ide/pci/via82cxxx.h +++ b/drivers/ide/pci/via82cxxx.h @@ -12,8 +12,6 @@ static void init_hwif_via82cxxx(ide_hwif_t *); static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = { { /* 0 */ - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_82C576_1, .name = "VP_IDE", .init_chipset = init_chipset_via82cxxx, .init_hwif = init_hwif_via82cxxx, @@ -21,23 +19,6 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = { .autodma = NOAUTODMA, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, .bootable = ON_BOARD, - .extra = 0, - },{ /* 1 */ - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_82C586_1, - .name = "VP_IDE", - .init_chipset = init_chipset_via82cxxx, - .init_hwif = init_hwif_via82cxxx, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD, - .extra = 0, - },{ - .vendor = 0, - .device = 0, - .channels = 0, - .bootable = EOL, } }; diff --git a/drivers/ide/ppc/swarm.c b/drivers/ide/ppc/swarm.c deleted file mode 100644 index d54a55525..000000000 --- a/drivers/ide/ppc/swarm.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2001 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Derived loosely from ide-pmac.c, so: - * - * Copyright (C) 1998 Paul Mackerras. - * Copyright (C) 1995-1998 Mark Lord - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __IDE_SWARM_C - -#include - -void __init swarm_ide_probe(void) -{ - int i; - ide_hwif_t *hwif; - /* - * Find the first untaken slot in hwifs - */ - for (i = 0; i < MAX_HWIFS; i++) { - if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) { - break; - } - } - if (i == MAX_HWIFS) { - printk("No space for SWARM onboard IDE driver in ide_hwifs[]. Not enabled.\n"); - return; - } - - /* Set up our stuff */ - hwif = &ide_hwifs[i]; - hwif->hw.io_ports[IDE_DATA_OFFSET] = SWARM_IDE_REG(0x1f0); - hwif->hw.io_ports[IDE_ERROR_OFFSET] = SWARM_IDE_REG(0x1f1); - hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2); - hwif->hw.io_ports[IDE_SECTOR_OFFSET] = SWARM_IDE_REG(0x1f3); - hwif->hw.io_ports[IDE_LCYL_OFFSET] = SWARM_IDE_REG(0x1f4); - hwif->hw.io_ports[IDE_HCYL_OFFSET] = SWARM_IDE_REG(0x1f5); - hwif->hw.io_ports[IDE_SELECT_OFFSET] = SWARM_IDE_REG(0x1f6); - hwif->hw.io_ports[IDE_STATUS_OFFSET] = SWARM_IDE_REG(0x1f7); - hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6); - hwif->hw.io_ports[IDE_IRQ_OFFSET] = SWARM_IDE_REG(0x3f7); -// hwif->hw->ack_intr = swarm_ide_ack_intr; - hwif->hw.irq = SWARM_IDE_INT; -#if 0 - hwif->iops = swarm_iops; -#else - hwif->OUTB = hwif->OUTBP = swarm_outb; - hwif->OUTW = hwif->OUTWP = swarm_outw; - hwif->OUTL = hwif->OUTLP = swarm_outl; - hwif->OUTSW = hwif->OUTSWP = swarm_outsw; - hwif->OUTSL = hwif->OUTSLP = swarm_outsl; - hwif->INB = hwif->INBP = swarm_inb; - hwif->INW = hwif->INWP = swarm_inw; - hwif->INL = hwif->INLP = swarm_inl; - hwif->INSW = hwif->INSWP = swarm_insw; - hwif->INSL = hwif->INSLP = swarm_insl; -#endif -#if 0 - hwif->pioops = swarm_pio_ops; -#else - hwif->ata_input_data = swarm_ata_input_data; - hwif->ata_output_data = swarm_ata_output_data; - hwif->atapi_input_bytes = swarm_atapi_input_bytes; - hwif->atapi_output_bytes = swarm_atapi_output_bytes; -#endif - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->irq = hwif->hw.irq; - printk("SWARM onboard IDE configured as device %i\n", i); - -#ifndef HWIF_PROBE_CLASSIC_METHOD - probe_hwif_init(hwif->index); -#endif /* HWIF_PROBE_CLASSIC_METHOD */ - -} - diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c index 931464b6c..301011c3c 100644 --- a/drivers/ieee1394/csr1212.c +++ b/drivers/ieee1394/csr1212.c @@ -1061,10 +1061,6 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) } nkv = kv->next; - if (kv->prev) - kv->prev->next = NULL; - if (kv->next) - kv->next->prev = NULL; kv->prev = NULL; kv->next = NULL; } @@ -1138,7 +1134,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) /* Make sure the Extended ROM leaf is a multiple of * max_rom in size. */ leaf_size = (cache->len + (csr->max_rom - 1)) & - ~(csr->max_rom - 1); + (csr->max_rom - 1); /* Zero out the unused ROM region */ memset(cache->data + bytes_to_quads(cache->len), 0x00, diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index c502c6e9c..47a6141cb 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -30,7 +30,7 @@ #include "config_roms.h" -static void delayed_reset_bus(void * __reset_info) +static void delayed_reset_bus(unsigned long __reset_info) { struct hpsb_host *host = (struct hpsb_host*)__reset_info; int generation = host->csr.generation + 1; @@ -129,6 +129,9 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, skb_queue_head_init(&h->pending_packet_queue); INIT_LIST_HEAD(&h->addr_space); + init_timer(&h->delayed_reset); + h->delayed_reset.function = delayed_reset_bus; + h->delayed_reset.data = (unsigned long)h; for (i = 2; i < 16; i++) h->csr.gen_timestamp[i] = jiffies - 60 * HZ; @@ -137,8 +140,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, atomic_set(&h->generation, 0); - INIT_WORK(&h->delayed_reset, delayed_reset_bus, h); - init_timer(&h->timeout); h->timeout.data = (unsigned long) h; h->timeout.function = abort_timedouts; @@ -187,8 +188,7 @@ void hpsb_remove_host(struct hpsb_host *host) { host->is_shutdown = 1; - cancel_delayed_work(&host->delayed_reset); - flush_scheduled_work(); + del_timer_sync(&host->delayed_reset); host->driver = &dummy_driver; @@ -202,7 +202,7 @@ void hpsb_remove_host(struct hpsb_host *host) int hpsb_update_config_rom_image(struct hpsb_host *host) { - unsigned long reset_delay; + unsigned long reset_time; int next_gen = host->csr.generation + 1; if (!host->update_config_rom) @@ -213,21 +213,21 @@ int hpsb_update_config_rom_image(struct hpsb_host *host) /* Stop the delayed interrupt, we're about to change the config rom and * it would be a waste to do a bus reset twice. */ - cancel_delayed_work(&host->delayed_reset); + del_timer_sync(&host->delayed_reset); /* IEEE 1394a-2000 prohibits using the same generation number * twice in a 60 second period. */ if (jiffies - host->csr.gen_timestamp[next_gen] < 60 * HZ) /* Wait 60 seconds from the last time this generation number was * used. */ - reset_delay = (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies; + reset_time = (60 * HZ) + host->csr.gen_timestamp[next_gen]; else /* Wait 1 second in case some other code wants to change the * Config ROM in the near future. */ - reset_delay = HZ; + reset_time = jiffies + HZ; - PREPARE_WORK(&host->delayed_reset, delayed_reset_bus, host); - schedule_delayed_work(&host->delayed_reset, reset_delay); + /* This will add the timer as well as modify it */ + mod_timer(&host->delayed_reset, reset_time); return 0; } diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 9a3c58654..c6fa4c81c 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -1034,11 +1033,6 @@ static int hpsbpkt_thread(void *__hi) if (khpsbpkt_kill) break; - if (current->flags & PF_FREEZE) { - refrigerator(0); - continue; - } - while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) { packet = (struct hpsb_packet *)skb->data; diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index c912be4b2..9bfd293d1 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "ieee1394_types.h" @@ -1475,20 +1474,11 @@ static int nodemgr_host_thread(void *__hi) /* Sit and wait for a signal to probe the nodes on the bus. This * happens when we get a bus reset. */ - while (1) { + while (!down_interruptible(&hi->reset_sem) && + !down_interruptible(&nodemgr_serialize)) { unsigned int generation = 0; int i; - if (down_interruptible(&hi->reset_sem) || - down_interruptible(&nodemgr_serialize)) { - if (current->flags & PF_FREEZE) { - refrigerator(0); - continue; - } - printk("NodeMgr: received unexpected signal?!\n" ); - break; - } - if (hi->kill_me) break; diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 78a4f8ed5..624cca549 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -78,7 +78,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 1219 $ Ben Collins "; + "$Rev: 1205 $ Ben Collins "; /* * Module load parameter definitions diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 94dece474..b7862843c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -44,13 +44,6 @@ config INPUT_MOUSEDEV_PSAUX bool "Provide legacy /dev/psaux device" default y depends on INPUT_MOUSEDEV - ---help--- - Say Y here if you want your mouse also be accessible as char device - 10:1 - /dev/psaux. The data available through /dev/psaux is exactly - the same as the data from /dev/input/mice. - - If unsure, say Y. - config INPUT_MOUSEDEV_SCREEN_X int "Horizontal screen resolution" diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 3737e5abc..4f784c877 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -126,7 +126,7 @@ static int evdev_open(struct inode * inode, struct file * file) int i = iminor(inode) - EVDEV_MINOR_BASE; int accept_err; - if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) + if (i >= EVDEV_MINORS || !evdev_table[i]) return -ENODEV; if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) @@ -175,7 +175,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count return -EAGAIN; retval = wait_event_interruptible(list->evdev->wait, - list->head != list->tail || (!list->evdev->exist)); + list->head != list->tail && list->evdev->exist); if (retval) return retval; @@ -222,7 +222,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case EVIOCGID: return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0; - + case EVIOCGKEYCODE: if (get_user(t, ip)) return -EFAULT; if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL; @@ -430,7 +430,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); - class_simple_device_add(input_class, + class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), dev->dev, "event%d", minor); diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index f31ce0bad..352878953 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -12,18 +12,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -59,7 +59,7 @@ struct ns558 { char phys[32]; char name[32]; }; - + static LIST_HEAD(ns558_list); /* @@ -116,7 +116,7 @@ static void ns558_isa_probe(int io) i = 0; goto out; } -/* +/* * And now find the number of mirrors of the port. */ @@ -292,7 +292,7 @@ void __exit ns558_exit(void) release_region(port->gameport.io & ~(port->size - 1), port->size); kfree(port); break; - + default: break; } diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c index 02c31b779..fa20a3376 100644 --- a/drivers/input/gameport/vortex.c +++ b/drivers/input/gameport/vortex.c @@ -83,7 +83,7 @@ static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32)); if (axes[i] == 0x1fff) axes[i] = -1; } - + return 0; } @@ -122,7 +122,7 @@ static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_i vortex->gameport.driver = vortex; vortex->gameport.fuzz = 64; - + vortex->gameport.read = vortex_read; vortex->gameport.trigger = vortex_trigger; vortex->gameport.cooked_read = vortex_cooked_read; @@ -145,7 +145,7 @@ static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_i vortex->io = vortex->base + id->driver_data; gameport_register_port(&vortex->gameport); - + printk(KERN_INFO "gameport at pci%s speed %d kHz\n", pci_name(dev), vortex->gameport.speed); diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index da70b5dea..10ef222a1 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -11,18 +11,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -72,8 +72,8 @@ MODULE_LICENSE("GPL"); */ static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", - "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", - "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", + "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", + "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", "WingMan GamePad USB", "Unknown Device %#x" }; static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; @@ -178,7 +178,7 @@ static void adi_read_packet(struct adi_port *port) /* * adi_move_bits() detects a possible 2-stream mode, and moves - * the bits accordingly. + * the bits accordingly. */ static void adi_move_bits(struct adi_port *port, int length) @@ -208,7 +208,7 @@ static inline int adi_get_bits(struct adi *adi, int count) int i; if ((adi->idx += count) > adi->ret) return 0; for (i = 0; i < count; i++) - bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; + bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; return bits; } @@ -224,12 +224,12 @@ static int adi_decode(struct adi *adi) int i, t; if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) - return -1; + return -1; - for (i = 0; i < adi->axes10; i++) + for (i = 0; i < adi->axes10; i++) input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); - for (i = 0; i < adi->axes8; i++) + for (i = 0; i < adi->axes8; i++) input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); for (i = 0; i < adi->buttons && i < 63; i++) { @@ -249,7 +249,7 @@ static int adi_decode(struct adi *adi) for (i = 63; i < adi->buttons; i++) input_report_key(dev, *key++, adi_get_bits(adi, 1)); - + input_sync(dev); return 0; @@ -294,7 +294,7 @@ static int adi_open(struct input_dev *dev) { struct adi_port *port = dev->private; if (!port->used++) - mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME); + mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME); return 0; } @@ -334,7 +334,7 @@ static void adi_id_decode(struct adi *adi, struct adi_port *port) return; if (adi->ret < (t = adi_get_bits(adi, 10))) { - printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); + printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); return; } @@ -498,7 +498,7 @@ static void adi_connect(struct gameport *gameport, struct gameport_dev *dev) adi_init_digital(gameport); adi_read_packet(port); - + if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) adi_move_bits(port, adi_get_bits(port->adi, 10)); diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 3e83968a9..5d10a6475 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -11,18 +11,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -237,7 +237,7 @@ static int analog_cooked_read(struct analog_port *port) loopout = (ANALOG_LOOP_TIME * port->loop) / 1000; timeout = ANALOG_MAX_TIME * port->speed; - + local_irq_save(flags); gameport_trigger(gameport); GET_TIME(now); @@ -284,7 +284,7 @@ static int analog_button_read(struct analog_port *port, char saitek, char chf) u = gameport_read(port->gameport); - if (!chf) { + if (!chf) { port->buttons = (~u >> 4) & 0xf; return 0; } @@ -333,7 +333,7 @@ static void analog_timer(unsigned long data) } } - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) if (port->analog[i].mask) analog_decode(port->analog + i, port->axes, port->initial, port->buttons); @@ -348,7 +348,7 @@ static int analog_open(struct input_dev *dev) { struct analog_port *port = dev->private; if (!port->used++) - mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME); + mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME); return 0; } @@ -408,7 +408,7 @@ static void analog_calibrate_timer(struct analog_port *port) static void analog_name(struct analog *analog) { - sprintf(analog->name, "Analog %d-axis %d-button", + sprintf(analog->name, "Analog %d-axis %d-button", hweight8(analog->mask & ANALOG_AXES_STD), hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); @@ -450,10 +450,10 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, analog->dev.close = analog_close; analog->dev.private = port; analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - + for (i = j = 0; i < 4; i++) if (analog->mask & (1 << i)) { - + t = analog_axes[j]; x = port->axes[i]; y = (port->axes[0] + port->axes[1]) >> 1; @@ -481,8 +481,8 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, j++; } - for (i = j = 0; i < 3; i++) - if (analog->mask & analog_exts[i]) + for (i = j = 0; i < 3; i++) + if (analog->mask & analog_exts[i]) for (x = 0; x < 2; x++) { t = analog_hats[j++]; set_bit(t, analog->dev.absbit); @@ -517,7 +517,7 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, else printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME, port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, - port->speed > 10000 ? "M" : "k", + port->speed > 10000 ? "M" : "k", port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000) : (port->loop * 1000000) / port->speed); } @@ -580,11 +580,11 @@ static int analog_init_masks(struct analog_port *port) gameport_calibrate(port->gameport, port->axes, max); } - - for (i = 0; i < 4; i++) + + for (i = 0; i < 4; i++) port->initial[i] = port->axes[i]; - return -!(analog[0].mask || analog[1].mask); + return -!(analog[0].mask || analog[1].mask); } static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port) @@ -606,7 +606,7 @@ static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, msleep(ANALOG_MAX_TIME); port->mask = (gameport_read(gameport) ^ t) & t & 0xf; port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS; - + for (i = 0; i < ANALOG_INIT_RETRIES; i++) { if (!analog_cooked_read(port)) break; msleep(ANALOG_MAX_TIME); @@ -617,11 +617,11 @@ static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, msleep(ANALOG_MAX_TIME); t = gameport_time(gameport, ANALOG_MAX_TIME * 1000); gameport_trigger(gameport); - while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; + while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; udelay(ANALOG_SAITEK_DELAY); t = gameport_time(gameport, ANALOG_SAITEK_TIME); gameport_trigger(gameport); - while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; + while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; if (v < (u >> 1)) { /* FIXME - more than one port */ analog_options[0] |= /* FIXME - more than one port */ @@ -721,7 +721,7 @@ static void analog_parse_options(void) if (!strcmp(analog_types[j].name, js[i])) { analog_options[i] = analog_types[j].value; break; - } + } if (analog_types[j].name) continue; analog_options[i] = simple_strtoul(js[i], &end, 0); diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 10cc6ca9c..7cec946d4 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -11,18 +11,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -223,7 +223,7 @@ static int gf2k_open(struct input_dev *dev) { struct gf2k *gf2k = dev->private; if (!gf2k->used++) - mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH); + mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH); return 0; } @@ -324,7 +324,7 @@ static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev) for (i = 0; i < gf2k_axes[gf2k->id]; i++) { gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 : - gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; + gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; gf2k->dev.absmin[gf2k_abs[i]] = 32; gf2k->dev.absfuzz[gf2k_abs[i]] = 8; gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; diff --git a/drivers/input/misc/98spkr.c b/drivers/input/misc/98spkr.c index cdb6c0d14..80fc6ee55 100644 --- a/drivers/input/misc/98spkr.c +++ b/drivers/input/misc/98spkr.c @@ -42,11 +42,11 @@ static int spkr98_event(struct input_dev *dev, unsigned int type, unsigned int c case SND_BELL: if (value) value = 1000; case SND_TONE: break; default: return -1; - } + } if (value > 20 && value < 32767) count = PIT_TICK_RATE / value; - + spin_lock_irqsave(&i8253_beep_lock, flags); if (count) { diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 830d1c37c..f06600fc3 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -41,11 +41,11 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c case SND_BELL: if (value) value = 1000; case SND_TONE: break; default: return -1; - } + } if (value > 20 && value < 32767) count = PIT_TICK_RATE / value; - + spin_lock_irqsave(&i8253_beep_lock, flags); if (count) { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index f266b7ef5..5482e86de 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -2,7 +2,6 @@ * Input driver to ExplorerPS/2 device driver module. * * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published by @@ -48,24 +47,15 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; module_param(yres, uint, 0); MODULE_PARM_DESC(yres, "Vertical screen resolution"); -struct mousedev_motion { - int dx, dy, dz; -}; - struct mousedev { int exist; int open; int minor; + int misc; char name[16]; wait_queue_head_t wait; struct list_head list; struct input_handle handle; - - struct mousedev_motion packet; - unsigned long buttons; - unsigned int pkt_count; - int old_x[4], old_y[4]; - unsigned int touch; }; struct mousedev_list { @@ -73,10 +63,13 @@ struct mousedev_list { struct mousedev *mousedev; struct list_head node; int dx, dy, dz; + int old_x[4], old_y[4]; unsigned long buttons; signed char ps2[6]; unsigned char ready, buffer, bufsiz; unsigned char mode, imexseq, impsseq; + unsigned int pkt_count; + unsigned char touch; }; #define MOUSEDEV_SEQ_LEN 6 @@ -89,157 +82,135 @@ static struct input_handler mousedev_handler; static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev mousedev_mix; -#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) -#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) +#define fx(i) (list->old_x[(list->pkt_count - (i)) & 03]) +#define fy(i) (list->old_y[(list->pkt_count - (i)) & 03]) -static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value) { - if (mousedev->touch) { - switch (code) { - case ABS_X: - fx(0) = value; - if (mousedev->pkt_count >= 2) - mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; - break; + int size; + int touchpad; - case ABS_Y: - fy(0) = value; - if (mousedev->pkt_count >= 2) - mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; - break; - } - } -} + /* Ignore joysticks */ + if (test_bit(BTN_TRIGGER, handle->dev->keybit)) + return; -static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) -{ - int size; + touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit); switch (code) { case ABS_X: - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) size = xres; - mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size; - mousedev->old_x[0] = mousedev->packet.dx * size; + if (touchpad) { + if (list->touch) { + fx(0) = value; + if (list->pkt_count >= 2) + list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; + } + } else { + size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; + if (size == 0) size = xres; + list->dx += (value * xres - list->old_x[0]) / size; + list->old_x[0] += list->dx * size; + } break; - case ABS_Y: - size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; - if (size == 0) size = yres; - mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size; - mousedev->old_y[0] = mousedev->packet.dy * size; + if (touchpad) { + if (list->touch) { + fy(0) = value; + if (list->pkt_count >= 2) + list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; + } + } else { + size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; + if (size == 0) size = yres; + list->dy -= (value * yres - list->old_y[0]) / size; + list->old_y[0] -= list->dy * size; + } break; } } -static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value) -{ - switch (code) { - case REL_X: mousedev->packet.dx += value; break; - case REL_Y: mousedev->packet.dy -= value; break; - case REL_WHEEL: mousedev->packet.dz -= value; break; - } -} - -static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value) -{ - int index; - - switch (code) { - case BTN_TOUCH: - case BTN_0: - case BTN_FORWARD: - case BTN_LEFT: index = 0; break; - case BTN_STYLUS: - case BTN_1: - case BTN_RIGHT: index = 1; break; - case BTN_2: - case BTN_STYLUS2: - case BTN_MIDDLE: index = 2; break; - case BTN_3: - case BTN_BACK: - case BTN_SIDE: index = 3; break; - case BTN_4: - case BTN_EXTRA: index = 4; break; - default: return; - } - - if (value) { - set_bit(index, &mousedev->buttons); - set_bit(index, &mousedev_mix.buttons); - } else { - clear_bit(index, &mousedev->buttons); - clear_bit(index, &mousedev_mix.buttons); - } -} - -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) -{ - struct mousedev_list *list; - - list_for_each_entry(list, &mousedev->list, node) { - list->dx += packet->dx; - list->dy += packet->dy; - list->dz += packet->dz; - list->buttons = mousedev->buttons; - list->ready = 1; - kill_fasync(&list->fasync, SIGIO, POLL_IN); - } - - wake_up_interruptible(&mousedev->wait); -} - static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - struct mousedev *mousedev = handle->private; - - switch (type) { - case EV_ABS: - /* Ignore joysticks */ - if (test_bit(BTN_TRIGGER, handle->dev->keybit)) - return; - - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_event(mousedev, code, value); - else - mousedev_abs_event(handle->dev, mousedev, code, value); - - break; - - case EV_REL: - mousedev_rel_event(mousedev, code, value); - break; - - case EV_KEY: - if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - /* Handle touchpad data */ - mousedev->touch = value; - if (!mousedev->touch) - mousedev->pkt_count = 0; - } - else - mousedev_key_event(mousedev, code, value); + struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; + struct mousedev **mousedev = mousedevs; + struct mousedev_list *list; + int index, wake; + + while (*mousedev) { + + wake = 0; + + list_for_each_entry(list, &(*mousedev)->list, node) + switch (type) { + case EV_ABS: + mousedev_abs_event(handle, list, code, value); + break; + + case EV_REL: + switch (code) { + case REL_X: list->dx += value; break; + case REL_Y: list->dy -= value; break; + case REL_WHEEL: if (list->mode) list->dz -= value; break; + } + break; + + case EV_KEY: + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { + /* Handle touchpad data */ + list->touch = value; + if (!list->touch) + list->pkt_count = 0; + break; + } + + switch (code) { + case BTN_TOUCH: + case BTN_0: + case BTN_FORWARD: + case BTN_LEFT: index = 0; break; + case BTN_4: + case BTN_EXTRA: if (list->mode == 2) { index = 4; break; } + case BTN_STYLUS: + case BTN_1: + case BTN_RIGHT: index = 1; break; + case BTN_3: + case BTN_BACK: + case BTN_SIDE: if (list->mode == 2) { index = 3; break; } + case BTN_2: + case BTN_STYLUS2: + case BTN_MIDDLE: index = 2; break; + default: return; + } + switch (value) { + case 0: clear_bit(index, &list->buttons); break; + case 1: set_bit(index, &list->buttons); break; + case 2: return; + } + break; + + case EV_SYN: + switch (code) { + case SYN_REPORT: + if (list->touch) { + list->pkt_count++; + /* Input system eats duplicate events, + * but we need all of them to do correct + * averaging so apply present one forward + */ + fx(0) = fx(1); + fy(0) = fy(1); + } + + list->ready = 1; + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake = 1; + break; + } } - break; - - case EV_SYN: - if (code == SYN_REPORT) { - if (mousedev->touch) { - mousedev->pkt_count++; - /* Input system eats duplicate events, but we need all of them - * to do correct averaging so apply present one forward - */ - fx(0) = fx(1); - fy(0) = fy(1); - } - mousedev_notify_readers(mousedev, &mousedev->packet); - mousedev_notify_readers(&mousedev_mix, &mousedev->packet); + if (wake) + wake_up_interruptible(&((*mousedev)->wait)); - memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); - } - break; + mousedev++; } } @@ -296,7 +267,7 @@ static int mousedev_release(struct inode * inode, struct file * file) mousedev_free(list->mousedev); } } - + kfree(list); return 0; } @@ -330,11 +301,11 @@ static int mousedev_open(struct inode * inode, struct file * file) if (list->mousedev->minor == MOUSEDEV_MIX) { list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { mousedev = handle->private; - if (!mousedev->open && mousedev->exist) + if (!mousedev->open && mousedev->exist) input_open_device(handle); } - } else - if (!mousedev_mix.open && list->mousedev->exist) + } else + if (!mousedev_mix.open && list->mousedev->exist) input_open_device(&list->mousedev->handle); } @@ -355,10 +326,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off) list->dz -= list->ps2[off + 3]; list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); list->bufsiz++; - } else { - list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); } - + if (list->mode == 1) { list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); list->dz -= list->ps2[off + 3]; @@ -422,9 +391,9 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si list->impsseq = 0; list->imexseq = 0; list->mode = 0; - list->ps2[1] = 0xaa; - list->ps2[2] = 0x00; - list->bufsiz = 3; + list->ps2[0] = 0xaa; + list->ps2[1] = 0x00; + list->bufsiz = 2; break; } @@ -434,7 +403,7 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si kill_fasync(&list->fasync, SIGIO, POLL_IN); wake_up_interruptible(&list->mousedev->wait); - + return count; } @@ -462,7 +431,7 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count)) return -EFAULT; - return count; + return count; } /* No kernel lock - fine */ @@ -518,7 +487,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); - class_simple_device_add(input_class, + class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), dev->dev, "mouse%d", minor); @@ -569,7 +538,7 @@ static struct input_device_id mousedev_ids[] = { }; MODULE_DEVICE_TABLE(input, mousedev_ids); - + static struct input_handler mousedev_handler = { .event = mousedev_event, .connect = mousedev_connect, @@ -584,7 +553,6 @@ static struct input_handler mousedev_handler = { static struct miscdevice psaux_mouse = { PSMOUSE_MINOR, "psaux", &mousedev_fops }; -static int psaux_registered; #endif static int __init mousedev_init(void) @@ -604,7 +572,7 @@ static int __init mousedev_init(void) NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (!(psaux_registered = !misc_register(&psaux_mouse))) + if (!(mousedev_mix.misc = !misc_register(&psaux_mouse))) printk(KERN_WARNING "mice: could not misc_register the device\n"); #endif @@ -616,7 +584,7 @@ static int __init mousedev_init(void) static void __exit mousedev_exit(void) { #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (psaux_registered) + if (mousedev_mix.misc) misc_deregister(&psaux_mouse); #endif devfs_remove("input/mice"); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 19e269249..716fe7d14 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -48,6 +48,11 @@ static int serport_serio_write(struct serio *serio, unsigned char data) return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); } +static int serport_serio_open(struct serio *serio) +{ + return 0; +} + static void serport_serio_close(struct serio *serio) { struct serport *serport = serio->driver; @@ -82,6 +87,7 @@ static int serport_ldisc_open(struct tty_struct *tty) serport->serio.type = SERIO_RS232; serport->serio.write = serport_serio_write; + serport->serio.open = serport_serio_open; serport->serio.close = serport_serio_close; serport->serio.driver = serport; @@ -129,7 +135,7 @@ static int serport_ldisc_room(struct tty_struct *tty) } /* - * serport_ldisc_read() just waits indefinitely if everything goes well. + * serport_ldisc_read() just waits indefinitely if everything goes well. * However, when the serio driver closes the serio port, it finishes, * returning 0 characters. */ @@ -159,7 +165,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) { struct serport *serport = (struct serport*) tty->disc_data; - + if (cmd == SPIOCSTYPE) return get_user(serport->serio.type, (unsigned long __user *) arg); diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c new file mode 100644 index 000000000..17212b420 --- /dev/null +++ b/drivers/md/dm-exception-store.c @@ -0,0 +1,648 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" +#include "dm-snap.h" +#include "dm-io.h" +#include "kcopyd.h" + +#include +#include +#include +#include + +/*----------------------------------------------------------------- + * Persistent snapshots, by persistent we mean that the snapshot + * will survive a reboot. + *---------------------------------------------------------------*/ + +/* + * We need to store a record of which parts of the origin have + * been copied to the snapshot device. The snapshot code + * requires that we copy exception chunks to chunk aligned areas + * of the COW store. It makes sense therefore, to store the + * metadata in chunk size blocks. + * + * There is no backward or forward compatibility implemented, + * snapshots with different disk versions than the kernel will + * not be usable. It is expected that "lvcreate" will blank out + * the start of a fresh COW device before calling the snapshot + * constructor. + * + * The first chunk of the COW device just contains the header. + * After this there is a chunk filled with exception metadata, + * followed by as many exception chunks as can fit in the + * metadata areas. + * + * All on disk structures are in little-endian format. The end + * of the exceptions info is indicated by an exception with a + * new_chunk of 0, which is invalid since it would point to the + * header chunk. + */ + +/* + * Magic for persistent snapshots: "SnAp" - Feeble isn't it. + */ +#define SNAP_MAGIC 0x70416e53 + +/* + * The on-disk version of the metadata. + */ +#define SNAPSHOT_DISK_VERSION 1 + +struct disk_header { + uint32_t magic; + + /* + * Is this snapshot valid. There is no way of recovering + * an invalid snapshot. + */ + uint32_t valid; + + /* + * Simple, incrementing version. no backward + * compatibility. + */ + uint32_t version; + + /* In sectors */ + uint32_t chunk_size; +}; + +struct disk_exception { + uint64_t old_chunk; + uint64_t new_chunk; +}; + +struct commit_callback { + void (*callback)(void *, int success); + void *context; +}; + +/* + * The top level structure for a persistent exception store. + */ +struct pstore { + struct dm_snapshot *snap; /* up pointer to my snapshot */ + int version; + int valid; + uint32_t chunk_size; + uint32_t exceptions_per_area; + + /* + * Now that we have an asynchronous kcopyd there is no + * need for large chunk sizes, so it wont hurt to have a + * whole chunks worth of metadata in memory at once. + */ + void *area; + + /* + * Used to keep track of which metadata area the data in + * 'chunk' refers to. + */ + uint32_t current_area; + + /* + * The next free chunk for an exception. + */ + uint32_t next_free; + + /* + * The index of next free exception in the current + * metadata area. + */ + uint32_t current_committed; + + atomic_t pending_count; + uint32_t callback_count; + struct commit_callback *callbacks; +}; + +static inline unsigned int sectors_to_pages(unsigned int sectors) +{ + return sectors / (PAGE_SIZE >> 9); +} + +static int alloc_area(struct pstore *ps) +{ + int r = -ENOMEM; + size_t len; + + len = ps->chunk_size << SECTOR_SHIFT; + + /* + * Allocate the chunk_size block of memory that will hold + * a single metadata area. + */ + ps->area = vmalloc(len); + if (!ps->area) + return r; + + return 0; +} + +static void free_area(struct pstore *ps) +{ + vfree(ps->area); +} + +/* + * Read or write a chunk aligned and sized block of data from a device. + */ +static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) +{ + struct io_region where; + unsigned long bits; + + where.bdev = ps->snap->cow->bdev; + where.sector = ps->chunk_size * chunk; + where.count = ps->chunk_size; + + return dm_io_sync_vm(1, &where, rw, ps->area, &bits); +} + +/* + * Read or write a metadata area. Remembering to skip the first + * chunk which holds the header. + */ +static int area_io(struct pstore *ps, uint32_t area, int rw) +{ + int r; + uint32_t chunk; + + /* convert a metadata area index to a chunk index */ + chunk = 1 + ((ps->exceptions_per_area + 1) * area); + + r = chunk_io(ps, chunk, rw); + if (r) + return r; + + ps->current_area = area; + return 0; +} + +static int zero_area(struct pstore *ps, uint32_t area) +{ + memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); + return area_io(ps, area, WRITE); +} + +static int read_header(struct pstore *ps, int *new_snapshot) +{ + int r; + struct disk_header *dh; + + r = chunk_io(ps, 0, READ); + if (r) + return r; + + dh = (struct disk_header *) ps->area; + + if (le32_to_cpu(dh->magic) == 0) { + *new_snapshot = 1; + + } else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) { + *new_snapshot = 0; + ps->valid = le32_to_cpu(dh->valid); + ps->version = le32_to_cpu(dh->version); + ps->chunk_size = le32_to_cpu(dh->chunk_size); + + } else { + DMWARN("Invalid/corrupt snapshot"); + r = -ENXIO; + } + + return r; +} + +static int write_header(struct pstore *ps) +{ + struct disk_header *dh; + + memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); + + dh = (struct disk_header *) ps->area; + dh->magic = cpu_to_le32(SNAP_MAGIC); + dh->valid = cpu_to_le32(ps->valid); + dh->version = cpu_to_le32(ps->version); + dh->chunk_size = cpu_to_le32(ps->chunk_size); + + return chunk_io(ps, 0, WRITE); +} + +/* + * Access functions for the disk exceptions, these do the endian conversions. + */ +static struct disk_exception *get_exception(struct pstore *ps, uint32_t index) +{ + if (index >= ps->exceptions_per_area) + return NULL; + + return ((struct disk_exception *) ps->area) + index; +} + +static int read_exception(struct pstore *ps, + uint32_t index, struct disk_exception *result) +{ + struct disk_exception *e; + + e = get_exception(ps, index); + if (!e) + return -EINVAL; + + /* copy it */ + result->old_chunk = le64_to_cpu(e->old_chunk); + result->new_chunk = le64_to_cpu(e->new_chunk); + + return 0; +} + +static int write_exception(struct pstore *ps, + uint32_t index, struct disk_exception *de) +{ + struct disk_exception *e; + + e = get_exception(ps, index); + if (!e) + return -EINVAL; + + /* copy it */ + e->old_chunk = cpu_to_le64(de->old_chunk); + e->new_chunk = cpu_to_le64(de->new_chunk); + + return 0; +} + +/* + * Registers the exceptions that are present in the current area. + * 'full' is filled in to indicate if the area has been + * filled. + */ +static int insert_exceptions(struct pstore *ps, int *full) +{ + int r; + unsigned int i; + struct disk_exception de; + + /* presume the area is full */ + *full = 1; + + for (i = 0; i < ps->exceptions_per_area; i++) { + r = read_exception(ps, i, &de); + + if (r) + return r; + + /* + * If the new_chunk is pointing at the start of + * the COW device, where the first metadata area + * is we know that we've hit the end of the + * exceptions. Therefore the area is not full. + */ + if (de.new_chunk == 0LL) { + ps->current_committed = i; + *full = 0; + break; + } + + /* + * Keep track of the start of the free chunks. + */ + if (ps->next_free <= de.new_chunk) + ps->next_free = de.new_chunk + 1; + + /* + * Otherwise we add the exception to the snapshot. + */ + r = dm_add_exception(ps->snap, de.old_chunk, de.new_chunk); + if (r) + return r; + } + + return 0; +} + +static int read_exceptions(struct pstore *ps) +{ + uint32_t area; + int r, full = 1; + + /* + * Keeping reading chunks and inserting exceptions until + * we find a partially full area. + */ + for (area = 0; full; area++) { + r = area_io(ps, area, READ); + if (r) + return r; + + r = insert_exceptions(ps, &full); + if (r) + return r; + } + + return 0; +} + +static inline struct pstore *get_info(struct exception_store *store) +{ + return (struct pstore *) store->context; +} + +static void persistent_fraction_full(struct exception_store *store, + sector_t *numerator, sector_t *denominator) +{ + *numerator = get_info(store)->next_free * store->snap->chunk_size; + *denominator = get_dev_size(store->snap->cow->bdev); +} + +static void persistent_destroy(struct exception_store *store) +{ + struct pstore *ps = get_info(store); + + dm_io_put(sectors_to_pages(ps->chunk_size)); + vfree(ps->callbacks); + free_area(ps); + kfree(ps); +} + +static int persistent_read_metadata(struct exception_store *store) +{ + int r, new_snapshot; + struct pstore *ps = get_info(store); + + /* + * Read the snapshot header. + */ + r = read_header(ps, &new_snapshot); + if (r) + return r; + + /* + * Do we need to setup a new snapshot ? + */ + if (new_snapshot) { + r = write_header(ps); + if (r) { + DMWARN("write_header failed"); + return r; + } + + r = zero_area(ps, 0); + if (r) { + DMWARN("zero_area(0) failed"); + return r; + } + + } else { + /* + * Sanity checks. + */ + if (!ps->valid) { + DMWARN("snapshot is marked invalid"); + return -EINVAL; + } + + if (ps->version != SNAPSHOT_DISK_VERSION) { + DMWARN("unable to handle snapshot disk version %d", + ps->version); + return -EINVAL; + } + + /* + * Read the metadata. + */ + r = read_exceptions(ps); + if (r) + return r; + } + + return 0; +} + +static int persistent_prepare(struct exception_store *store, + struct exception *e) +{ + struct pstore *ps = get_info(store); + uint32_t stride; + sector_t size = get_dev_size(store->snap->cow->bdev); + + /* Is there enough room ? */ + if (size < ((ps->next_free + 1) * store->snap->chunk_size)) + return -ENOSPC; + + e->new_chunk = ps->next_free; + + /* + * Move onto the next free pending, making sure to take + * into account the location of the metadata chunks. + */ + stride = (ps->exceptions_per_area + 1); + if ((++ps->next_free % stride) == 1) + ps->next_free++; + + atomic_inc(&ps->pending_count); + return 0; +} + +static void persistent_commit(struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context) +{ + int r; + unsigned int i; + struct pstore *ps = get_info(store); + struct disk_exception de; + struct commit_callback *cb; + + de.old_chunk = e->old_chunk; + de.new_chunk = e->new_chunk; + write_exception(ps, ps->current_committed++, &de); + + /* + * Add the callback to the back of the array. This code + * is the only place where the callback array is + * manipulated, and we know that it will never be called + * multiple times concurrently. + */ + cb = ps->callbacks + ps->callback_count++; + cb->callback = callback; + cb->context = callback_context; + + /* + * If there are no more exceptions in flight, or we have + * filled this metadata area we commit the exceptions to + * disk. + */ + if (atomic_dec_and_test(&ps->pending_count) || + (ps->current_committed == ps->exceptions_per_area)) { + r = area_io(ps, ps->current_area, WRITE); + if (r) + ps->valid = 0; + + for (i = 0; i < ps->callback_count; i++) { + cb = ps->callbacks + i; + cb->callback(cb->context, r == 0 ? 1 : 0); + } + + ps->callback_count = 0; + } + + /* + * Have we completely filled the current area ? + */ + if (ps->current_committed == ps->exceptions_per_area) { + ps->current_committed = 0; + r = zero_area(ps, ps->current_area + 1); + if (r) + ps->valid = 0; + } +} + +static void persistent_drop(struct exception_store *store) +{ + struct pstore *ps = get_info(store); + + ps->valid = 0; + if (write_header(ps)) + DMWARN("write header failed"); +} + +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) +{ + int r; + struct pstore *ps; + + r = dm_io_get(sectors_to_pages(chunk_size)); + if (r) + return r; + + /* allocate the pstore */ + ps = kmalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) { + r = -ENOMEM; + goto bad; + } + + ps->snap = store->snap; + ps->valid = 1; + ps->version = SNAPSHOT_DISK_VERSION; + ps->chunk_size = chunk_size; + ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) / + sizeof(struct disk_exception); + ps->next_free = 2; /* skipping the header and first area */ + ps->current_committed = 0; + + r = alloc_area(ps); + if (r) + goto bad; + + /* + * Allocate space for all the callbacks. + */ + ps->callback_count = 0; + atomic_set(&ps->pending_count, 0); + ps->callbacks = dm_vcalloc(ps->exceptions_per_area, + sizeof(*ps->callbacks)); + + if (!ps->callbacks) { + r = -ENOMEM; + goto bad; + } + + store->destroy = persistent_destroy; + store->read_metadata = persistent_read_metadata; + store->prepare_exception = persistent_prepare; + store->commit_exception = persistent_commit; + store->drop_snapshot = persistent_drop; + store->fraction_full = persistent_fraction_full; + store->context = ps; + + return 0; + + bad: + dm_io_put(sectors_to_pages(chunk_size)); + if (ps) { + if (ps->area) + free_area(ps); + + kfree(ps); + } + return r; +} + +/*----------------------------------------------------------------- + * Implementation of the store for non-persistent snapshots. + *---------------------------------------------------------------*/ +struct transient_c { + sector_t next_free; +}; + +static void transient_destroy(struct exception_store *store) +{ + kfree(store->context); +} + +static int transient_read_metadata(struct exception_store *store) +{ + return 0; +} + +static int transient_prepare(struct exception_store *store, struct exception *e) +{ + struct transient_c *tc = (struct transient_c *) store->context; + sector_t size = get_dev_size(store->snap->cow->bdev); + + if (size < (tc->next_free + store->snap->chunk_size)) + return -1; + + e->new_chunk = sector_to_chunk(store->snap, tc->next_free); + tc->next_free += store->snap->chunk_size; + + return 0; +} + +static void transient_commit(struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context) +{ + /* Just succeed */ + callback(callback_context, 1); +} + +static void transient_fraction_full(struct exception_store *store, + sector_t *numerator, sector_t *denominator) +{ + *numerator = ((struct transient_c *) store->context)->next_free; + *denominator = get_dev_size(store->snap->cow->bdev); +} + +int dm_create_transient(struct exception_store *store, + struct dm_snapshot *s, int blocksize) +{ + struct transient_c *tc; + + memset(store, 0, sizeof(*store)); + store->destroy = transient_destroy; + store->read_metadata = transient_read_metadata; + store->prepare_exception = transient_prepare; + store->commit_exception = transient_commit; + store->fraction_full = transient_fraction_full; + store->snap = s; + + tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); + if (!tc) + return -ENOMEM; + + tc->next_free = 0; + store->context = tc; + + return 0; +} diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c new file mode 100644 index 000000000..9f3fb61fd --- /dev/null +++ b/drivers/md/dm-io.c @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2003 Sistina Software + * + * This file is released under the GPL. + */ + +#include "dm-io.h" + +#include +#include +#include +#include +#include + +#define BIO_POOL_SIZE 256 + + +/*----------------------------------------------------------------- + * Bio set, move this to bio.c + *---------------------------------------------------------------*/ +#define BV_NAME_SIZE 16 +struct biovec_pool { + int nr_vecs; + char name[BV_NAME_SIZE]; + kmem_cache_t *slab; + mempool_t *pool; + atomic_t allocated; /* FIXME: debug */ +}; + +#define BIOVEC_NR_POOLS 6 +struct bio_set { + char name[BV_NAME_SIZE]; + kmem_cache_t *bio_slab; + mempool_t *bio_pool; + struct biovec_pool pools[BIOVEC_NR_POOLS]; +}; + +static void bio_set_exit(struct bio_set *bs) +{ + unsigned i; + struct biovec_pool *bp; + + if (bs->bio_pool) + mempool_destroy(bs->bio_pool); + + if (bs->bio_slab) + kmem_cache_destroy(bs->bio_slab); + + for (i = 0; i < BIOVEC_NR_POOLS; i++) { + bp = bs->pools + i; + if (bp->pool) + mempool_destroy(bp->pool); + + if (bp->slab) + kmem_cache_destroy(bp->slab); + } +} + +static void mk_name(char *str, size_t len, const char *prefix, unsigned count) +{ + snprintf(str, len, "%s-%u", prefix, count); +} + +static int bio_set_init(struct bio_set *bs, const char *slab_prefix, + unsigned pool_entries, unsigned scale) +{ + /* FIXME: this must match bvec_index(), why not go the + * whole hog and have a pool per power of 2 ? */ + static unsigned _vec_lengths[BIOVEC_NR_POOLS] = { + 1, 4, 16, 64, 128, BIO_MAX_PAGES + }; + + + unsigned i, size; + struct biovec_pool *bp; + + /* zero the bs so we can tear down properly on error */ + memset(bs, 0, sizeof(*bs)); + + /* + * Set up the bio pool. + */ + snprintf(bs->name, sizeof(bs->name), "%s-bio", slab_prefix); + + bs->bio_slab = kmem_cache_create(bs->name, sizeof(struct bio), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!bs->bio_slab) { + DMWARN("can't init bio slab"); + goto bad; + } + + bs->bio_pool = mempool_create(pool_entries, mempool_alloc_slab, + mempool_free_slab, bs->bio_slab); + if (!bs->bio_pool) { + DMWARN("can't init bio pool"); + goto bad; + } + + /* + * Set up the biovec pools. + */ + for (i = 0; i < BIOVEC_NR_POOLS; i++) { + bp = bs->pools + i; + bp->nr_vecs = _vec_lengths[i]; + atomic_set(&bp->allocated, 1); /* FIXME: debug */ + + + size = bp->nr_vecs * sizeof(struct bio_vec); + + mk_name(bp->name, sizeof(bp->name), slab_prefix, i); + bp->slab = kmem_cache_create(bp->name, size, 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!bp->slab) { + DMWARN("can't init biovec slab cache"); + goto bad; + } + + if (i >= scale) + pool_entries >>= 1; + + bp->pool = mempool_create(pool_entries, mempool_alloc_slab, + mempool_free_slab, bp->slab); + if (!bp->pool) { + DMWARN("can't init biovec mempool"); + goto bad; + } + } + + return 0; + + bad: + bio_set_exit(bs); + return -ENOMEM; +} + +/* FIXME: blech */ +static inline unsigned bvec_index(unsigned nr) +{ + switch (nr) { + case 1: return 0; + case 2 ... 4: return 1; + case 5 ... 16: return 2; + case 17 ... 64: return 3; + case 65 ... 128:return 4; + case 129 ... BIO_MAX_PAGES: return 5; + } + + BUG(); + return 0; +} + +static inline void bs_bio_init(struct bio *bio) +{ + bio->bi_next = NULL; + bio->bi_flags = 1 << BIO_UPTODATE; + bio->bi_rw = 0; + bio->bi_vcnt = 0; + bio->bi_idx = 0; + bio->bi_phys_segments = 0; + bio->bi_hw_segments = 0; + bio->bi_size = 0; + bio->bi_max_vecs = 0; + bio->bi_end_io = NULL; + atomic_set(&bio->bi_cnt, 1); + bio->bi_private = NULL; +} + +static unsigned _bio_count = 0; +struct bio *bio_set_alloc(struct bio_set *bs, int gfp_mask, int nr_iovecs) +{ + struct biovec_pool *bp; + struct bio_vec *bv = NULL; + unsigned long idx; + struct bio *bio; + + bio = mempool_alloc(bs->bio_pool, gfp_mask); + if (unlikely(!bio)) + return NULL; + + bio_init(bio); + + if (likely(nr_iovecs)) { + idx = bvec_index(nr_iovecs); + bp = bs->pools + idx; + bv = mempool_alloc(bp->pool, gfp_mask); + if (!bv) { + mempool_free(bio, bs->bio_pool); + return NULL; + } + + memset(bv, 0, bp->nr_vecs * sizeof(*bv)); + bio->bi_flags |= idx << BIO_POOL_OFFSET; + bio->bi_max_vecs = bp->nr_vecs; + atomic_inc(&bp->allocated); + } + + bio->bi_io_vec = bv; + return bio; +} + +static void bio_set_free(struct bio_set *bs, struct bio *bio) +{ + struct biovec_pool *bp = bs->pools + BIO_POOL_IDX(bio); + + if (atomic_dec_and_test(&bp->allocated)) + BUG(); + + mempool_free(bio->bi_io_vec, bp->pool); + mempool_free(bio, bs->bio_pool); +} + +/*----------------------------------------------------------------- + * dm-io proper + *---------------------------------------------------------------*/ +static struct bio_set _bios; + +/* FIXME: can we shrink this ? */ +struct io { + unsigned long error; + atomic_t count; + struct task_struct *sleeper; + io_notify_fn callback; + void *context; +}; + +/* + * io contexts are only dynamically allocated for asynchronous + * io. Since async io is likely to be the majority of io we'll + * have the same number of io contexts as buffer heads ! (FIXME: + * must reduce this). + */ +static unsigned _num_ios; +static mempool_t *_io_pool; + +static void *alloc_io(int gfp_mask, void *pool_data) +{ + return kmalloc(sizeof(struct io), gfp_mask); +} + +static void free_io(void *element, void *pool_data) +{ + kfree(element); +} + +static unsigned int pages_to_ios(unsigned int pages) +{ + return 4 * pages; /* too many ? */ +} + +static int resize_pool(unsigned int new_ios) +{ + int r = 0; + + if (_io_pool) { + if (new_ios == 0) { + /* free off the pool */ + mempool_destroy(_io_pool); + _io_pool = NULL; + bio_set_exit(&_bios); + + } else { + /* resize the pool */ + r = mempool_resize(_io_pool, new_ios, GFP_KERNEL); + } + + } else { + /* create new pool */ + _io_pool = mempool_create(new_ios, alloc_io, free_io, NULL); + if (!_io_pool) + r = -ENOMEM; + + r = bio_set_init(&_bios, "dm-io", 512, 1); + if (r) { + mempool_destroy(_io_pool); + _io_pool = NULL; + } + } + + if (!r) + _num_ios = new_ios; + + return r; +} + +int dm_io_get(unsigned int num_pages) +{ + return resize_pool(_num_ios + pages_to_ios(num_pages)); +} + +void dm_io_put(unsigned int num_pages) +{ + resize_pool(_num_ios - pages_to_ios(num_pages)); +} + +/*----------------------------------------------------------------- + * We need to keep track of which region a bio is doing io for. + * In order to save a memory allocation we store this the last + * bvec which we know is unused (blech). + *---------------------------------------------------------------*/ +static inline void bio_set_region(struct bio *bio, unsigned region) +{ + bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len = region; +} + +static inline unsigned bio_get_region(struct bio *bio) +{ + return bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len; +} + +/*----------------------------------------------------------------- + * We need an io object to keep track of the number of bios that + * have been dispatched for a particular io. + *---------------------------------------------------------------*/ +static void dec_count(struct io *io, unsigned int region, int error) +{ + if (error) + set_bit(region, &io->error); + + if (atomic_dec_and_test(&io->count)) { + if (io->sleeper) + wake_up_process(io->sleeper); + + else { + int r = io->error; + io_notify_fn fn = io->callback; + void *context = io->context; + + mempool_free(io, _io_pool); + fn(r, context); + } + } +} + +/* FIXME Move this to bio.h? */ +static void zero_fill_bio(struct bio *bio) +{ + unsigned long flags; + struct bio_vec *bv; + int i; + + bio_for_each_segment(bv, bio, i) { + char *data = bvec_kmap_irq(bv, &flags); + memset(data, 0, bv->bv_len); + flush_dcache_page(bv->bv_page); + bvec_kunmap_irq(data, &flags); + } +} + +static int endio(struct bio *bio, unsigned int done, int error) +{ + struct io *io = (struct io *) bio->bi_private; + + /* keep going until we've finished */ + if (bio->bi_size) + return 1; + + if (error && bio_data_dir(bio) == READ) + zero_fill_bio(bio); + + dec_count(io, bio_get_region(bio), error); + bio_put(bio); + + return 0; +} + +static void bio_dtr(struct bio *bio) +{ + _bio_count--; + bio_set_free(&_bios, bio); +} + +/*----------------------------------------------------------------- + * These little objects provide an abstraction for getting a new + * destination page for io. + *---------------------------------------------------------------*/ +struct dpages { + void (*get_page)(struct dpages *dp, + struct page **p, unsigned long *len, unsigned *offset); + void (*next_page)(struct dpages *dp); + + unsigned context_u; + void *context_ptr; +}; + +/* + * Functions for getting the pages from a list. + */ +static void list_get_page(struct dpages *dp, + struct page **p, unsigned long *len, unsigned *offset) +{ + unsigned o = dp->context_u; + struct page_list *pl = (struct page_list *) dp->context_ptr; + + *p = pl->page; + *len = PAGE_SIZE - o; + *offset = o; +} + +static void list_next_page(struct dpages *dp) +{ + struct page_list *pl = (struct page_list *) dp->context_ptr; + dp->context_ptr = pl->next; + dp->context_u = 0; +} + +static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offset) +{ + dp->get_page = list_get_page; + dp->next_page = list_next_page; + dp->context_u = offset; + dp->context_ptr = pl; +} + +/* + * Functions for getting the pages from a bvec. + */ +static void bvec_get_page(struct dpages *dp, + struct page **p, unsigned long *len, unsigned *offset) +{ + struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr; + *p = bvec->bv_page; + *len = bvec->bv_len; + *offset = bvec->bv_offset; +} + +static void bvec_next_page(struct dpages *dp) +{ + struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr; + dp->context_ptr = bvec + 1; +} + +static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec) +{ + dp->get_page = bvec_get_page; + dp->next_page = bvec_next_page; + dp->context_ptr = bvec; +} + +static void vm_get_page(struct dpages *dp, + struct page **p, unsigned long *len, unsigned *offset) +{ + *p = vmalloc_to_page(dp->context_ptr); + *offset = dp->context_u; + *len = PAGE_SIZE - dp->context_u; +} + +static void vm_next_page(struct dpages *dp) +{ + dp->context_ptr += PAGE_SIZE - dp->context_u; + dp->context_u = 0; +} + +static void vm_dp_init(struct dpages *dp, void *data) +{ + dp->get_page = vm_get_page; + dp->next_page = vm_next_page; + dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1); + dp->context_ptr = data; +} + +/*----------------------------------------------------------------- + * IO routines that accept a list of pages. + *---------------------------------------------------------------*/ +static void do_region(int rw, unsigned int region, struct io_region *where, + struct dpages *dp, struct io *io) +{ + struct bio *bio; + struct page *page; + unsigned long len; + unsigned offset; + unsigned num_bvecs; + sector_t remaining = where->count; + + while (remaining) { + /* + * Allocate a suitably sized bio, we add an extra + * bvec for bio_get/set_region(). + */ + num_bvecs = (remaining / (PAGE_SIZE >> 9)) + 2; + _bio_count++; + bio = bio_set_alloc(&_bios, GFP_NOIO, num_bvecs); + bio->bi_sector = where->sector + (where->count - remaining); + bio->bi_bdev = where->bdev; + bio->bi_end_io = endio; + bio->bi_private = io; + bio->bi_destructor = bio_dtr; + bio_set_region(bio, region); + + /* + * Try and add as many pages as possible. + */ + while (remaining) { + dp->get_page(dp, &page, &len, &offset); + len = min(len, to_bytes(remaining)); + if (!bio_add_page(bio, page, len, offset)) + break; + + offset = 0; + remaining -= to_sector(len); + dp->next_page(dp); + } + + atomic_inc(&io->count); + submit_bio(rw, bio); + } +} + +static void dispatch_io(int rw, unsigned int num_regions, + struct io_region *where, struct dpages *dp, + struct io *io, int sync) +{ + int i; + struct dpages old_pages = *dp; + + if (sync) + rw |= (1 << BIO_RW_SYNC); + + /* + * For multiple regions we need to be careful to rewind + * the dp object for each call to do_region. + */ + for (i = 0; i < num_regions; i++) { + *dp = old_pages; + if (where[i].count) + do_region(rw, i, where + i, dp, io); + } + + /* + * Drop the extra refence that we were holding to avoid + * the io being completed too early. + */ + dec_count(io, 0, 0); +} + +static int sync_io(unsigned int num_regions, struct io_region *where, + int rw, struct dpages *dp, unsigned long *error_bits) +{ + struct io io; + + if (num_regions > 1 && rw != WRITE) { + WARN_ON(1); + return -EIO; + } + + io.error = 0; + atomic_set(&io.count, 1); /* see dispatch_io() */ + io.sleeper = current; + + dispatch_io(rw, num_regions, where, dp, &io, 1); + + while (1) { + set_current_state(TASK_UNINTERRUPTIBLE); + + if (!atomic_read(&io.count) || signal_pending(current)) + break; + + io_schedule(); + } + set_current_state(TASK_RUNNING); + + if (atomic_read(&io.count)) + return -EINTR; + + *error_bits = io.error; + return io.error ? -EIO : 0; +} + +static int async_io(unsigned int num_regions, struct io_region *where, int rw, + struct dpages *dp, io_notify_fn fn, void *context) +{ + struct io *io; + + if (num_regions > 1 && rw != WRITE) { + WARN_ON(1); + fn(1, context); + return -EIO; + } + + io = mempool_alloc(_io_pool, GFP_NOIO); + io->error = 0; + atomic_set(&io->count, 1); /* see dispatch_io() */ + io->sleeper = NULL; + io->callback = fn; + io->context = context; + + dispatch_io(rw, num_regions, where, dp, io, 0); + return 0; +} + +int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + unsigned long *error_bits) +{ + struct dpages dp; + list_dp_init(&dp, pl, offset); + return sync_io(num_regions, where, rw, &dp, error_bits); +} + +int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw, + struct bio_vec *bvec, unsigned long *error_bits) +{ + struct dpages dp; + bvec_dp_init(&dp, bvec); + return sync_io(num_regions, where, rw, &dp, error_bits); +} + +int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, unsigned long *error_bits) +{ + struct dpages dp; + vm_dp_init(&dp, data); + return sync_io(num_regions, where, rw, &dp, error_bits); +} + +int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + io_notify_fn fn, void *context) +{ + struct dpages dp; + list_dp_init(&dp, pl, offset); + return async_io(num_regions, where, rw, &dp, fn, context); +} + +int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, + struct bio_vec *bvec, io_notify_fn fn, void *context) +{ + struct dpages dp; + bvec_dp_init(&dp, bvec); + return async_io(num_regions, where, rw, &dp, fn, context); +} + +int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, io_notify_fn fn, void *context) +{ + struct dpages dp; + vm_dp_init(&dp, data); + return async_io(num_regions, where, rw, &dp, fn, context); +} + +EXPORT_SYMBOL(dm_io_get); +EXPORT_SYMBOL(dm_io_put); +EXPORT_SYMBOL(dm_io_sync); +EXPORT_SYMBOL(dm_io_async); +EXPORT_SYMBOL(dm_io_sync_bvec); +EXPORT_SYMBOL(dm_io_async_bvec); +EXPORT_SYMBOL(dm_io_sync_vm); +EXPORT_SYMBOL(dm_io_async_vm); diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h new file mode 100644 index 000000000..1a77f3265 --- /dev/null +++ b/drivers/md/dm-io.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2003 Sistina Software + * + * This file is released under the GPL. + */ + +#ifndef _DM_IO_H +#define _DM_IO_H + +#include "dm.h" + +/* FIXME make this configurable */ +#define DM_MAX_IO_REGIONS 8 + +struct io_region { + struct block_device *bdev; + sector_t sector; + sector_t count; +}; + +struct page_list { + struct page_list *next; + struct page *page; +}; + + +/* + * 'error' is a bitset, with each bit indicating whether an error + * occurred doing io to the corresponding region. + */ +typedef void (*io_notify_fn)(unsigned long error, void *context); + + +/* + * Before anyone uses the IO interface they should call + * dm_io_get(), specifying roughly how many pages they are + * expecting to perform io on concurrently. + * + * This function may block. + */ +int dm_io_get(unsigned int num_pages); +void dm_io_put(unsigned int num_pages); + +/* + * Synchronous IO. + * + * Please ensure that the rw flag in the next two functions is + * either READ or WRITE, ie. we don't take READA. Any + * regions with a zero count field will be ignored. + */ +int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + unsigned long *error_bits); + +int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw, + struct bio_vec *bvec, unsigned long *error_bits); + +int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, unsigned long *error_bits); + +/* + * Aynchronous IO. + * + * The 'where' array may be safely allocated on the stack since + * the function takes a copy. + */ +int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, + struct page_list *pl, unsigned int offset, + io_notify_fn fn, void *context); + +int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, + struct bio_vec *bvec, io_notify_fn fn, void *context); + +int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, + void *data, io_notify_fn fn, void *context); + +#endif diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index e1703f77c..0d508c016 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -417,9 +417,9 @@ static int list_devices(struct dm_ioctl *param, size_t param_size) return 0; } -static void list_version_get_needed(struct target_type *tt, void *needed_param) +static void list_version_get_needed(struct target_type *tt, void *param) { - size_t *needed = needed_param; + int *needed = param; *needed += strlen(tt->name); *needed += sizeof(tt->version); @@ -1133,7 +1133,7 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) * As well as checking the version compatibility this always * copies the kernel interface version out. */ -static int check_version(unsigned int cmd, struct dm_ioctl __user *user) +static int check_version(unsigned int cmd, struct dm_ioctl *user) { uint32_t version[3]; int r = 0; @@ -1168,7 +1168,7 @@ static void free_params(struct dm_ioctl *param) vfree(param); } -static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) { struct dm_ioctl tmp, *dmi; @@ -1225,7 +1225,7 @@ static int ctl_ioctl(struct inode *inode, struct file *file, int r = 0; unsigned int cmd; struct dm_ioctl *param; - struct dm_ioctl __user *user = (struct dm_ioctl __user *) u; + struct dm_ioctl *user = (struct dm_ioctl *) u; ioctl_fn fn = NULL; size_t param_size; diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c new file mode 100644 index 000000000..7a1c77dee --- /dev/null +++ b/drivers/md/dm-log.c @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2003 Sistina Software + * + * This file is released under the LGPL. + */ + +#include +#include +#include +#include + +#include "dm-log.h" +#include "dm-io.h" + +static LIST_HEAD(_log_types); +static spinlock_t _lock = SPIN_LOCK_UNLOCKED; + +int dm_register_dirty_log_type(struct dirty_log_type *type) +{ + if (!try_module_get(type->module)) + return -EINVAL; + + spin_lock(&_lock); + type->use_count = 0; + list_add(&type->list, &_log_types); + spin_unlock(&_lock); + + return 0; +} + +int dm_unregister_dirty_log_type(struct dirty_log_type *type) +{ + spin_lock(&_lock); + + if (type->use_count) + DMWARN("Attempt to unregister a log type that is still in use"); + else { + list_del(&type->list); + module_put(type->module); + } + + spin_unlock(&_lock); + + return 0; +} + +static struct dirty_log_type *get_type(const char *type_name) +{ + struct dirty_log_type *type; + + spin_lock(&_lock); + list_for_each_entry (type, &_log_types, list) + if (!strcmp(type_name, type->name)) { + type->use_count++; + spin_unlock(&_lock); + return type; + } + + spin_unlock(&_lock); + return NULL; +} + +static void put_type(struct dirty_log_type *type) +{ + spin_lock(&_lock); + type->use_count--; + spin_unlock(&_lock); +} + +struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti, + unsigned int argc, char **argv) +{ + struct dirty_log_type *type; + struct dirty_log *log; + + log = kmalloc(sizeof(*log), GFP_KERNEL); + if (!log) + return NULL; + + type = get_type(type_name); + if (!type) { + kfree(log); + return NULL; + } + + log->type = type; + if (type->ctr(log, ti, argc, argv)) { + kfree(log); + put_type(type); + return NULL; + } + + return log; +} + +void dm_destroy_dirty_log(struct dirty_log *log) +{ + log->type->dtr(log); + put_type(log->type); + kfree(log); +} + +/*----------------------------------------------------------------- + * Persistent and core logs share a lot of their implementation. + * FIXME: need a reload method to be called from a resume + *---------------------------------------------------------------*/ +/* + * Magic for persistent mirrors: "MiRr" + */ +#define MIRROR_MAGIC 0x4D695272 + +/* + * The on-disk version of the metadata. + */ +#define MIRROR_DISK_VERSION 1 +#define LOG_OFFSET 2 + +struct log_header { + uint32_t magic; + + /* + * Simple, incrementing version. no backward + * compatibility. + */ + uint32_t version; + sector_t nr_regions; +}; + +struct log_c { + struct dm_target *ti; + int touched; + sector_t region_size; + unsigned int region_count; + region_t sync_count; + + unsigned bitset_uint32_count; + uint32_t *clean_bits; + uint32_t *sync_bits; + uint32_t *recovering_bits; /* FIXME: this seems excessive */ + + int sync_search; + + /* + * Disk log fields + */ + struct dm_dev *log_dev; + struct log_header header; + + struct io_region header_location; + struct log_header *disk_header; + + struct io_region bits_location; + uint32_t *disk_bits; +}; + +/* + * The touched member needs to be updated every time we access + * one of the bitsets. + */ +static inline int log_test_bit(uint32_t *bs, unsigned bit) +{ + return test_bit(bit, (unsigned long *) bs) ? 1 : 0; +} + +static inline void log_set_bit(struct log_c *l, + uint32_t *bs, unsigned bit) +{ + set_bit(bit, (unsigned long *) bs); + l->touched = 1; +} + +static inline void log_clear_bit(struct log_c *l, + uint32_t *bs, unsigned bit) +{ + clear_bit(bit, (unsigned long *) bs); + l->touched = 1; +} + +/*---------------------------------------------------------------- + * Header IO + *--------------------------------------------------------------*/ +static void header_to_disk(struct log_header *core, struct log_header *disk) +{ + disk->magic = cpu_to_le32(core->magic); + disk->version = cpu_to_le32(core->version); + disk->nr_regions = cpu_to_le64(core->nr_regions); +} + +static void header_from_disk(struct log_header *core, struct log_header *disk) +{ + core->magic = le32_to_cpu(disk->magic); + core->version = le32_to_cpu(disk->version); + core->nr_regions = le64_to_cpu(disk->nr_regions); +} + +static int read_header(struct log_c *log) +{ + int r; + unsigned long ebits; + + r = dm_io_sync_vm(1, &log->header_location, READ, + log->disk_header, &ebits); + if (r) + return r; + + header_from_disk(&log->header, log->disk_header); + + if (log->header.magic != MIRROR_MAGIC) { + log->header.magic = MIRROR_MAGIC; + log->header.version = MIRROR_DISK_VERSION; + log->header.nr_regions = 0; + } + + if (log->header.version != MIRROR_DISK_VERSION) { + DMWARN("incompatible disk log version"); + return -EINVAL; + } + + return 0; +} + +static inline int write_header(struct log_c *log) +{ + unsigned long ebits; + + header_to_disk(&log->header, log->disk_header); + return dm_io_sync_vm(1, &log->header_location, WRITE, + log->disk_header, &ebits); +} + +/*---------------------------------------------------------------- + * Bits IO + *--------------------------------------------------------------*/ +static inline void bits_to_core(uint32_t *core, uint32_t *disk, unsigned count) +{ + unsigned i; + + for (i = 0; i < count; i++) + core[i] = le32_to_cpu(disk[i]); +} + +static inline void bits_to_disk(uint32_t *core, uint32_t *disk, unsigned count) +{ + unsigned i; + + /* copy across the clean/dirty bitset */ + for (i = 0; i < count; i++) + disk[i] = cpu_to_le32(core[i]); +} + +static int read_bits(struct log_c *log) +{ + int r; + unsigned long ebits; + + r = dm_io_sync_vm(1, &log->bits_location, READ, + log->disk_bits, &ebits); + if (r) + return r; + + bits_to_core(log->clean_bits, log->disk_bits, + log->bitset_uint32_count); + return 0; +} + +static int write_bits(struct log_c *log) +{ + unsigned long ebits; + bits_to_disk(log->clean_bits, log->disk_bits, + log->bitset_uint32_count); + return dm_io_sync_vm(1, &log->bits_location, WRITE, + log->disk_bits, &ebits); +} + +/*---------------------------------------------------------------- + * constructor/destructor + *--------------------------------------------------------------*/ +#define BYTE_SHIFT 3 +static int core_ctr(struct dirty_log *log, struct dm_target *ti, + unsigned int argc, char **argv) +{ + struct log_c *lc; + sector_t region_size; + unsigned int region_count; + size_t bitset_size; + + if (argc != 1) { + DMWARN("wrong number of arguments to log_c"); + return -EINVAL; + } + + if (sscanf(argv[0], SECTOR_FORMAT, ®ion_size) != 1) { + DMWARN("invalid region size string"); + return -EINVAL; + } + + region_count = dm_div_up(ti->len, region_size); + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { + DMWARN("couldn't allocate core log"); + return -ENOMEM; + } + + lc->ti = ti; + lc->touched = 0; + lc->region_size = region_size; + lc->region_count = region_count; + + /* + * Work out how many words we need to hold the bitset. + */ + bitset_size = dm_round_up(region_count, + sizeof(*lc->clean_bits) << BYTE_SHIFT); + bitset_size >>= BYTE_SHIFT; + + lc->bitset_uint32_count = bitset_size / 4; + lc->clean_bits = vmalloc(bitset_size); + if (!lc->clean_bits) { + DMWARN("couldn't allocate clean bitset"); + kfree(lc); + return -ENOMEM; + } + memset(lc->clean_bits, -1, bitset_size); + + lc->sync_bits = vmalloc(bitset_size); + if (!lc->sync_bits) { + DMWARN("couldn't allocate sync bitset"); + vfree(lc->clean_bits); + kfree(lc); + return -ENOMEM; + } + memset(lc->sync_bits, 0, bitset_size); + lc->sync_count = 0; + + lc->recovering_bits = vmalloc(bitset_size); + if (!lc->recovering_bits) { + DMWARN("couldn't allocate sync bitset"); + vfree(lc->sync_bits); + vfree(lc->clean_bits); + kfree(lc); + return -ENOMEM; + } + memset(lc->recovering_bits, 0, bitset_size); + lc->sync_search = 0; + log->context = lc; + return 0; +} + +static void core_dtr(struct dirty_log *log) +{ + struct log_c *lc = (struct log_c *) log->context; + vfree(lc->clean_bits); + vfree(lc->sync_bits); + vfree(lc->recovering_bits); + kfree(lc); +} + +static int disk_ctr(struct dirty_log *log, struct dm_target *ti, + unsigned int argc, char **argv) +{ + int r; + size_t size; + struct log_c *lc; + struct dm_dev *dev; + + if (argc != 2) { + DMWARN("wrong number of arguments to log_d"); + return -EINVAL; + } + + r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */, + FMODE_READ | FMODE_WRITE, &dev); + if (r) + return r; + + r = core_ctr(log, ti, argc - 1, argv + 1); + if (r) { + dm_put_device(ti, dev); + return r; + } + + lc = (struct log_c *) log->context; + lc->log_dev = dev; + + /* setup the disk header fields */ + lc->header_location.bdev = lc->log_dev->bdev; + lc->header_location.sector = 0; + lc->header_location.count = 1; + + /* + * We can't read less than this amount, even though we'll + * not be using most of this space. + */ + lc->disk_header = vmalloc(1 << SECTOR_SHIFT); + if (!lc->disk_header) + goto bad; + + /* setup the disk bitset fields */ + lc->bits_location.bdev = lc->log_dev->bdev; + lc->bits_location.sector = LOG_OFFSET; + + size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t), + 1 << SECTOR_SHIFT); + lc->bits_location.count = size >> SECTOR_SHIFT; + lc->disk_bits = vmalloc(size); + if (!lc->disk_bits) { + vfree(lc->disk_header); + goto bad; + } + return 0; + + bad: + dm_put_device(ti, lc->log_dev); + core_dtr(log); + return -ENOMEM; +} + +static void disk_dtr(struct dirty_log *log) +{ + struct log_c *lc = (struct log_c *) log->context; + dm_put_device(lc->ti, lc->log_dev); + vfree(lc->disk_header); + vfree(lc->disk_bits); + core_dtr(log); +} + +static int count_bits32(uint32_t *addr, unsigned size) +{ + int count = 0, i; + + for (i = 0; i < size; i++) { + count += hweight32(*(addr+i)); + } + return count; +} + +static int disk_resume(struct dirty_log *log) +{ + int r; + unsigned i; + struct log_c *lc = (struct log_c *) log->context; + size_t size = lc->bitset_uint32_count * sizeof(uint32_t); + + /* read the disk header */ + r = read_header(lc); + if (r) + return r; + + /* read the bits */ + r = read_bits(lc); + if (r) + return r; + + /* zero any new bits if the mirror has grown */ + for (i = lc->header.nr_regions; i < lc->region_count; i++) + /* FIXME: amazingly inefficient */ + log_clear_bit(lc, lc->clean_bits, i); + + /* copy clean across to sync */ + memcpy(lc->sync_bits, lc->clean_bits, size); + lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); + + /* write the bits */ + r = write_bits(lc); + if (r) + return r; + + /* set the correct number of regions in the header */ + lc->header.nr_regions = lc->region_count; + + /* write the new header */ + return write_header(lc); +} + +static sector_t core_get_region_size(struct dirty_log *log) +{ + struct log_c *lc = (struct log_c *) log->context; + return lc->region_size; +} + +static int core_is_clean(struct dirty_log *log, region_t region) +{ + struct log_c *lc = (struct log_c *) log->context; + return log_test_bit(lc->clean_bits, region); +} + +static int core_in_sync(struct dirty_log *log, region_t region, int block) +{ + struct log_c *lc = (struct log_c *) log->context; + return log_test_bit(lc->sync_bits, region); +} + +static int core_flush(struct dirty_log *log) +{ + /* no op */ + return 0; +} + +static int disk_flush(struct dirty_log *log) +{ + int r; + struct log_c *lc = (struct log_c *) log->context; + + /* only write if the log has changed */ + if (!lc->touched) + return 0; + + r = write_bits(lc); + if (!r) + lc->touched = 0; + + return r; +} + +static void core_mark_region(struct dirty_log *log, region_t region) +{ + struct log_c *lc = (struct log_c *) log->context; + log_clear_bit(lc, lc->clean_bits, region); +} + +static void core_clear_region(struct dirty_log *log, region_t region) +{ + struct log_c *lc = (struct log_c *) log->context; + log_set_bit(lc, lc->clean_bits, region); +} + +static int core_get_resync_work(struct dirty_log *log, region_t *region) +{ + struct log_c *lc = (struct log_c *) log->context; + + if (lc->sync_search >= lc->region_count) + return 0; + + do { + *region = find_next_zero_bit((unsigned long *) lc->sync_bits, + lc->region_count, + lc->sync_search); + lc->sync_search = *region + 1; + + if (*region == lc->region_count) + return 0; + + } while (log_test_bit(lc->recovering_bits, *region)); + + log_set_bit(lc, lc->recovering_bits, *region); + return 1; +} + +static void core_complete_resync_work(struct dirty_log *log, region_t region, + int success) +{ + struct log_c *lc = (struct log_c *) log->context; + + log_clear_bit(lc, lc->recovering_bits, region); + if (success) { + log_set_bit(lc, lc->sync_bits, region); + lc->sync_count++; + } +} + +static region_t core_get_sync_count(struct dirty_log *log) +{ + struct log_c *lc = (struct log_c *) log->context; + + return lc->sync_count; +} + +static struct dirty_log_type _core_type = { + .name = "core", + .module = THIS_MODULE, + .ctr = core_ctr, + .dtr = core_dtr, + .get_region_size = core_get_region_size, + .is_clean = core_is_clean, + .in_sync = core_in_sync, + .flush = core_flush, + .mark_region = core_mark_region, + .clear_region = core_clear_region, + .get_resync_work = core_get_resync_work, + .complete_resync_work = core_complete_resync_work, + .get_sync_count = core_get_sync_count +}; + +static struct dirty_log_type _disk_type = { + .name = "disk", + .module = THIS_MODULE, + .ctr = disk_ctr, + .dtr = disk_dtr, + .suspend = disk_flush, + .resume = disk_resume, + .get_region_size = core_get_region_size, + .is_clean = core_is_clean, + .in_sync = core_in_sync, + .flush = disk_flush, + .mark_region = core_mark_region, + .clear_region = core_clear_region, + .get_resync_work = core_get_resync_work, + .complete_resync_work = core_complete_resync_work, + .get_sync_count = core_get_sync_count +}; + +int __init dm_dirty_log_init(void) +{ + int r; + + r = dm_register_dirty_log_type(&_core_type); + if (r) + DMWARN("couldn't register core log"); + + r = dm_register_dirty_log_type(&_disk_type); + if (r) { + DMWARN("couldn't register disk type"); + dm_unregister_dirty_log_type(&_core_type); + } + + return r; +} + +void dm_dirty_log_exit(void) +{ + dm_unregister_dirty_log_type(&_disk_type); + dm_unregister_dirty_log_type(&_core_type); +} + +EXPORT_SYMBOL(dm_register_dirty_log_type); +EXPORT_SYMBOL(dm_unregister_dirty_log_type); +EXPORT_SYMBOL(dm_create_dirty_log); +EXPORT_SYMBOL(dm_destroy_dirty_log); diff --git a/drivers/md/dm-log.h b/drivers/md/dm-log.h new file mode 100644 index 000000000..ced4ebacd --- /dev/null +++ b/drivers/md/dm-log.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2003 Sistina Software + * + * This file is released under the LGPL. + */ + +#ifndef DM_DIRTY_LOG +#define DM_DIRTY_LOG + +#include "dm.h" + +typedef sector_t region_t; + +struct dirty_log_type; + +struct dirty_log { + struct dirty_log_type *type; + void *context; +}; + +struct dirty_log_type { + struct list_head list; + const char *name; + struct module *module; + unsigned int use_count; + + int (*ctr)(struct dirty_log *log, struct dm_target *ti, + unsigned int argc, char **argv); + void (*dtr)(struct dirty_log *log); + + /* + * There are times when we don't want the log to touch + * the disk. + */ + int (*suspend)(struct dirty_log *log); + int (*resume)(struct dirty_log *log); + + /* + * Retrieves the smallest size of region that the log can + * deal with. + */ + sector_t (*get_region_size)(struct dirty_log *log); + + /* + * A predicate to say whether a region is clean or not. + * May block. + */ + int (*is_clean)(struct dirty_log *log, region_t region); + + /* + * Returns: 0, 1, -EWOULDBLOCK, < 0 + * + * A predicate function to check the area given by + * [sector, sector + len) is in sync. + * + * If -EWOULDBLOCK is returned the state of the region is + * unknown, typically this will result in a read being + * passed to a daemon to deal with, since a daemon is + * allowed to block. + */ + int (*in_sync)(struct dirty_log *log, region_t region, int can_block); + + /* + * Flush the current log state (eg, to disk). This + * function may block. + */ + int (*flush)(struct dirty_log *log); + + /* + * Mark an area as clean or dirty. These functions may + * block, though for performance reasons blocking should + * be extremely rare (eg, allocating another chunk of + * memory for some reason). + */ + void (*mark_region)(struct dirty_log *log, region_t region); + void (*clear_region)(struct dirty_log *log, region_t region); + + /* + * Returns: <0 (error), 0 (no region), 1 (region) + * + * The mirrord will need perform recovery on regions of + * the mirror that are in the NOSYNC state. This + * function asks the log to tell the caller about the + * next region that this machine should recover. + * + * Do not confuse this function with 'in_sync()', one + * tells you if an area is synchronised, the other + * assigns recovery work. + */ + int (*get_resync_work)(struct dirty_log *log, region_t *region); + + /* + * This notifies the log that the resync of an area has + * been completed. The log should then mark this region + * as CLEAN. + */ + void (*complete_resync_work)(struct dirty_log *log, + region_t region, int success); + + /* + * Returns the number of regions that are in sync. + */ + region_t (*get_sync_count)(struct dirty_log *log); +}; + +int dm_register_dirty_log_type(struct dirty_log_type *type); +int dm_unregister_dirty_log_type(struct dirty_log_type *type); + + +/* + * Make sure you use these two functions, rather than calling + * type->constructor/destructor() directly. + */ +struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti, + unsigned int argc, char **argv); +void dm_destroy_dirty_log(struct dirty_log *log); + +/* + * init/exit functions. + */ +int dm_dirty_log_init(void); +void dm_dirty_log_exit(void); + +#endif diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c new file mode 100644 index 000000000..843e9b83d --- /dev/null +++ b/drivers/md/dm-raid1.c @@ -0,0 +1,1278 @@ +/* + * Copyright (C) 2003 Sistina Software Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" +#include "dm-bio-list.h" +#include "dm-io.h" +#include "dm-log.h" +#include "kcopyd.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct workqueue_struct *_kmirrord_wq; +static struct work_struct _kmirrord_work; + +static inline void wake(void) +{ + queue_work(_kmirrord_wq, &_kmirrord_work); +} + +/*----------------------------------------------------------------- + * Region hash + * + * The mirror splits itself up into discrete regions. Each + * region can be in one of three states: clean, dirty, + * nosync. There is no need to put clean regions in the hash. + * + * In addition to being present in the hash table a region _may_ + * be present on one of three lists. + * + * clean_regions: Regions on this list have no io pending to + * them, they are in sync, we are no longer interested in them, + * they are dull. rh_update_states() will remove them from the + * hash table. + * + * quiesced_regions: These regions have been spun down, ready + * for recovery. rh_recovery_start() will remove regions from + * this list and hand them to kmirrord, which will schedule the + * recovery io with kcopyd. + * + * recovered_regions: Regions that kcopyd has successfully + * recovered. rh_update_states() will now schedule any delayed + * io, up the recovery_count, and remove the region from the + * hash. + * + * There are 2 locks: + * A rw spin lock 'hash_lock' protects just the hash table, + * this is never held in write mode from interrupt context, + * which I believe means that we only have to disable irqs when + * doing a write lock. + * + * An ordinary spin lock 'region_lock' that protects the three + * lists in the region_hash, with the 'state', 'list' and + * 'bhs_delayed' fields of the regions. This is used from irq + * context, so all other uses will have to suspend local irqs. + *---------------------------------------------------------------*/ +struct mirror_set; +struct region_hash { + struct mirror_set *ms; + sector_t region_size; + unsigned region_shift; + + /* holds persistent region state */ + struct dirty_log *log; + + /* hash table */ + rwlock_t hash_lock; + mempool_t *region_pool; + unsigned int mask; + unsigned int nr_buckets; + struct list_head *buckets; + + spinlock_t region_lock; + struct semaphore recovery_count; + struct list_head clean_regions; + struct list_head quiesced_regions; + struct list_head recovered_regions; +}; + +enum { + RH_CLEAN, + RH_DIRTY, + RH_NOSYNC, + RH_RECOVERING +}; + +struct region { + struct region_hash *rh; /* FIXME: can we get rid of this ? */ + region_t key; + int state; + + struct list_head hash_list; + struct list_head list; + + atomic_t pending; + struct bio_list delayed_bios; +}; + +/* + * Conversion fns + */ +static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) +{ + return bio->bi_sector >> rh->region_shift; +} + +static inline sector_t region_to_sector(struct region_hash *rh, region_t region) +{ + return region << rh->region_shift; +} + +/* FIXME move this */ +static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); + +static void *region_alloc(int gfp_mask, void *pool_data) +{ + return kmalloc(sizeof(struct region), gfp_mask); +} + +static void region_free(void *element, void *pool_data) +{ + kfree(element); +} + +#define MIN_REGIONS 64 +#define MAX_RECOVERY 1 +static int rh_init(struct region_hash *rh, struct mirror_set *ms, + struct dirty_log *log, sector_t region_size, + region_t nr_regions) +{ + unsigned int nr_buckets, max_buckets; + size_t i; + + /* + * Calculate a suitable number of buckets for our hash + * table. + */ + max_buckets = nr_regions >> 6; + for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1) + ; + nr_buckets >>= 1; + + rh->ms = ms; + rh->log = log; + rh->region_size = region_size; + rh->region_shift = ffs(region_size) - 1; + rwlock_init(&rh->hash_lock); + rh->mask = nr_buckets - 1; + rh->nr_buckets = nr_buckets; + + rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets)); + if (!rh->buckets) { + DMERR("unable to allocate region hash memory"); + return -ENOMEM; + } + + for (i = 0; i < nr_buckets; i++) + INIT_LIST_HEAD(rh->buckets + i); + + spin_lock_init(&rh->region_lock); + sema_init(&rh->recovery_count, 0); + INIT_LIST_HEAD(&rh->clean_regions); + INIT_LIST_HEAD(&rh->quiesced_regions); + INIT_LIST_HEAD(&rh->recovered_regions); + + rh->region_pool = mempool_create(MIN_REGIONS, region_alloc, + region_free, NULL); + if (!rh->region_pool) { + vfree(rh->buckets); + rh->buckets = NULL; + return -ENOMEM; + } + + return 0; +} + +static void rh_exit(struct region_hash *rh) +{ + unsigned int h; + struct region *reg, *nreg; + + BUG_ON(!list_empty(&rh->quiesced_regions)); + for (h = 0; h < rh->nr_buckets; h++) { + list_for_each_entry_safe(reg, nreg, rh->buckets + h, hash_list) { + BUG_ON(atomic_read(®->pending)); + mempool_free(reg, rh->region_pool); + } + } + + if (rh->log) + dm_destroy_dirty_log(rh->log); + if (rh->region_pool) + mempool_destroy(rh->region_pool); + vfree(rh->buckets); +} + +#define RH_HASH_MULT 2654435387U + +static inline unsigned int rh_hash(struct region_hash *rh, region_t region) +{ + return (unsigned int) ((region * RH_HASH_MULT) >> 12) & rh->mask; +} + +static struct region *__rh_lookup(struct region_hash *rh, region_t region) +{ + struct region *reg; + + list_for_each_entry (reg, rh->buckets + rh_hash(rh, region), hash_list) + if (reg->key == region) + return reg; + + return NULL; +} + +static void __rh_insert(struct region_hash *rh, struct region *reg) +{ + unsigned int h = rh_hash(rh, reg->key); + list_add(®->hash_list, rh->buckets + h); +} + +static struct region *__rh_alloc(struct region_hash *rh, region_t region) +{ + struct region *reg, *nreg; + + read_unlock(&rh->hash_lock); + nreg = mempool_alloc(rh->region_pool, GFP_NOIO); + nreg->state = rh->log->type->in_sync(rh->log, region, 1) ? + RH_CLEAN : RH_NOSYNC; + nreg->rh = rh; + nreg->key = region; + + INIT_LIST_HEAD(&nreg->list); + + atomic_set(&nreg->pending, 0); + bio_list_init(&nreg->delayed_bios); + write_lock_irq(&rh->hash_lock); + + reg = __rh_lookup(rh, region); + if (reg) + /* we lost the race */ + mempool_free(nreg, rh->region_pool); + + else { + __rh_insert(rh, nreg); + if (nreg->state == RH_CLEAN) { + spin_lock_irq(&rh->region_lock); + list_add(&nreg->list, &rh->clean_regions); + spin_unlock_irq(&rh->region_lock); + } + reg = nreg; + } + write_unlock_irq(&rh->hash_lock); + read_lock(&rh->hash_lock); + + return reg; +} + +static inline struct region *__rh_find(struct region_hash *rh, region_t region) +{ + struct region *reg; + + reg = __rh_lookup(rh, region); + if (!reg) + reg = __rh_alloc(rh, region); + + return reg; +} + +static int rh_state(struct region_hash *rh, region_t region, int may_block) +{ + int r; + struct region *reg; + + read_lock(&rh->hash_lock); + reg = __rh_lookup(rh, region); + read_unlock(&rh->hash_lock); + + if (reg) + return reg->state; + + /* + * The region wasn't in the hash, so we fall back to the + * dirty log. + */ + r = rh->log->type->in_sync(rh->log, region, may_block); + + /* + * Any error from the dirty log (eg. -EWOULDBLOCK) gets + * taken as a RH_NOSYNC + */ + return r == 1 ? RH_CLEAN : RH_NOSYNC; +} + +static inline int rh_in_sync(struct region_hash *rh, + region_t region, int may_block) +{ + int state = rh_state(rh, region, may_block); + return state == RH_CLEAN || state == RH_DIRTY; +} + +static void dispatch_bios(struct mirror_set *ms, struct bio_list *bio_list) +{ + struct bio *bio; + + while ((bio = bio_list_pop(bio_list))) { + queue_bio(ms, bio, WRITE); + } +} + +static void rh_update_states(struct region_hash *rh) +{ + struct region *reg, *next; + + LIST_HEAD(clean); + LIST_HEAD(recovered); + + /* + * Quickly grab the lists. + */ + write_lock_irq(&rh->hash_lock); + spin_lock(&rh->region_lock); + if (!list_empty(&rh->clean_regions)) { + list_splice(&rh->clean_regions, &clean); + INIT_LIST_HEAD(&rh->clean_regions); + + list_for_each_entry (reg, &clean, list) { + rh->log->type->clear_region(rh->log, reg->key); + list_del(®->hash_list); + } + } + + if (!list_empty(&rh->recovered_regions)) { + list_splice(&rh->recovered_regions, &recovered); + INIT_LIST_HEAD(&rh->recovered_regions); + + list_for_each_entry (reg, &recovered, list) + list_del(®->hash_list); + } + spin_unlock(&rh->region_lock); + write_unlock_irq(&rh->hash_lock); + + /* + * All the regions on the recovered and clean lists have + * now been pulled out of the system, so no need to do + * any more locking. + */ + list_for_each_entry_safe (reg, next, &recovered, list) { + rh->log->type->clear_region(rh->log, reg->key); + rh->log->type->complete_resync_work(rh->log, reg->key, 1); + dispatch_bios(rh->ms, ®->delayed_bios); + up(&rh->recovery_count); + mempool_free(reg, rh->region_pool); + } + + if (!list_empty(&recovered)) + rh->log->type->flush(rh->log); + + list_for_each_entry_safe (reg, next, &clean, list) + mempool_free(reg, rh->region_pool); +} + +static void rh_inc(struct region_hash *rh, region_t region) +{ + struct region *reg; + + read_lock(&rh->hash_lock); + reg = __rh_find(rh, region); + if (reg->state == RH_CLEAN) { + rh->log->type->mark_region(rh->log, reg->key); + + spin_lock_irq(&rh->region_lock); + reg->state = RH_DIRTY; + list_del_init(®->list); /* take off the clean list */ + spin_unlock_irq(&rh->region_lock); + } + + atomic_inc(®->pending); + read_unlock(&rh->hash_lock); +} + +static void rh_inc_pending(struct region_hash *rh, struct bio_list *bios) +{ + struct bio *bio; + + for (bio = bios->head; bio; bio = bio->bi_next) + rh_inc(rh, bio_to_region(rh, bio)); +} + +static void rh_dec(struct region_hash *rh, region_t region) +{ + unsigned long flags; + struct region *reg; + int should_wake = 0; + + read_lock(&rh->hash_lock); + reg = __rh_lookup(rh, region); + read_unlock(&rh->hash_lock); + + if (atomic_dec_and_test(®->pending)) { + spin_lock_irqsave(&rh->region_lock, flags); + if (reg->state == RH_RECOVERING) { + list_add_tail(®->list, &rh->quiesced_regions); + } else { + reg->state = RH_CLEAN; + list_add(®->list, &rh->clean_regions); + } + spin_unlock_irqrestore(&rh->region_lock, flags); + should_wake = 1; + } + + if (should_wake) + wake(); +} + +/* + * Starts quiescing a region in preparation for recovery. + */ +static int __rh_recovery_prepare(struct region_hash *rh) +{ + int r; + struct region *reg; + region_t region; + + /* + * Ask the dirty log what's next. + */ + r = rh->log->type->get_resync_work(rh->log, ®ion); + if (r <= 0) + return r; + + /* + * Get this region, and start it quiescing by setting the + * recovering flag. + */ + read_lock(&rh->hash_lock); + reg = __rh_find(rh, region); + read_unlock(&rh->hash_lock); + + spin_lock_irq(&rh->region_lock); + reg->state = RH_RECOVERING; + + /* Already quiesced ? */ + if (atomic_read(®->pending)) + list_del_init(®->list); + + else { + list_del_init(®->list); + list_add(®->list, &rh->quiesced_regions); + } + spin_unlock_irq(&rh->region_lock); + + return 1; +} + +static void rh_recovery_prepare(struct region_hash *rh) +{ + while (!down_trylock(&rh->recovery_count)) + if (__rh_recovery_prepare(rh) <= 0) { + up(&rh->recovery_count); + break; + } +} + +/* + * Returns any quiesced regions. + */ +static struct region *rh_recovery_start(struct region_hash *rh) +{ + struct region *reg = NULL; + + spin_lock_irq(&rh->region_lock); + if (!list_empty(&rh->quiesced_regions)) { + reg = list_entry(rh->quiesced_regions.next, + struct region, list); + list_del_init(®->list); /* remove from the quiesced list */ + } + spin_unlock_irq(&rh->region_lock); + + return reg; +} + +/* FIXME: success ignored for now */ +static void rh_recovery_end(struct region *reg, int success) +{ + struct region_hash *rh = reg->rh; + + spin_lock_irq(&rh->region_lock); + list_add(®->list, ®->rh->recovered_regions); + spin_unlock_irq(&rh->region_lock); + + wake(); +} + +static void rh_flush(struct region_hash *rh) +{ + rh->log->type->flush(rh->log); +} + +static void rh_delay(struct region_hash *rh, struct bio *bio) +{ + struct region *reg; + + read_lock(&rh->hash_lock); + reg = __rh_find(rh, bio_to_region(rh, bio)); + bio_list_add(®->delayed_bios, bio); + read_unlock(&rh->hash_lock); +} + +static void rh_stop_recovery(struct region_hash *rh) +{ + int i; + + /* wait for any recovering regions */ + for (i = 0; i < MAX_RECOVERY; i++) + down(&rh->recovery_count); +} + +static void rh_start_recovery(struct region_hash *rh) +{ + int i; + + for (i = 0; i < MAX_RECOVERY; i++) + up(&rh->recovery_count); + + wake(); +} + +/*----------------------------------------------------------------- + * Mirror set structures. + *---------------------------------------------------------------*/ +struct mirror { + atomic_t error_count; + struct dm_dev *dev; + sector_t offset; +}; + +struct mirror_set { + struct dm_target *ti; + struct list_head list; + struct region_hash rh; + struct kcopyd_client *kcopyd_client; + + spinlock_t lock; /* protects the next two lists */ + struct bio_list reads; + struct bio_list writes; + + /* recovery */ + region_t nr_regions; + int in_sync; + + unsigned int nr_mirrors; + struct mirror mirror[0]; +}; + +/* + * Every mirror should look like this one. + */ +#define DEFAULT_MIRROR 0 + +/* + * This is yucky. We squirrel the mirror_set struct away inside + * bi_next for write buffers. This is safe since the bh + * doesn't get submitted to the lower levels of block layer. + */ +static struct mirror_set *bio_get_ms(struct bio *bio) +{ + return (struct mirror_set *) bio->bi_next; +} + +static void bio_set_ms(struct bio *bio, struct mirror_set *ms) +{ + bio->bi_next = (struct bio *) ms; +} + +/*----------------------------------------------------------------- + * Recovery. + * + * When a mirror is first activated we may find that some regions + * are in the no-sync state. We have to recover these by + * recopying from the default mirror to all the others. + *---------------------------------------------------------------*/ +static void recovery_complete(int read_err, unsigned int write_err, + void *context) +{ + struct region *reg = (struct region *) context; + + /* FIXME: better error handling */ + rh_recovery_end(reg, read_err || write_err); +} + +static int recover(struct mirror_set *ms, struct region *reg) +{ + int r; + unsigned int i; + struct io_region from, to[ms->nr_mirrors - 1], *dest; + struct mirror *m; + unsigned long flags = 0; + + /* fill in the source */ + m = ms->mirror + DEFAULT_MIRROR; + from.bdev = m->dev->bdev; + from.sector = m->offset + region_to_sector(reg->rh, reg->key); + if (reg->key == (ms->nr_regions - 1)) { + /* + * The final region may be smaller than + * region_size. + */ + from.count = ms->ti->len & (reg->rh->region_size - 1); + if (!from.count) + from.count = reg->rh->region_size; + } else + from.count = reg->rh->region_size; + + /* fill in the destinations */ + for (i = 0, dest = to; i < ms->nr_mirrors; i++) { + if (i == DEFAULT_MIRROR) + continue; + + m = ms->mirror + i; + dest->bdev = m->dev->bdev; + dest->sector = m->offset + region_to_sector(reg->rh, reg->key); + dest->count = from.count; + dest++; + } + + /* hand to kcopyd */ + set_bit(KCOPYD_IGNORE_ERROR, &flags); + r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags, + recovery_complete, reg); + + return r; +} + +static void do_recovery(struct mirror_set *ms) +{ + int r; + struct region *reg; + struct dirty_log *log = ms->rh.log; + + /* + * Start quiescing some regions. + */ + rh_recovery_prepare(&ms->rh); + + /* + * Copy any already quiesced regions. + */ + while ((reg = rh_recovery_start(&ms->rh))) { + r = recover(ms, reg); + if (r) + rh_recovery_end(reg, 0); + } + + /* + * Update the in sync flag. + */ + if (!ms->in_sync && + (log->type->get_sync_count(log) == ms->nr_regions)) { + /* the sync is complete */ + dm_table_event(ms->ti->table); + ms->in_sync = 1; + } +} + +/*----------------------------------------------------------------- + * Reads + *---------------------------------------------------------------*/ +static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector) +{ + /* FIXME: add read balancing */ + return ms->mirror + DEFAULT_MIRROR; +} + +/* + * remap a buffer to a particular mirror. + */ +static void map_bio(struct mirror_set *ms, struct mirror *m, struct bio *bio) +{ + bio->bi_bdev = m->dev->bdev; + bio->bi_sector = m->offset + (bio->bi_sector - ms->ti->begin); +} + +static void do_reads(struct mirror_set *ms, struct bio_list *reads) +{ + region_t region; + struct bio *bio; + struct mirror *m; + + while ((bio = bio_list_pop(reads))) { + region = bio_to_region(&ms->rh, bio); + + /* + * We can only read balance if the region is in sync. + */ + if (rh_in_sync(&ms->rh, region, 0)) + m = choose_mirror(ms, bio->bi_sector); + else + m = ms->mirror + DEFAULT_MIRROR; + + map_bio(ms, m, bio); + generic_make_request(bio); + } +} + +/*----------------------------------------------------------------- + * Writes. + * + * We do different things with the write io depending on the + * state of the region that it's in: + * + * SYNC: increment pending, use kcopyd to write to *all* mirrors + * RECOVERING: delay the io until recovery completes + * NOSYNC: increment pending, just write to the default mirror + *---------------------------------------------------------------*/ +static void write_callback(unsigned long error, void *context) +{ + unsigned int i; + int uptodate = 1; + struct bio *bio = (struct bio *) context; + struct mirror_set *ms; + + ms = bio_get_ms(bio); + bio_set_ms(bio, NULL); + + /* + * NOTE: We don't decrement the pending count here, + * instead it is done by the targets endio function. + * This way we handle both writes to SYNC and NOSYNC + * regions with the same code. + */ + + if (error) { + /* + * only error the io if all mirrors failed. + * FIXME: bogus + */ + uptodate = 0; + for (i = 0; i < ms->nr_mirrors; i++) + if (!test_bit(i, &error)) { + uptodate = 1; + break; + } + } + bio_endio(bio, bio->bi_size, 0); +} + +static void do_write(struct mirror_set *ms, struct bio *bio) +{ + unsigned int i; + struct io_region io[ms->nr_mirrors]; + struct mirror *m; + + for (i = 0; i < ms->nr_mirrors; i++) { + m = ms->mirror + i; + + io[i].bdev = m->dev->bdev; + io[i].sector = m->offset + (bio->bi_sector - ms->ti->begin); + io[i].count = bio->bi_size >> 9; + } + + bio_set_ms(bio, ms); + dm_io_async_bvec(ms->nr_mirrors, io, WRITE, + bio->bi_io_vec + bio->bi_idx, + write_callback, bio); +} + +static void do_writes(struct mirror_set *ms, struct bio_list *writes) +{ + int state; + struct bio *bio; + struct bio_list sync, nosync, recover, *this_list = NULL; + + if (!writes->head) + return; + + /* + * Classify each write. + */ + bio_list_init(&sync); + bio_list_init(&nosync); + bio_list_init(&recover); + + while ((bio = bio_list_pop(writes))) { + state = rh_state(&ms->rh, bio_to_region(&ms->rh, bio), 1); + switch (state) { + case RH_CLEAN: + case RH_DIRTY: + this_list = &sync; + break; + + case RH_NOSYNC: + this_list = &nosync; + break; + + case RH_RECOVERING: + this_list = &recover; + break; + } + + bio_list_add(this_list, bio); + } + + /* + * Increment the pending counts for any regions that will + * be written to (writes to recover regions are going to + * be delayed). + */ + rh_inc_pending(&ms->rh, &sync); + rh_inc_pending(&ms->rh, &nosync); + rh_flush(&ms->rh); + + /* + * Dispatch io. + */ + while ((bio = bio_list_pop(&sync))) + do_write(ms, bio); + + while ((bio = bio_list_pop(&recover))) + rh_delay(&ms->rh, bio); + + while ((bio = bio_list_pop(&nosync))) { + map_bio(ms, ms->mirror + DEFAULT_MIRROR, bio); + generic_make_request(bio); + } +} + +/*----------------------------------------------------------------- + * kmirrord + *---------------------------------------------------------------*/ +static LIST_HEAD(_mirror_sets); +static DECLARE_RWSEM(_mirror_sets_lock); + +static void do_mirror(struct mirror_set *ms) +{ + struct bio_list reads, writes; + + spin_lock(&ms->lock); + reads = ms->reads; + writes = ms->writes; + bio_list_init(&ms->reads); + bio_list_init(&ms->writes); + spin_unlock(&ms->lock); + + rh_update_states(&ms->rh); + do_recovery(ms); + do_reads(ms, &reads); + do_writes(ms, &writes); +} + +static void do_work(void *ignored) +{ + struct mirror_set *ms; + + down_read(&_mirror_sets_lock); + list_for_each_entry (ms, &_mirror_sets, list) + do_mirror(ms); + up_read(&_mirror_sets_lock); +} + +/*----------------------------------------------------------------- + * Target functions + *---------------------------------------------------------------*/ +static struct mirror_set *alloc_context(unsigned int nr_mirrors, + sector_t region_size, + struct dm_target *ti, + struct dirty_log *dl) +{ + size_t len; + struct mirror_set *ms = NULL; + + if (array_too_big(sizeof(*ms), sizeof(ms->mirror[0]), nr_mirrors)) + return NULL; + + len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors); + + ms = kmalloc(len, GFP_KERNEL); + if (!ms) { + ti->error = "dm-mirror: Cannot allocate mirror context"; + return NULL; + } + + memset(ms, 0, len); + spin_lock_init(&ms->lock); + + ms->ti = ti; + ms->nr_mirrors = nr_mirrors; + ms->nr_regions = dm_div_up(ti->len, region_size); + ms->in_sync = 0; + + if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { + ti->error = "dm-mirror: Error creating dirty region hash"; + kfree(ms); + return NULL; + } + + return ms; +} + +static void free_context(struct mirror_set *ms, struct dm_target *ti, + unsigned int m) +{ + while (m--) + dm_put_device(ti, ms->mirror[m].dev); + + rh_exit(&ms->rh); + kfree(ms); +} + +static inline int _check_region_size(struct dm_target *ti, sector_t size) +{ + return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) || + size > ti->len); +} + +static int get_mirror(struct mirror_set *ms, struct dm_target *ti, + unsigned int mirror, char **argv) +{ + sector_t offset; + + if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) { + ti->error = "dm-mirror: Invalid offset"; + return -EINVAL; + } + + if (dm_get_device(ti, argv[0], offset, ti->len, + dm_table_get_mode(ti->table), + &ms->mirror[mirror].dev)) { + ti->error = "dm-mirror: Device lookup failure"; + return -ENXIO; + } + + ms->mirror[mirror].offset = offset; + + return 0; +} + +static int add_mirror_set(struct mirror_set *ms) +{ + down_write(&_mirror_sets_lock); + list_add_tail(&ms->list, &_mirror_sets); + up_write(&_mirror_sets_lock); + wake(); + + return 0; +} + +static void del_mirror_set(struct mirror_set *ms) +{ + down_write(&_mirror_sets_lock); + list_del(&ms->list); + up_write(&_mirror_sets_lock); +} + +/* + * Create dirty log: log_type #log_params + */ +static struct dirty_log *create_dirty_log(struct dm_target *ti, + unsigned int argc, char **argv, + unsigned int *args_used) +{ + unsigned int param_count; + struct dirty_log *dl; + + if (argc < 2) { + ti->error = "dm-mirror: Insufficient mirror log arguments"; + return NULL; + } + + if (sscanf(argv[1], "%u", ¶m_count) != 1) { + ti->error = "dm-mirror: Invalid mirror log argument count"; + return NULL; + } + + *args_used = 2 + param_count; + + if (argc < *args_used) { + ti->error = "dm-mirror: Insufficient mirror log arguments"; + return NULL; + } + + dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); + if (!dl) { + ti->error = "dm-mirror: Error creating mirror dirty log"; + return NULL; + } + + if (!_check_region_size(ti, dl->type->get_region_size(dl))) { + ti->error = "dm-mirror: Invalid region size"; + dm_destroy_dirty_log(dl); + return NULL; + } + + return dl; +} + +/* + * Construct a mirror mapping: + * + * log_type #log_params + * #mirrors [mirror_path offset]{2,} + * + * For now, #log_params = 1, log_type = "core" + * + */ +#define DM_IO_PAGES 64 +static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + int r; + unsigned int nr_mirrors, m, args_used; + struct mirror_set *ms; + struct dirty_log *dl; + + dl = create_dirty_log(ti, argc, argv, &args_used); + if (!dl) + return -EINVAL; + + argv += args_used; + argc -= args_used; + + if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || + nr_mirrors < 2) { + ti->error = "dm-mirror: Invalid number of mirrors"; + dm_destroy_dirty_log(dl); + return -EINVAL; + } + + argv++, argc--; + + if (argc != nr_mirrors * 2) { + ti->error = "dm-mirror: Wrong number of mirror arguments"; + dm_destroy_dirty_log(dl); + return -EINVAL; + } + + ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl); + if (!ms) { + dm_destroy_dirty_log(dl); + return -ENOMEM; + } + + /* Get the mirror parameter sets */ + for (m = 0; m < nr_mirrors; m++) { + r = get_mirror(ms, ti, m, argv); + if (r) { + free_context(ms, ti, m); + return r; + } + argv += 2; + argc -= 2; + } + + ti->private = ms; + + r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); + if (r) { + free_context(ms, ti, ms->nr_mirrors); + return r; + } + + add_mirror_set(ms); + return 0; +} + +static void mirror_dtr(struct dm_target *ti) +{ + struct mirror_set *ms = (struct mirror_set *) ti->private; + + del_mirror_set(ms); + kcopyd_client_destroy(ms->kcopyd_client); + free_context(ms, ti, ms->nr_mirrors); +} + +static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw) +{ + int should_wake = 0; + struct bio_list *bl; + + bl = (rw == WRITE) ? &ms->writes : &ms->reads; + spin_lock(&ms->lock); + should_wake = !(bl->head); + bio_list_add(bl, bio); + spin_unlock(&ms->lock); + + if (should_wake) + wake(); +} + +/* + * Mirror mapping function + */ +static int mirror_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + int r, rw = bio_rw(bio); + struct mirror *m; + struct mirror_set *ms = ti->private; + + map_context->ll = bio->bi_sector >> ms->rh.region_shift; + + if (rw == WRITE) { + queue_bio(ms, bio, rw); + return 0; + } + + r = ms->rh.log->type->in_sync(ms->rh.log, + bio_to_region(&ms->rh, bio), 0); + if (r < 0 && r != -EWOULDBLOCK) + return r; + + if (r == -EWOULDBLOCK) /* FIXME: ugly */ + r = 0; + + /* + * We don't want to fast track a recovery just for a read + * ahead. So we just let it silently fail. + * FIXME: get rid of this. + */ + if (!r && rw == READA) + return -EIO; + + if (!r) { + /* Pass this io over to the daemon */ + queue_bio(ms, bio, rw); + return 0; + } + + m = choose_mirror(ms, bio->bi_sector); + if (!m) + return -EIO; + + map_bio(ms, m, bio); + return 1; +} + +static int mirror_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + int rw = bio_rw(bio); + struct mirror_set *ms = (struct mirror_set *) ti->private; + region_t region = map_context->ll; + + /* + * We need to dec pending if this was a write. + */ + if (rw == WRITE) + rh_dec(&ms->rh, region); + + return 0; +} + +static void mirror_suspend(struct dm_target *ti) +{ + struct mirror_set *ms = (struct mirror_set *) ti->private; + struct dirty_log *log = ms->rh.log; + rh_stop_recovery(&ms->rh); + if (log->type->suspend && log->type->suspend(log)) + /* FIXME: need better error handling */ + DMWARN("log suspend failed"); +} + +static void mirror_resume(struct dm_target *ti) +{ + struct mirror_set *ms = (struct mirror_set *) ti->private; + struct dirty_log *log = ms->rh.log; + if (log->type->resume && log->type->resume(log)) + /* FIXME: need better error handling */ + DMWARN("log resume failed"); + rh_start_recovery(&ms->rh); +} + +static int mirror_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) +{ + char buffer[32]; + unsigned int m, sz = 0; + struct mirror_set *ms = (struct mirror_set *) ti->private; + +#define EMIT(x...) sz += ((sz >= maxlen) ? \ + 0 : scnprintf(result + sz, maxlen - sz, x)) + + switch (type) { + case STATUSTYPE_INFO: + EMIT("%d ", ms->nr_mirrors); + + for (m = 0; m < ms->nr_mirrors; m++) { + format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); + EMIT("%s ", buffer); + } + + EMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, + ms->rh.log->type->get_sync_count(ms->rh.log), + ms->nr_regions); + break; + + case STATUSTYPE_TABLE: + EMIT("%s 1 " SECTOR_FORMAT " %d ", + ms->rh.log->type->name, ms->rh.region_size, + ms->nr_mirrors); + + for (m = 0; m < ms->nr_mirrors; m++) { + format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); + EMIT("%s " SECTOR_FORMAT " ", + buffer, ms->mirror[m].offset); + } + } + + return 0; +} + +static struct target_type mirror_target = { + .name = "mirror", + .version = {1, 0, 1}, + .module = THIS_MODULE, + .ctr = mirror_ctr, + .dtr = mirror_dtr, + .map = mirror_map, + .end_io = mirror_end_io, + .suspend = mirror_suspend, + .resume = mirror_resume, + .status = mirror_status, +}; + +static int __init dm_mirror_init(void) +{ + int r; + + r = dm_dirty_log_init(); + if (r) + return r; + + _kmirrord_wq = create_workqueue("kmirrord"); + if (!_kmirrord_wq) { + DMERR("couldn't start kmirrord"); + dm_dirty_log_exit(); + return r; + } + INIT_WORK(&_kmirrord_work, do_work, NULL); + + r = dm_register_target(&mirror_target); + if (r < 0) { + DMERR("%s: Failed to register mirror target", + mirror_target.name); + dm_dirty_log_exit(); + destroy_workqueue(_kmirrord_wq); + } + + return r; +} + +static void __exit dm_mirror_exit(void) +{ + int r; + + r = dm_unregister_target(&mirror_target); + if (r < 0) + DMERR("%s: unregister failed %d", mirror_target.name, r); + + destroy_workqueue(_kmirrord_wq); + dm_dirty_log_exit(); +} + +/* Module hooks */ +module_init(dm_mirror_init); +module_exit(dm_mirror_exit); + +MODULE_DESCRIPTION(DM_NAME " mirror target"); +MODULE_AUTHOR("Joe Thornber"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c new file mode 100644 index 000000000..36691ab1e --- /dev/null +++ b/drivers/md/dm-snap.c @@ -0,0 +1,1213 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dm-snap.h" +#include "dm-bio-list.h" +#include "kcopyd.h" + +/* + * The percentage increment we will wake up users at + */ +#define WAKE_UP_PERCENT 5 + +/* + * kcopyd priority of snapshot operations + */ +#define SNAPSHOT_COPY_PRIORITY 2 + +/* + * Each snapshot reserves this many pages for io + */ +#define SNAPSHOT_PAGES 256 + +struct pending_exception { + struct exception e; + + /* + * Origin buffers waiting for this to complete are held + * in a bio list + */ + struct bio_list origin_bios; + struct bio_list snapshot_bios; + + /* + * Other pending_exceptions that are processing this + * chunk. When this list is empty, we know we can + * complete the origins. + */ + struct list_head siblings; + + /* Pointer back to snapshot context */ + struct dm_snapshot *snap; + + /* + * 1 indicates the exception has already been sent to + * kcopyd. + */ + int started; +}; + +/* + * Hash table mapping origin volumes to lists of snapshots and + * a lock to protect it + */ +static kmem_cache_t *exception_cache; +static kmem_cache_t *pending_cache; +static mempool_t *pending_pool; + +/* + * One of these per registered origin, held in the snapshot_origins hash + */ +struct origin { + /* The origin device */ + struct block_device *bdev; + + struct list_head hash_list; + + /* List of snapshots for this origin */ + struct list_head snapshots; +}; + +/* + * Size of the hash table for origin volumes. If we make this + * the size of the minors list then it should be nearly perfect + */ +#define ORIGIN_HASH_SIZE 256 +#define ORIGIN_MASK 0xFF +static struct list_head *_origins; +static struct rw_semaphore _origins_lock; + +static int init_origin_hash(void) +{ + int i; + + _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), + GFP_KERNEL); + if (!_origins) { + DMERR("Device mapper: Snapshot: unable to allocate memory"); + return -ENOMEM; + } + + for (i = 0; i < ORIGIN_HASH_SIZE; i++) + INIT_LIST_HEAD(_origins + i); + init_rwsem(&_origins_lock); + + return 0; +} + +static void exit_origin_hash(void) +{ + kfree(_origins); +} + +static inline unsigned int origin_hash(struct block_device *bdev) +{ + return bdev->bd_dev & ORIGIN_MASK; +} + +static struct origin *__lookup_origin(struct block_device *origin) +{ + struct list_head *ol; + struct origin *o; + + ol = &_origins[origin_hash(origin)]; + list_for_each_entry (o, ol, hash_list) + if (bdev_equal(o->bdev, origin)) + return o; + + return NULL; +} + +static void __insert_origin(struct origin *o) +{ + struct list_head *sl = &_origins[origin_hash(o->bdev)]; + list_add_tail(&o->hash_list, sl); +} + +/* + * Make a note of the snapshot and its origin so we can look it + * up when the origin has a write on it. + */ +static int register_snapshot(struct dm_snapshot *snap) +{ + struct origin *o; + struct block_device *bdev = snap->origin->bdev; + + down_write(&_origins_lock); + o = __lookup_origin(bdev); + + if (!o) { + /* New origin */ + o = kmalloc(sizeof(*o), GFP_KERNEL); + if (!o) { + up_write(&_origins_lock); + return -ENOMEM; + } + + /* Initialise the struct */ + INIT_LIST_HEAD(&o->snapshots); + o->bdev = bdev; + + __insert_origin(o); + } + + list_add_tail(&snap->list, &o->snapshots); + + up_write(&_origins_lock); + return 0; +} + +static void unregister_snapshot(struct dm_snapshot *s) +{ + struct origin *o; + + down_write(&_origins_lock); + o = __lookup_origin(s->origin->bdev); + + list_del(&s->list); + if (list_empty(&o->snapshots)) { + list_del(&o->hash_list); + kfree(o); + } + + up_write(&_origins_lock); +} + +/* + * Implementation of the exception hash tables. + */ +static int init_exception_table(struct exception_table *et, uint32_t size) +{ + unsigned int i; + + et->hash_mask = size - 1; + et->table = dm_vcalloc(size, sizeof(struct list_head)); + if (!et->table) + return -ENOMEM; + + for (i = 0; i < size; i++) + INIT_LIST_HEAD(et->table + i); + + return 0; +} + +static void exit_exception_table(struct exception_table *et, kmem_cache_t *mem) +{ + struct list_head *slot; + struct exception *ex, *next; + int i, size; + + size = et->hash_mask + 1; + for (i = 0; i < size; i++) { + slot = et->table + i; + + list_for_each_entry_safe (ex, next, slot, hash_list) + kmem_cache_free(mem, ex); + } + + vfree(et->table); +} + +static inline uint32_t exception_hash(struct exception_table *et, chunk_t chunk) +{ + return chunk & et->hash_mask; +} + +static void insert_exception(struct exception_table *eh, struct exception *e) +{ + struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)]; + list_add(&e->hash_list, l); +} + +static inline void remove_exception(struct exception *e) +{ + list_del(&e->hash_list); +} + +/* + * Return the exception data for a sector, or NULL if not + * remapped. + */ +static struct exception *lookup_exception(struct exception_table *et, + chunk_t chunk) +{ + struct list_head *slot; + struct exception *e; + + slot = &et->table[exception_hash(et, chunk)]; + list_for_each_entry (e, slot, hash_list) + if (e->old_chunk == chunk) + return e; + + return NULL; +} + +static inline struct exception *alloc_exception(void) +{ + struct exception *e; + + e = kmem_cache_alloc(exception_cache, GFP_NOIO); + if (!e) + e = kmem_cache_alloc(exception_cache, GFP_ATOMIC); + + return e; +} + +static inline void free_exception(struct exception *e) +{ + kmem_cache_free(exception_cache, e); +} + +static inline struct pending_exception *alloc_pending_exception(void) +{ + return mempool_alloc(pending_pool, GFP_NOIO); +} + +static inline void free_pending_exception(struct pending_exception *pe) +{ + mempool_free(pe, pending_pool); +} + +int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new) +{ + struct exception *e; + + e = alloc_exception(); + if (!e) + return -ENOMEM; + + e->old_chunk = old; + e->new_chunk = new; + insert_exception(&s->complete, e); + return 0; +} + +/* + * Hard coded magic. + */ +static int calc_max_buckets(void) +{ + /* use a fixed size of 2MB */ + unsigned long mem = 2 * 1024 * 1024; + mem /= sizeof(struct list_head); + + return mem; +} + +/* + * Rounds a number down to a power of 2. + */ +static inline uint32_t round_down(uint32_t n) +{ + while (n & (n - 1)) + n &= (n - 1); + return n; +} + +/* + * Allocate room for a suitable hash table. + */ +static int init_hash_tables(struct dm_snapshot *s) +{ + sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets; + + /* + * Calculate based on the size of the original volume or + * the COW volume... + */ + cow_dev_size = get_dev_size(s->cow->bdev); + origin_dev_size = get_dev_size(s->origin->bdev); + max_buckets = calc_max_buckets(); + + hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift; + hash_size = min(hash_size, max_buckets); + + /* Round it down to a power of 2 */ + hash_size = round_down(hash_size); + if (init_exception_table(&s->complete, hash_size)) + return -ENOMEM; + + /* + * Allocate hash table for in-flight exceptions + * Make this smaller than the real hash table + */ + hash_size >>= 3; + if (hash_size < 64) + hash_size = 64; + + if (init_exception_table(&s->pending, hash_size)) { + exit_exception_table(&s->complete, exception_cache); + return -ENOMEM; + } + + return 0; +} + +/* + * Round a number up to the nearest 'size' boundary. size must + * be a power of 2. + */ +static inline ulong round_up(ulong n, ulong size) +{ + size--; + return (n + size) & ~size; +} + +/* + * Construct a snapshot mapping:

+ */ +static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct dm_snapshot *s; + unsigned long chunk_size; + int r = -EINVAL; + char persistent; + char *origin_path; + char *cow_path; + char *value; + int blocksize; + + if (argc < 4) { + ti->error = "dm-snapshot: requires exactly 4 arguments"; + r = -EINVAL; + goto bad1; + } + + origin_path = argv[0]; + cow_path = argv[1]; + persistent = toupper(*argv[2]); + + if (persistent != 'P' && persistent != 'N') { + ti->error = "Persistent flag is not P or N"; + r = -EINVAL; + goto bad1; + } + + chunk_size = simple_strtoul(argv[3], &value, 10); + if (chunk_size == 0 || value == NULL) { + ti->error = "Invalid chunk size"; + r = -EINVAL; + goto bad1; + } + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) { + ti->error = "Cannot allocate snapshot context private " + "structure"; + r = -ENOMEM; + goto bad1; + } + + r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); + if (r) { + ti->error = "Cannot get origin device"; + goto bad2; + } + + r = dm_get_device(ti, cow_path, 0, 0, + FMODE_READ | FMODE_WRITE, &s->cow); + if (r) { + dm_put_device(ti, s->origin); + ti->error = "Cannot get COW device"; + goto bad2; + } + + /* + * Chunk size must be multiple of page size. Silently + * round up if it's not. + */ + chunk_size = round_up(chunk_size, PAGE_SIZE >> 9); + + /* Validate the chunk size against the device block size */ + blocksize = s->cow->bdev->bd_disk->queue->hardsect_size; + if (chunk_size % (blocksize >> 9)) { + ti->error = "Chunk size is not a multiple of device blocksize"; + r = -EINVAL; + goto bad3; + } + + /* Check chunk_size is a power of 2 */ + if (chunk_size & (chunk_size - 1)) { + ti->error = "Chunk size is not a power of 2"; + r = -EINVAL; + goto bad3; + } + + s->chunk_size = chunk_size; + s->chunk_mask = chunk_size - 1; + s->type = persistent; + s->chunk_shift = ffs(chunk_size) - 1; + + s->valid = 1; + s->have_metadata = 0; + s->last_percent = 0; + init_rwsem(&s->lock); + s->table = ti->table; + + /* Allocate hash table for COW data */ + if (init_hash_tables(s)) { + ti->error = "Unable to allocate hash table space"; + r = -ENOMEM; + goto bad3; + } + + /* + * Check the persistent flag - done here because we need the iobuf + * to check the LV header + */ + s->store.snap = s; + + if (persistent == 'P') + r = dm_create_persistent(&s->store, chunk_size); + else + r = dm_create_transient(&s->store, s, blocksize); + + if (r) { + ti->error = "Couldn't create exception store"; + r = -EINVAL; + goto bad4; + } + + r = kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); + if (r) { + ti->error = "Could not create kcopyd client"; + goto bad5; + } + + /* Add snapshot to the list of snapshots for this origin */ + if (register_snapshot(s)) { + r = -EINVAL; + ti->error = "Cannot register snapshot origin"; + goto bad6; + } + + ti->private = s; + ti->split_io = chunk_size; + + return 0; + + bad6: + kcopyd_client_destroy(s->kcopyd_client); + + bad5: + s->store.destroy(&s->store); + + bad4: + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + + bad3: + dm_put_device(ti, s->cow); + dm_put_device(ti, s->origin); + + bad2: + kfree(s); + + bad1: + return r; +} + +static void snapshot_dtr(struct dm_target *ti) +{ + struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + + unregister_snapshot(s); + + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + + /* Deallocate memory used */ + s->store.destroy(&s->store); + + dm_put_device(ti, s->origin); + dm_put_device(ti, s->cow); + kcopyd_client_destroy(s->kcopyd_client); + kfree(s); +} + +/* + * Flush a list of buffers. + */ +static void flush_bios(struct bio *bio) +{ + struct bio *n; + + while (bio) { + n = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = n; + } +} + +/* + * Error a list of buffers. + */ +static void error_bios(struct bio *bio) +{ + struct bio *n; + + while (bio) { + n = bio->bi_next; + bio->bi_next = NULL; + bio_io_error(bio, bio->bi_size); + bio = n; + } +} + +static struct bio *__flush_bios(struct pending_exception *pe) +{ + struct pending_exception *sibling; + + if (list_empty(&pe->siblings)) + return bio_list_get(&pe->origin_bios); + + sibling = list_entry(pe->siblings.next, + struct pending_exception, siblings); + + list_del(&pe->siblings); + + /* This is fine as long as kcopyd is single-threaded. If kcopyd + * becomes multi-threaded, we'll need some locking here. + */ + bio_list_merge(&sibling->origin_bios, &pe->origin_bios); + + return NULL; +} + +static void pending_complete(struct pending_exception *pe, int success) +{ + struct exception *e; + struct dm_snapshot *s = pe->snap; + struct bio *flush = NULL; + + if (success) { + e = alloc_exception(); + if (!e) { + DMWARN("Unable to allocate exception."); + down_write(&s->lock); + s->store.drop_snapshot(&s->store); + s->valid = 0; + flush = __flush_bios(pe); + up_write(&s->lock); + + error_bios(bio_list_get(&pe->snapshot_bios)); + goto out; + } + *e = pe->e; + + /* + * Add a proper exception, and remove the + * in-flight exception from the list. + */ + down_write(&s->lock); + insert_exception(&s->complete, e); + remove_exception(&pe->e); + flush = __flush_bios(pe); + + /* Submit any pending write bios */ + up_write(&s->lock); + + flush_bios(bio_list_get(&pe->snapshot_bios)); + } else { + /* Read/write error - snapshot is unusable */ + down_write(&s->lock); + if (s->valid) + DMERR("Error reading/writing snapshot"); + s->store.drop_snapshot(&s->store); + s->valid = 0; + remove_exception(&pe->e); + flush = __flush_bios(pe); + up_write(&s->lock); + + error_bios(bio_list_get(&pe->snapshot_bios)); + + dm_table_event(s->table); + } + + out: + free_pending_exception(pe); + + if (flush) + flush_bios(flush); +} + +static void commit_callback(void *context, int success) +{ + struct pending_exception *pe = (struct pending_exception *) context; + pending_complete(pe, success); +} + +/* + * Called when the copy I/O has finished. kcopyd actually runs + * this code so don't block. + */ +static void copy_callback(int read_err, unsigned int write_err, void *context) +{ + struct pending_exception *pe = (struct pending_exception *) context; + struct dm_snapshot *s = pe->snap; + + if (read_err || write_err) + pending_complete(pe, 0); + + else + /* Update the metadata if we are persistent */ + s->store.commit_exception(&s->store, &pe->e, commit_callback, + pe); +} + +/* + * Dispatches the copy operation to kcopyd. + */ +static inline void start_copy(struct pending_exception *pe) +{ + struct dm_snapshot *s = pe->snap; + struct io_region src, dest; + struct block_device *bdev = s->origin->bdev; + sector_t dev_size; + + dev_size = get_dev_size(bdev); + + src.bdev = bdev; + src.sector = chunk_to_sector(s, pe->e.old_chunk); + src.count = min(s->chunk_size, dev_size - src.sector); + + dest.bdev = s->cow->bdev; + dest.sector = chunk_to_sector(s, pe->e.new_chunk); + dest.count = src.count; + + /* Hand over to kcopyd */ + kcopyd_copy(s->kcopyd_client, + &src, 1, &dest, 0, copy_callback, pe); +} + +/* + * Looks to see if this snapshot already has a pending exception + * for this chunk, otherwise it allocates a new one and inserts + * it into the pending table. + * + * NOTE: a write lock must be held on snap->lock before calling + * this. + */ +static struct pending_exception * +__find_pending_exception(struct dm_snapshot *s, struct bio *bio) +{ + struct exception *e; + struct pending_exception *pe; + chunk_t chunk = sector_to_chunk(s, bio->bi_sector); + + /* + * Is there a pending exception for this already ? + */ + e = lookup_exception(&s->pending, chunk); + if (e) { + /* cast the exception to a pending exception */ + pe = container_of(e, struct pending_exception, e); + + } else { + /* + * Create a new pending exception, we don't want + * to hold the lock while we do this. + */ + up_write(&s->lock); + pe = alloc_pending_exception(); + down_write(&s->lock); + + e = lookup_exception(&s->pending, chunk); + if (e) { + free_pending_exception(pe); + pe = container_of(e, struct pending_exception, e); + } else { + pe->e.old_chunk = chunk; + bio_list_init(&pe->origin_bios); + bio_list_init(&pe->snapshot_bios); + INIT_LIST_HEAD(&pe->siblings); + pe->snap = s; + pe->started = 0; + + if (s->store.prepare_exception(&s->store, &pe->e)) { + free_pending_exception(pe); + s->valid = 0; + return NULL; + } + + insert_exception(&s->pending, &pe->e); + } + } + + return pe; +} + +static inline void remap_exception(struct dm_snapshot *s, struct exception *e, + struct bio *bio) +{ + bio->bi_bdev = s->cow->bdev; + bio->bi_sector = chunk_to_sector(s, e->new_chunk) + + (bio->bi_sector & s->chunk_mask); +} + +static int snapshot_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + struct exception *e; + struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + int r = 1; + chunk_t chunk; + struct pending_exception *pe; + + chunk = sector_to_chunk(s, bio->bi_sector); + + /* Full snapshots are not usable */ + if (!s->valid) + return -1; + + /* + * Write to snapshot - higher level takes care of RW/RO + * flags so we should only get this if we are + * writeable. + */ + if (bio_rw(bio) == WRITE) { + + /* FIXME: should only take write lock if we need + * to copy an exception */ + down_write(&s->lock); + + /* If the block is already remapped - use that, else remap it */ + e = lookup_exception(&s->complete, chunk); + if (e) { + remap_exception(s, e, bio); + up_write(&s->lock); + + } else { + pe = __find_pending_exception(s, bio); + + if (!pe) { + if (s->store.drop_snapshot) + s->store.drop_snapshot(&s->store); + s->valid = 0; + r = -EIO; + up_write(&s->lock); + } else { + remap_exception(s, &pe->e, bio); + bio_list_add(&pe->snapshot_bios, bio); + + if (!pe->started) { + /* this is protected by snap->lock */ + pe->started = 1; + up_write(&s->lock); + start_copy(pe); + } else + up_write(&s->lock); + r = 0; + } + } + + } else { + /* + * FIXME: this read path scares me because we + * always use the origin when we have a pending + * exception. However I can't think of a + * situation where this is wrong - ejt. + */ + + /* Do reads */ + down_read(&s->lock); + + /* See if it it has been remapped */ + e = lookup_exception(&s->complete, chunk); + if (e) + remap_exception(s, e, bio); + else + bio->bi_bdev = s->origin->bdev; + + up_read(&s->lock); + } + + return r; +} + +static void snapshot_resume(struct dm_target *ti) +{ + struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + + if (s->have_metadata) + return; + + if (s->store.read_metadata(&s->store)) { + down_write(&s->lock); + s->valid = 0; + up_write(&s->lock); + } + + s->have_metadata = 1; +} + +static int snapshot_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) +{ + struct dm_snapshot *snap = (struct dm_snapshot *) ti->private; + char cow[32]; + char org[32]; + + switch (type) { + case STATUSTYPE_INFO: + if (!snap->valid) + snprintf(result, maxlen, "Invalid"); + else { + if (snap->store.fraction_full) { + sector_t numerator, denominator; + snap->store.fraction_full(&snap->store, + &numerator, + &denominator); + snprintf(result, maxlen, + SECTOR_FORMAT "/" SECTOR_FORMAT, + numerator, denominator); + } + else + snprintf(result, maxlen, "Unknown"); + } + break; + + case STATUSTYPE_TABLE: + /* + * kdevname returns a static pointer so we need + * to make private copies if the output is to + * make sense. + */ + format_dev_t(cow, snap->cow->bdev->bd_dev); + format_dev_t(org, snap->origin->bdev->bd_dev); + snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT, org, cow, + snap->type, snap->chunk_size); + break; + } + + return 0; +} + +/*----------------------------------------------------------------- + * Origin methods + *---------------------------------------------------------------*/ +static void list_merge(struct list_head *l1, struct list_head *l2) +{ + struct list_head *l1_n, *l2_p; + + l1_n = l1->next; + l2_p = l2->prev; + + l1->next = l2; + l2->prev = l1; + + l2_p->next = l1_n; + l1_n->prev = l2_p; +} + +static int __origin_write(struct list_head *snapshots, struct bio *bio) +{ + int r = 1, first = 1; + struct dm_snapshot *snap; + struct exception *e; + struct pending_exception *pe, *last = NULL; + chunk_t chunk; + + /* Do all the snapshots on this origin */ + list_for_each_entry (snap, snapshots, list) { + + /* Only deal with valid snapshots */ + if (!snap->valid) + continue; + + down_write(&snap->lock); + + /* + * Remember, different snapshots can have + * different chunk sizes. + */ + chunk = sector_to_chunk(snap, bio->bi_sector); + + /* + * Check exception table to see if block + * is already remapped in this snapshot + * and trigger an exception if not. + */ + e = lookup_exception(&snap->complete, chunk); + if (!e) { + pe = __find_pending_exception(snap, bio); + if (!pe) { + snap->store.drop_snapshot(&snap->store); + snap->valid = 0; + + } else { + if (last) + list_merge(&pe->siblings, + &last->siblings); + + last = pe; + r = 0; + } + } + + up_write(&snap->lock); + } + + /* + * Now that we have a complete pe list we can start the copying. + */ + if (last) { + pe = last; + do { + down_write(&pe->snap->lock); + if (first) + bio_list_add(&pe->origin_bios, bio); + if (!pe->started) { + pe->started = 1; + up_write(&pe->snap->lock); + start_copy(pe); + } else + up_write(&pe->snap->lock); + first = 0; + pe = list_entry(pe->siblings.next, + struct pending_exception, siblings); + + } while (pe != last); + } + + return r; +} + +/* + * Called on a write from the origin driver. + */ +static int do_origin(struct dm_dev *origin, struct bio *bio) +{ + struct origin *o; + int r = 1; + + down_read(&_origins_lock); + o = __lookup_origin(origin->bdev); + if (o) + r = __origin_write(&o->snapshots, bio); + up_read(&_origins_lock); + + return r; +} + +/* + * Origin: maps a linear range of a device, with hooks for snapshotting. + */ + +/* + * Construct an origin mapping: + * The context for an origin is merely a 'struct dm_dev *' + * pointing to the real device. + */ +static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + int r; + struct dm_dev *dev; + + if (argc != 1) { + ti->error = "dm-origin: incorrect number of arguments"; + return -EINVAL; + } + + r = dm_get_device(ti, argv[0], 0, ti->len, + dm_table_get_mode(ti->table), &dev); + if (r) { + ti->error = "Cannot get target device"; + return r; + } + + ti->private = dev; + return 0; +} + +static void origin_dtr(struct dm_target *ti) +{ + struct dm_dev *dev = (struct dm_dev *) ti->private; + dm_put_device(ti, dev); +} + +static int origin_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + struct dm_dev *dev = (struct dm_dev *) ti->private; + bio->bi_bdev = dev->bdev; + + /* Only tell snapshots if this is a write */ + return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : 1; +} + +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) + +/* + * Set the target "split_io" field to the minimum of all the snapshots' + * chunk sizes. + */ +static void origin_resume(struct dm_target *ti) +{ + struct dm_dev *dev = (struct dm_dev *) ti->private; + struct dm_snapshot *snap; + struct origin *o; + chunk_t chunk_size = 0; + + down_read(&_origins_lock); + o = __lookup_origin(dev->bdev); + if (o) + list_for_each_entry (snap, &o->snapshots, list) + chunk_size = min_not_zero(chunk_size, snap->chunk_size); + up_read(&_origins_lock); + + ti->split_io = chunk_size; +} + +static int origin_status(struct dm_target *ti, status_type_t type, char *result, + unsigned int maxlen) +{ + struct dm_dev *dev = (struct dm_dev *) ti->private; + char buffer[32]; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + format_dev_t(buffer, dev->bdev->bd_dev); + snprintf(result, maxlen, "%s", buffer); + break; + } + + return 0; +} + +static struct target_type origin_target = { + .name = "snapshot-origin", + .version = {1, 0, 1}, + .module = THIS_MODULE, + .ctr = origin_ctr, + .dtr = origin_dtr, + .map = origin_map, + .resume = origin_resume, + .status = origin_status, +}; + +static struct target_type snapshot_target = { + .name = "snapshot", + .version = {1, 0, 1}, + .module = THIS_MODULE, + .ctr = snapshot_ctr, + .dtr = snapshot_dtr, + .map = snapshot_map, + .resume = snapshot_resume, + .status = snapshot_status, +}; + +static int __init dm_snapshot_init(void) +{ + int r; + + r = dm_register_target(&snapshot_target); + if (r) { + DMERR("snapshot target register failed %d", r); + return r; + } + + r = dm_register_target(&origin_target); + if (r < 0) { + DMERR("Device mapper: Origin: register failed %d\n", r); + goto bad1; + } + + r = init_origin_hash(); + if (r) { + DMERR("init_origin_hash failed."); + goto bad2; + } + + exception_cache = kmem_cache_create("dm-snapshot-ex", + sizeof(struct exception), + __alignof__(struct exception), + 0, NULL, NULL); + if (!exception_cache) { + DMERR("Couldn't create exception cache."); + r = -ENOMEM; + goto bad3; + } + + pending_cache = + kmem_cache_create("dm-snapshot-in", + sizeof(struct pending_exception), + __alignof__(struct pending_exception), + 0, NULL, NULL); + if (!pending_cache) { + DMERR("Couldn't create pending cache."); + r = -ENOMEM; + goto bad4; + } + + pending_pool = mempool_create(128, mempool_alloc_slab, + mempool_free_slab, pending_cache); + if (!pending_pool) { + DMERR("Couldn't create pending pool."); + r = -ENOMEM; + goto bad5; + } + + return 0; + + bad5: + kmem_cache_destroy(pending_cache); + bad4: + kmem_cache_destroy(exception_cache); + bad3: + exit_origin_hash(); + bad2: + dm_unregister_target(&origin_target); + bad1: + dm_unregister_target(&snapshot_target); + return r; +} + +static void __exit dm_snapshot_exit(void) +{ + int r; + + r = dm_unregister_target(&snapshot_target); + if (r) + DMERR("snapshot unregister failed %d", r); + + r = dm_unregister_target(&origin_target); + if (r) + DMERR("origin unregister failed %d", r); + + exit_origin_hash(); + mempool_destroy(pending_pool); + kmem_cache_destroy(pending_cache); + kmem_cache_destroy(exception_cache); +} + +/* Module hooks */ +module_init(dm_snapshot_init); +module_exit(dm_snapshot_exit); + +MODULE_DESCRIPTION(DM_NAME " snapshot target"); +MODULE_AUTHOR("Joe Thornber"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h new file mode 100644 index 000000000..375aa24d4 --- /dev/null +++ b/drivers/md/dm-snap.h @@ -0,0 +1,161 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#ifndef DM_SNAPSHOT_H +#define DM_SNAPSHOT_H + +#include "dm.h" +#include + +struct exception_table { + uint32_t hash_mask; + struct list_head *table; +}; + +/* + * The snapshot code deals with largish chunks of the disk at a + * time. Typically 64k - 256k. + */ +/* FIXME: can we get away with limiting these to a uint32_t ? */ +typedef sector_t chunk_t; + +/* + * An exception is used where an old chunk of data has been + * replaced by a new one. + */ +struct exception { + struct list_head hash_list; + + chunk_t old_chunk; + chunk_t new_chunk; +}; + +/* + * Abstraction to handle the meta/layout of exception stores (the + * COW device). + */ +struct exception_store { + + /* + * Destroys this object when you've finished with it. + */ + void (*destroy) (struct exception_store *store); + + /* + * The target shouldn't read the COW device until this is + * called. + */ + int (*read_metadata) (struct exception_store *store); + + /* + * Find somewhere to store the next exception. + */ + int (*prepare_exception) (struct exception_store *store, + struct exception *e); + + /* + * Update the metadata with this exception. + */ + void (*commit_exception) (struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context); + + /* + * The snapshot is invalid, note this in the metadata. + */ + void (*drop_snapshot) (struct exception_store *store); + + /* + * Return how full the snapshot is. + */ + void (*fraction_full) (struct exception_store *store, + sector_t *numerator, + sector_t *denominator); + + struct dm_snapshot *snap; + void *context; +}; + +struct dm_snapshot { + struct rw_semaphore lock; + struct dm_table *table; + + struct dm_dev *origin; + struct dm_dev *cow; + + /* List of snapshots per Origin */ + struct list_head list; + + /* Size of data blocks saved - must be a power of 2 */ + chunk_t chunk_size; + chunk_t chunk_mask; + chunk_t chunk_shift; + + /* You can't use a snapshot if this is 0 (e.g. if full) */ + int valid; + int have_metadata; + + /* Used for display of table */ + char type; + + /* The last percentage we notified */ + int last_percent; + + struct exception_table pending; + struct exception_table complete; + + /* The on disk metadata handler */ + struct exception_store store; + + struct kcopyd_client *kcopyd_client; +}; + +/* + * Used by the exception stores to load exceptions hen + * initialising. + */ +int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new); + +/* + * Constructor and destructor for the default persistent + * store. + */ +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size); + +int dm_create_transient(struct exception_store *store, + struct dm_snapshot *s, int blocksize); + +/* + * Return the number of sectors in the device. + */ +static inline sector_t get_dev_size(struct block_device *bdev) +{ + return bdev->bd_inode->i_size >> SECTOR_SHIFT; +} + +static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector) +{ + return (sector & ~s->chunk_mask) >> s->chunk_shift; +} + +static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk) +{ + return chunk << s->chunk_shift; +} + +static inline int bdev_equal(struct block_device *lhs, struct block_device *rhs) +{ + /* + * There is only ever one instance of a particular block + * device so we can compare pointers safely. + */ + return lhs == rhs; +} + +#endif diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c new file mode 100644 index 000000000..725f2c812 --- /dev/null +++ b/drivers/md/dm-zero.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2003 Christophe Saout + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include + +/* + * Construct a dummy mapping that only returns zeros + */ +static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + if (argc != 0) { + ti->error = "dm-zero: No arguments required"; + return -EINVAL; + } + + return 0; +} + +/* + * Fills the bio pages with zeros + */ +static void zero_fill_bio(struct bio *bio) +{ + unsigned long flags; + struct bio_vec *bv; + int i; + + bio_for_each_segment(bv, bio, i) { + char *data = bvec_kmap_irq(bv, &flags); + memset(data, 0, bv->bv_len); + flush_dcache_page(bv->bv_page); + bvec_kunmap_irq(data, &flags); + } +} + +/* + * Return zeros only on reads + */ +static int zero_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + switch(bio_rw(bio)) { + case READ: + zero_fill_bio(bio); + break; + case READA: + /* readahead of null bytes only wastes buffer cache */ + return -EIO; + case WRITE: + /* writes get silently dropped */ + break; + } + + bio_endio(bio, bio->bi_size, 0); + + /* accepted bio, don't make new request */ + return 0; +} + +static struct target_type zero_target = { + .name = "zero", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = zero_ctr, + .map = zero_map, +}; + +int __init dm_zero_init(void) +{ + int r = dm_register_target(&zero_target); + + if (r < 0) + DMERR("zero: register failed %d", r); + + return r; +} + +void __exit dm_zero_exit(void) +{ + int r = dm_unregister_target(&zero_target); + + if (r < 0) + DMERR("zero: unregister failed %d", r); +} + +module_init(dm_zero_init) +module_exit(dm_zero_exit) + +MODULE_AUTHOR("Christophe Saout "); +MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c new file mode 100644 index 000000000..40e46944e --- /dev/null +++ b/drivers/md/kcopyd.c @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + * + * Kcopyd provides a simple interface for copying an area of one + * block-device to one or more other block-devices, with an asynchronous + * completion notification. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcopyd.h" + +/* FIXME: this is only needed for the DMERR macros */ +#include "dm.h" + +static struct workqueue_struct *_kcopyd_wq; +static struct work_struct _kcopyd_work; + +static inline void wake(void) +{ + queue_work(_kcopyd_wq, &_kcopyd_work); +} + +/*----------------------------------------------------------------- + * Each kcopyd client has its own little pool of preallocated + * pages for kcopyd io. + *---------------------------------------------------------------*/ +struct kcopyd_client { + struct list_head list; + + spinlock_t lock; + struct page_list *pages; + unsigned int nr_pages; + unsigned int nr_free_pages; +}; + +static struct page_list *alloc_pl(void) +{ + struct page_list *pl; + + pl = kmalloc(sizeof(*pl), GFP_KERNEL); + if (!pl) + return NULL; + + pl->page = alloc_page(GFP_KERNEL); + if (!pl->page) { + kfree(pl); + return NULL; + } + + return pl; +} + +static void free_pl(struct page_list *pl) +{ + __free_page(pl->page); + kfree(pl); +} + +static int kcopyd_get_pages(struct kcopyd_client *kc, + unsigned int nr, struct page_list **pages) +{ + struct page_list *pl; + + spin_lock(&kc->lock); + if (kc->nr_free_pages < nr) { + spin_unlock(&kc->lock); + return -ENOMEM; + } + + kc->nr_free_pages -= nr; + for (*pages = pl = kc->pages; --nr; pl = pl->next) + ; + + kc->pages = pl->next; + pl->next = 0; + + spin_unlock(&kc->lock); + + return 0; +} + +static void kcopyd_put_pages(struct kcopyd_client *kc, struct page_list *pl) +{ + struct page_list *cursor; + + spin_lock(&kc->lock); + for (cursor = pl; cursor->next; cursor = cursor->next) + kc->nr_free_pages++; + + kc->nr_free_pages++; + cursor->next = kc->pages; + kc->pages = pl; + spin_unlock(&kc->lock); +} + +/* + * These three functions resize the page pool. + */ +static void drop_pages(struct page_list *pl) +{ + struct page_list *next; + + while (pl) { + next = pl->next; + free_pl(pl); + pl = next; + } +} + +static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr) +{ + unsigned int i; + struct page_list *pl = NULL, *next; + + for (i = 0; i < nr; i++) { + next = alloc_pl(); + if (!next) { + if (pl) + drop_pages(pl); + return -ENOMEM; + } + next->next = pl; + pl = next; + } + + kcopyd_put_pages(kc, pl); + kc->nr_pages += nr; + return 0; +} + +static void client_free_pages(struct kcopyd_client *kc) +{ + BUG_ON(kc->nr_free_pages != kc->nr_pages); + drop_pages(kc->pages); + kc->pages = NULL; + kc->nr_free_pages = kc->nr_pages = 0; +} + +/*----------------------------------------------------------------- + * kcopyd_jobs need to be allocated by the *clients* of kcopyd, + * for this reason we use a mempool to prevent the client from + * ever having to do io (which could cause a deadlock). + *---------------------------------------------------------------*/ +struct kcopyd_job { + struct kcopyd_client *kc; + struct list_head list; + unsigned long flags; + + /* + * Error state of the job. + */ + int read_err; + unsigned int write_err; + + /* + * Either READ or WRITE + */ + int rw; + struct io_region source; + + /* + * The destinations for the transfer. + */ + unsigned int num_dests; + struct io_region dests[KCOPYD_MAX_REGIONS]; + + sector_t offset; + unsigned int nr_pages; + struct page_list *pages; + + /* + * Set this to ensure you are notified when the job has + * completed. 'context' is for callback to use. + */ + kcopyd_notify_fn fn; + void *context; + + /* + * These fields are only used if the job has been split + * into more manageable parts. + */ + struct semaphore lock; + atomic_t sub_jobs; + sector_t progress; +}; + +/* FIXME: this should scale with the number of pages */ +#define MIN_JOBS 512 + +static kmem_cache_t *_job_cache; +static mempool_t *_job_pool; + +/* + * We maintain three lists of jobs: + * + * i) jobs waiting for pages + * ii) jobs that have pages, and are waiting for the io to be issued. + * iii) jobs that have completed. + * + * All three of these are protected by job_lock. + */ +static spinlock_t _job_lock = SPIN_LOCK_UNLOCKED; + +static LIST_HEAD(_complete_jobs); +static LIST_HEAD(_io_jobs); +static LIST_HEAD(_pages_jobs); + +static int jobs_init(void) +{ + _job_cache = kmem_cache_create("kcopyd-jobs", + sizeof(struct kcopyd_job), + __alignof__(struct kcopyd_job), + 0, NULL, NULL); + if (!_job_cache) + return -ENOMEM; + + _job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _job_cache); + if (!_job_pool) { + kmem_cache_destroy(_job_cache); + return -ENOMEM; + } + + return 0; +} + +static void jobs_exit(void) +{ + BUG_ON(!list_empty(&_complete_jobs)); + BUG_ON(!list_empty(&_io_jobs)); + BUG_ON(!list_empty(&_pages_jobs)); + + mempool_destroy(_job_pool); + kmem_cache_destroy(_job_cache); + _job_pool = NULL; + _job_cache = NULL; +} + +/* + * Functions to push and pop a job onto the head of a given job + * list. + */ +static inline struct kcopyd_job *pop(struct list_head *jobs) +{ + struct kcopyd_job *job = NULL; + unsigned long flags; + + spin_lock_irqsave(&_job_lock, flags); + + if (!list_empty(jobs)) { + job = list_entry(jobs->next, struct kcopyd_job, list); + list_del(&job->list); + } + spin_unlock_irqrestore(&_job_lock, flags); + + return job; +} + +static inline void push(struct list_head *jobs, struct kcopyd_job *job) +{ + unsigned long flags; + + spin_lock_irqsave(&_job_lock, flags); + list_add_tail(&job->list, jobs); + spin_unlock_irqrestore(&_job_lock, flags); +} + +/* + * These three functions process 1 item from the corresponding + * job list. + * + * They return: + * < 0: error + * 0: success + * > 0: can't process yet. + */ +static int run_complete_job(struct kcopyd_job *job) +{ + void *context = job->context; + int read_err = job->read_err; + unsigned int write_err = job->write_err; + kcopyd_notify_fn fn = job->fn; + + kcopyd_put_pages(job->kc, job->pages); + mempool_free(job, _job_pool); + fn(read_err, write_err, context); + return 0; +} + +static void complete_io(unsigned long error, void *context) +{ + struct kcopyd_job *job = (struct kcopyd_job *) context; + + if (error) { + if (job->rw == WRITE) + job->write_err &= error; + else + job->read_err = 1; + + if (!test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) { + push(&_complete_jobs, job); + wake(); + return; + } + } + + if (job->rw == WRITE) + push(&_complete_jobs, job); + + else { + job->rw = WRITE; + push(&_io_jobs, job); + } + + wake(); +} + +/* + * Request io on as many buffer heads as we can currently get for + * a particular job. + */ +static int run_io_job(struct kcopyd_job *job) +{ + int r; + + if (job->rw == READ) + r = dm_io_async(1, &job->source, job->rw, + job->pages, + job->offset, complete_io, job); + + else + r = dm_io_async(job->num_dests, job->dests, job->rw, + job->pages, + job->offset, complete_io, job); + + return r; +} + +static int run_pages_job(struct kcopyd_job *job) +{ + int r; + + job->nr_pages = dm_div_up(job->dests[0].count + job->offset, + PAGE_SIZE >> 9); + r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages); + if (!r) { + /* this job is ready for io */ + push(&_io_jobs, job); + return 0; + } + + if (r == -ENOMEM) + /* can't complete now */ + return 1; + + return r; +} + +/* + * Run through a list for as long as possible. Returns the count + * of successful jobs. + */ +static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) +{ + struct kcopyd_job *job; + int r, count = 0; + + while ((job = pop(jobs))) { + + r = fn(job); + + if (r < 0) { + /* error this rogue job */ + if (job->rw == WRITE) + job->write_err = (unsigned int) -1; + else + job->read_err = 1; + push(&_complete_jobs, job); + break; + } + + if (r > 0) { + /* + * We couldn't service this job ATM, so + * push this job back onto the list. + */ + push(jobs, job); + break; + } + + count++; + } + + return count; +} + +/* + * kcopyd does this every time it's woken up. + */ +static void do_work(void *ignored) +{ + /* + * The order that these are called is *very* important. + * complete jobs can free some pages for pages jobs. + * Pages jobs when successful will jump onto the io jobs + * list. io jobs call wake when they complete and it all + * starts again. + */ + process_jobs(&_complete_jobs, run_complete_job); + process_jobs(&_pages_jobs, run_pages_job); + process_jobs(&_io_jobs, run_io_job); +} + +/* + * If we are copying a small region we just dispatch a single job + * to do the copy, otherwise the io has to be split up into many + * jobs. + */ +static void dispatch_job(struct kcopyd_job *job) +{ + push(&_pages_jobs, job); + wake(); +} + +#define SUB_JOB_SIZE 128 +static void segment_complete(int read_err, + unsigned int write_err, void *context) +{ + /* FIXME: tidy this function */ + sector_t progress = 0; + sector_t count = 0; + struct kcopyd_job *job = (struct kcopyd_job *) context; + + down(&job->lock); + + /* update the error */ + if (read_err) + job->read_err = 1; + + if (write_err) + job->write_err &= write_err; + + /* + * Only dispatch more work if there hasn't been an error. + */ + if ((!job->read_err && !job->write_err) || + test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) { + /* get the next chunk of work */ + progress = job->progress; + count = job->source.count - progress; + if (count) { + if (count > SUB_JOB_SIZE) + count = SUB_JOB_SIZE; + + job->progress += count; + } + } + up(&job->lock); + + if (count) { + int i; + struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO); + + *sub_job = *job; + sub_job->source.sector += progress; + sub_job->source.count = count; + + for (i = 0; i < job->num_dests; i++) { + sub_job->dests[i].sector += progress; + sub_job->dests[i].count = count; + } + + sub_job->fn = segment_complete; + sub_job->context = job; + dispatch_job(sub_job); + + } else if (atomic_dec_and_test(&job->sub_jobs)) { + + /* + * To avoid a race we must keep the job around + * until after the notify function has completed. + * Otherwise the client may try and stop the job + * after we've completed. + */ + job->fn(read_err, write_err, job->context); + mempool_free(job, _job_pool); + } +} + +/* + * Create some little jobs that will do the move between + * them. + */ +#define SPLIT_COUNT 8 +static void split_job(struct kcopyd_job *job) +{ + int i; + + atomic_set(&job->sub_jobs, SPLIT_COUNT); + for (i = 0; i < SPLIT_COUNT; i++) + segment_complete(0, 0u, job); +} + +int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, + unsigned int num_dests, struct io_region *dests, + unsigned int flags, kcopyd_notify_fn fn, void *context) +{ + struct kcopyd_job *job; + + /* + * Allocate a new job. + */ + job = mempool_alloc(_job_pool, GFP_NOIO); + + /* + * set up for the read. + */ + job->kc = kc; + job->flags = flags; + job->read_err = 0; + job->write_err = 0; + job->rw = READ; + + job->source = *from; + + job->num_dests = num_dests; + memcpy(&job->dests, dests, sizeof(*dests) * num_dests); + + job->offset = 0; + job->nr_pages = 0; + job->pages = NULL; + + job->fn = fn; + job->context = context; + + if (job->source.count < SUB_JOB_SIZE) + dispatch_job(job); + + else { + init_MUTEX(&job->lock); + job->progress = 0; + split_job(job); + } + + return 0; +} + +/* + * Cancels a kcopyd job, eg. someone might be deactivating a + * mirror. + */ +int kcopyd_cancel(struct kcopyd_job *job, int block) +{ + /* FIXME: finish */ + return -1; +} + +/*----------------------------------------------------------------- + * Unit setup + *---------------------------------------------------------------*/ +static DECLARE_MUTEX(_client_lock); +static LIST_HEAD(_clients); + +static int client_add(struct kcopyd_client *kc) +{ + down(&_client_lock); + list_add(&kc->list, &_clients); + up(&_client_lock); + return 0; +} + +static void client_del(struct kcopyd_client *kc) +{ + down(&_client_lock); + list_del(&kc->list); + up(&_client_lock); +} + +static DECLARE_MUTEX(kcopyd_init_lock); +static int kcopyd_clients = 0; + +static int kcopyd_init(void) +{ + int r; + + down(&kcopyd_init_lock); + + if (kcopyd_clients) { + /* Already initialized. */ + kcopyd_clients++; + up(&kcopyd_init_lock); + return 0; + } + + r = jobs_init(); + if (r) { + up(&kcopyd_init_lock); + return r; + } + + _kcopyd_wq = create_singlethread_workqueue("kcopyd"); + if (!_kcopyd_wq) { + jobs_exit(); + up(&kcopyd_init_lock); + return -ENOMEM; + } + + kcopyd_clients++; + INIT_WORK(&_kcopyd_work, do_work, NULL); + up(&kcopyd_init_lock); + return 0; +} + +static void kcopyd_exit(void) +{ + down(&kcopyd_init_lock); + kcopyd_clients--; + if (!kcopyd_clients) { + jobs_exit(); + destroy_workqueue(_kcopyd_wq); + _kcopyd_wq = NULL; + } + up(&kcopyd_init_lock); +} + +int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) +{ + int r = 0; + struct kcopyd_client *kc; + + r = kcopyd_init(); + if (r) + return r; + + kc = kmalloc(sizeof(*kc), GFP_KERNEL); + if (!kc) { + kcopyd_exit(); + return -ENOMEM; + } + + kc->lock = SPIN_LOCK_UNLOCKED; + kc->pages = NULL; + kc->nr_pages = kc->nr_free_pages = 0; + r = client_alloc_pages(kc, nr_pages); + if (r) { + kfree(kc); + kcopyd_exit(); + return r; + } + + r = dm_io_get(nr_pages); + if (r) { + client_free_pages(kc); + kfree(kc); + kcopyd_exit(); + return r; + } + + r = client_add(kc); + if (r) { + dm_io_put(nr_pages); + client_free_pages(kc); + kfree(kc); + kcopyd_exit(); + return r; + } + + *result = kc; + return 0; +} + +void kcopyd_client_destroy(struct kcopyd_client *kc) +{ + dm_io_put(kc->nr_pages); + client_free_pages(kc); + client_del(kc); + kfree(kc); + kcopyd_exit(); +} + +EXPORT_SYMBOL(kcopyd_client_create); +EXPORT_SYMBOL(kcopyd_client_destroy); +EXPORT_SYMBOL(kcopyd_copy); +EXPORT_SYMBOL(kcopyd_cancel); diff --git a/drivers/md/kcopyd.h b/drivers/md/kcopyd.h new file mode 100644 index 000000000..4621ea055 --- /dev/null +++ b/drivers/md/kcopyd.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the GPL. + * + * Kcopyd provides a simple interface for copying an area of one + * block-device to one or more other block-devices, with an asynchronous + * completion notification. + */ + +#ifndef DM_KCOPYD_H +#define DM_KCOPYD_H + +#include "dm-io.h" + +/* FIXME: make this configurable */ +#define KCOPYD_MAX_REGIONS 8 + +#define KCOPYD_IGNORE_ERROR 1 + +/* + * To use kcopyd you must first create a kcopyd client object. + */ +struct kcopyd_client; +int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result); +void kcopyd_client_destroy(struct kcopyd_client *kc); + +/* + * Submit a copy job to kcopyd. This is built on top of the + * previous three fns. + * + * read_err is a boolean, + * write_err is a bitset, with 1 bit for each destination region + */ +typedef void (*kcopyd_notify_fn)(int read_err, + unsigned int write_err, void *context); + +int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, + unsigned int num_dests, struct io_region *dests, + unsigned int flags, kcopyd_notify_fn fn, void *context); + +#endif diff --git a/drivers/md/md.c b/drivers/md/md.c index 77cd6e9f3..7992b2106 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1934,7 +1934,7 @@ static int autostart_array(dev_t startdev) } -static int get_version(void __user * arg) +static int get_version(void * arg) { mdu_version_t ver; @@ -1948,7 +1948,7 @@ static int get_version(void __user * arg) return 0; } -static int get_array_info(mddev_t * mddev, void __user * arg) +static int get_array_info(mddev_t * mddev, void * arg) { mdu_array_info_t info; int nr,working,active,failed,spare; @@ -1998,7 +1998,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg) return 0; } -static int get_disk_info(mddev_t * mddev, void __user * arg) +static int get_disk_info(mddev_t * mddev, void * arg) { mdu_disk_info_t info; unsigned int nr; @@ -2251,12 +2251,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) return -EINVAL; } - if (mddev->persistent) - rdev->sb_offset = calc_dev_sboffset(rdev->bdev); - else - rdev->sb_offset = - rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; - + rdev->sb_offset = calc_dev_sboffset(rdev->bdev); size = calc_dev_size(rdev, mddev->chunk_size); rdev->size = size; @@ -2377,103 +2372,6 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) return 0; } -/* - * update_array_info is used to change the configuration of an - * on-line array. - * The version, ctime,level,size,raid_disks,not_persistent, layout,chunk_size - * fields in the info are checked against the array. - * Any differences that cannot be handled will cause an error. - * Normally, only one change can be managed at a time. - */ -static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) -{ - int rv = 0; - int cnt = 0; - - if (mddev->major_version != info->major_version || - mddev->minor_version != info->minor_version || -/* mddev->patch_version != info->patch_version || */ - mddev->ctime != info->ctime || - mddev->level != info->level || - mddev->layout != info->layout || - !mddev->persistent != info->not_persistent|| - mddev->chunk_size != info->chunk_size ) - return -EINVAL; - /* Check there is only one change */ - if (mddev->size != info->size) cnt++; - if (mddev->raid_disks != info->raid_disks) cnt++; - if (cnt == 0) return 0; - if (cnt > 1) return -EINVAL; - - if (mddev->size != info->size) { - mdk_rdev_t * rdev; - struct list_head *tmp; - if (mddev->pers->resize == NULL) - return -EINVAL; - /* The "size" is the amount of each device that is used. - * This can only make sense for arrays with redundancy. - * linear and raid0 always use whatever space is available - * We can only consider changing the size of no resync - * or reconstruction is happening, and if the new size - * is acceptable. It must fit before the sb_offset or, - * if that is sync_thread) - return -EBUSY; - ITERATE_RDEV(mddev,rdev,tmp) { - sector_t avail; - int fit = (info->size == 0); - if (rdev->sb_offset > rdev->data_offset) - avail = (rdev->sb_offset*2) - rdev->data_offset; - else - avail = get_capacity(rdev->bdev->bd_disk) - - rdev->data_offset; - if (fit && (info->size == 0 || info->size > avail/2)) - info->size = avail/2; - if (avail < ((sector_t)info->size << 1)) - return -ENOSPC; - } - rv = mddev->pers->resize(mddev, (sector_t)info->size *2); - if (!rv) { - struct block_device *bdev; - - bdev = bdget_disk(mddev->gendisk, 0); - if (bdev) { - down(&bdev->bd_inode->i_sem); - i_size_write(bdev->bd_inode, mddev->array_size << 10); - up(&bdev->bd_inode->i_sem); - bdput(bdev); - } - } - } - if (mddev->raid_disks != info->raid_disks) { - /* change the number of raid disks */ - if (mddev->pers->reshape == NULL) - return -EINVAL; - if (info->raid_disks <= 0 || - info->raid_disks >= mddev->max_disks) - return -EINVAL; - if (mddev->sync_thread) - return -EBUSY; - rv = mddev->pers->reshape(mddev, info->raid_disks); - if (!rv) { - struct block_device *bdev; - - bdev = bdget_disk(mddev->gendisk, 0); - if (bdev) { - down(&bdev->bd_inode->i_sem); - i_size_write(bdev->bd_inode, mddev->array_size << 10); - up(&bdev->bd_inode->i_sem); - bdput(bdev); - } - } - } - md_update_sb(mddev); - return rv; -} - static int set_disk_faulty(mddev_t *mddev, dev_t dev) { mdk_rdev_t *rdev; @@ -2491,8 +2389,7 @@ static int md_ioctl(struct inode *inode, struct file *file, { char b[BDEVNAME_SIZE]; int err = 0; - void __user *argp = (void __user *)arg; - struct hd_geometry __user *loc = argp; + struct hd_geometry *loc = (struct hd_geometry *) arg; mddev_t *mddev = NULL; if (!capable(CAP_SYS_ADMIN)) @@ -2505,7 +2402,7 @@ static int md_ioctl(struct inode *inode, struct file *file, switch (cmd) { case RAID_VERSION: - err = get_version(argp); + err = get_version((void *)arg); goto done; case PRINT_RAID_DEBUG: @@ -2566,41 +2463,33 @@ static int md_ioctl(struct inode *inode, struct file *file, switch (cmd) { case SET_ARRAY_INFO: + + if (!list_empty(&mddev->disks)) { + printk(KERN_WARNING + "md: array %s already has disks!\n", + mdname(mddev)); + err = -EBUSY; + goto abort_unlock; + } + if (mddev->raid_disks) { + printk(KERN_WARNING + "md: array %s already initialised!\n", + mdname(mddev)); + err = -EBUSY; + goto abort_unlock; + } { mdu_array_info_t info; if (!arg) memset(&info, 0, sizeof(info)); - else if (copy_from_user(&info, argp, sizeof(info))) { + else if (copy_from_user(&info, (void*)arg, sizeof(info))) { err = -EFAULT; goto abort_unlock; } - if (mddev->pers) { - err = update_array_info(mddev, &info); - if (err) { - printk(KERN_WARNING "md: couldn't update" - " array info. %d\n", err); - goto abort_unlock; - } - goto done_unlock; - } - if (!list_empty(&mddev->disks)) { - printk(KERN_WARNING - "md: array %s already has disks!\n", - mdname(mddev)); - err = -EBUSY; - goto abort_unlock; - } - if (mddev->raid_disks) { - printk(KERN_WARNING - "md: array %s already initialised!\n", - mdname(mddev)); - err = -EBUSY; - goto abort_unlock; - } err = set_array_info(mddev, &info); if (err) { printk(KERN_WARNING "md: couldn't set" - " array info. %d\n", err); + " array info. %d\n", err); goto abort_unlock; } } @@ -2624,11 +2513,11 @@ static int md_ioctl(struct inode *inode, struct file *file, switch (cmd) { case GET_ARRAY_INFO: - err = get_array_info(mddev, argp); + err = get_array_info(mddev, (void *)arg); goto done_unlock; case GET_DISK_INFO: - err = get_disk_info(mddev, argp); + err = get_disk_info(mddev, (void *)arg); goto done_unlock; case RESTART_ARRAY_RW: @@ -2654,18 +2543,18 @@ static int md_ioctl(struct inode *inode, struct file *file, err = -EINVAL; goto abort_unlock; } - err = put_user (2, (char __user *) &loc->heads); + err = put_user (2, (char *) &loc->heads); if (err) goto abort_unlock; - err = put_user (4, (char __user *) &loc->sectors); + err = put_user (4, (char *) &loc->sectors); if (err) goto abort_unlock; err = put_user(get_capacity(mddev->gendisk)/8, - (short __user *) &loc->cylinders); + (short *) &loc->cylinders); if (err) goto abort_unlock; err = put_user (get_start_sect(inode->i_bdev), - (long __user *) &loc->start); + (long *) &loc->start); goto done_unlock; } @@ -2684,7 +2573,7 @@ static int md_ioctl(struct inode *inode, struct file *file, case ADD_NEW_DISK: { mdu_disk_info_t info; - if (copy_from_user(&info, argp, sizeof(info))) + if (copy_from_user(&info, (void*)arg, sizeof(info))) err = -EFAULT; else err = add_new_disk(mddev, &info); @@ -3389,7 +3278,7 @@ static void md_do_sync(mddev_t *mddev) j += sectors; if (j>1) mddev->curr_resync = j; - if (last_check + window > j || j == max_sectors) + if (last_check + window > j) continue; last_check = j; @@ -3555,8 +3444,8 @@ void md_check_recovery(mddev_t *mddev) if (rdev->raid_disk >= 0 && rdev->faulty && atomic_read(&rdev->nr_pending)==0) { - if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) - rdev->raid_disk = -1; + mddev->pers->hot_remove_disk(mddev, rdev->raid_disk); + rdev->raid_disk = -1; } if (!rdev->faulty && rdev->raid_disk >= 0 && !rdev->in_sync) spares++; diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3d8790135..8f675d17f 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -54,8 +54,9 @@ static void mp_pool_free(void *mpb, void *data) kfree(mpb); } -static int multipath_map (multipath_conf_t *conf) +static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp) { + multipath_conf_t *conf = mddev_to_conf(mddev); int i, disks = conf->raid_disks; /* @@ -67,9 +68,10 @@ static int multipath_map (multipath_conf_t *conf) for (i = 0; i < disks; i++) { mdk_rdev_t *rdev = conf->multipaths[i].rdev; if (rdev && rdev->in_sync) { + *rdevp = rdev; atomic_inc(&rdev->nr_pending); spin_unlock_irq(&conf->device_lock); - return i; + return 0; } } spin_unlock_irq(&conf->device_lock); @@ -131,7 +133,25 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error) (unsigned long long)bio->bi_sector); multipath_reschedule_retry(mp_bh); } - rdev_dec_pending(rdev, conf->mddev); + atomic_dec(&rdev->nr_pending); + return 0; +} + +/* + * This routine returns the disk from which the requested read should + * be done. + */ + +static int multipath_read_balance (multipath_conf_t *conf) +{ + int disk; + + for (disk = 0; disk < conf->raid_disks; disk++) { + mdk_rdev_t *rdev = conf->multipaths[disk].rdev; + if (rdev && rdev->in_sync) + return disk; + } + BUG(); return 0; } @@ -184,14 +204,14 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) disk_stat_inc(mddev->gendisk, reads); disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio)); } - - mp_bh->path = multipath_map(conf); - if (mp_bh->path < 0) { - bio_endio(bio, bio->bi_size, -EIO); - mempool_free(mp_bh, conf->pool); - return 0; - } + /* + * read balancing logic: + */ + spin_lock_irq(&conf->device_lock); + mp_bh->path = multipath_read_balance(conf); multipath = conf->multipaths + mp_bh->path; + atomic_inc(&multipath->rdev->nr_pending); + spin_unlock_irq(&conf->device_lock); mp_bh->bio = *bio; mp_bh->bio.bi_bdev = multipath->rdev->bdev; @@ -355,7 +375,7 @@ static void multipathd (mddev_t *mddev) struct multipath_bh *mp_bh; struct bio *bio; unsigned long flags; - multipath_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t *rdev; md_check_recovery(mddev); for (;;) { @@ -371,7 +391,8 @@ static void multipathd (mddev_t *mddev) bio = &mp_bh->bio; bio->bi_sector = mp_bh->master_bio->bi_sector; - if ((mp_bh->path = multipath_map (conf))<0) { + rdev = NULL; + if (multipath_map (mddev, &rdev)<0) { printk(KERN_ALERT "multipath: %s: unrecoverable IO read" " error for block %llu\n", bdevname(bio->bi_bdev,b), @@ -382,7 +403,7 @@ static void multipathd (mddev_t *mddev) " to another IO path\n", bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); - bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; + bio->bi_bdev = rdev->bdev; generic_make_request(bio); } } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1b80c5b68..c600b1b2d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -42,17 +42,16 @@ static void unplug_slaves(mddev_t *mddev); static void * r1bio_pool_alloc(int gfp_flags, void *data) { - struct pool_info *pi = data; + mddev_t *mddev = data; r1bio_t *r1_bio; /* allocate a r1bio with room for raid_disks entries in the bios array */ - r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*pi->raid_disks, + r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks, gfp_flags); if (r1_bio) - memset(r1_bio, 0, sizeof(*r1_bio) + - sizeof(struct bio*) * pi->raid_disks); + memset(r1_bio, 0, sizeof(*r1_bio) + sizeof(struct bio*)*mddev->raid_disks); else - unplug_slaves(pi->mddev); + unplug_slaves(mddev); return r1_bio; } @@ -70,22 +69,22 @@ static void r1bio_pool_free(void *r1_bio, void *data) static void * r1buf_pool_alloc(int gfp_flags, void *data) { - struct pool_info *pi = data; + conf_t *conf = data; struct page *page; r1bio_t *r1_bio; struct bio *bio; int i, j; - r1_bio = r1bio_pool_alloc(gfp_flags, pi); + r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev); if (!r1_bio) { - unplug_slaves(pi->mddev); + unplug_slaves(conf->mddev); return NULL; } /* * Allocate bios : 1 for reading, n-1 for writing */ - for (j = pi->raid_disks ; j-- ; ) { + for (j = conf->raid_disks ; j-- ; ) { bio = bio_alloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_bio; @@ -112,16 +111,16 @@ out_free_pages: for ( ; i > 0 ; i--) __free_page(bio->bi_io_vec[i-1].bv_page); out_free_bio: - while ( ++j < pi->raid_disks ) + while ( ++j < conf->raid_disks ) bio_put(r1_bio->bios[j]); - r1bio_pool_free(r1_bio, data); + r1bio_pool_free(r1_bio, conf->mddev); return NULL; } static void r1buf_pool_free(void *__r1_bio, void *data) { - struct pool_info *pi = data; int i; + conf_t *conf = data; r1bio_t *r1bio = __r1_bio; struct bio *bio = r1bio->bios[0]; @@ -129,10 +128,10 @@ static void r1buf_pool_free(void *__r1_bio, void *data) __free_page(bio->bi_io_vec[i].bv_page); bio->bi_io_vec[i].bv_page = NULL; } - for (i=0 ; i < pi->raid_disks; i++) + for (i=0 ; i < conf->raid_disks; i++) bio_put(r1bio->bios[i]); - r1bio_pool_free(r1bio, data); + r1bio_pool_free(r1bio, conf->mddev); } static void put_all_bios(conf_t *conf, r1bio_t *r1_bio) @@ -297,7 +296,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int reschedule_retry(r1_bio); } - rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); + atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); return 0; } @@ -344,7 +343,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int raid_end_bio_io(r1_bio); } - rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); + atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); return 0; } @@ -511,7 +510,7 @@ static int make_request(request_queue_t *q, struct bio * bio) mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *read_bio; - int i, disks; + int i, disks = conf->raid_disks; /* * Register the new request and wait if the reconstruction @@ -571,7 +570,6 @@ static int make_request(request_queue_t *q, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ - disks = conf->raid_disks; spin_lock_irq(&conf->device_lock); for (i = 0; i < disks; i++) { if (conf->mirrors[i].rdev && @@ -807,7 +805,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) conf->mirrors[r1_bio->read_disk].rdev); else set_bit(R1BIO_Uptodate, &r1_bio->state); - rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev); + atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending); reschedule_retry(r1_bio); return 0; } @@ -837,7 +835,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) md_done_sync(mddev, r1_bio->sectors, uptodate); put_buf(r1_bio); } - rdev_dec_pending(conf->mirrors[mirror].rdev, mddev); + atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); return 0; } @@ -955,8 +953,7 @@ static int init_resync(conf_t *conf) buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; if (conf->r1buf_pool) BUG(); - conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, - conf->poolinfo); + conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf); if (!conf->r1buf_pool) return -ENOMEM; conf->next_resync = 0; @@ -982,7 +979,6 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) sector_t max_sector, nr_sectors; int disk; int i; - int write_targets = 0; if (!conf->r1buf_pool) if (init_resync(conf)) @@ -1059,24 +1055,12 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) sector_nr + RESYNC_SECTORS > mddev->recovery_cp)) { bio->bi_rw = WRITE; bio->bi_end_io = end_sync_write; - write_targets ++; } else continue; bio->bi_sector = sector_nr + conf->mirrors[i].rdev->data_offset; bio->bi_bdev = conf->mirrors[i].rdev->bdev; bio->bi_private = r1_bio; } - if (write_targets == 0) { - /* There is nowhere to write, so all non-sync - * drives must be failed - so we are finished - */ - int rv = max_sector - sector_nr; - md_done_sync(mddev, rv, 1); - put_buf(r1_bio); - atomic_dec(&conf->mirrors[disk].rdev->nr_pending); - return rv; - } - nr_sectors = 0; do { struct page *page; @@ -1139,28 +1123,28 @@ static int run(mddev_t *mddev) */ conf = kmalloc(sizeof(conf_t), GFP_KERNEL); mddev->private = conf; - if (!conf) - goto out_no_mem; - + if (!conf) { + printk(KERN_ERR "raid1: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out; + } memset(conf, 0, sizeof(*conf)); conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, GFP_KERNEL); - if (!conf->mirrors) - goto out_no_mem; - + if (!conf->mirrors) { + printk(KERN_ERR "raid1: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out_free_conf; + } memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks); - conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL); - if (!conf->poolinfo) - goto out_no_mem; - conf->poolinfo->mddev = mddev; - conf->poolinfo->raid_disks = mddev->raid_disks; conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, - conf->poolinfo); - if (!conf->r1bio_pool) - goto out_no_mem; - + r1bio_pool_free, mddev); + if (!conf->r1bio_pool) { + printk(KERN_ERR "raid1: couldn't allocate memory for %s\n", + mdname(mddev)); + goto out_free_conf; + } mddev->queue->unplug_fn = raid1_unplug; @@ -1246,21 +1230,13 @@ static int run(mddev_t *mddev) return 0; -out_no_mem: - printk(KERN_ERR "raid1: couldn't allocate memory for %s\n", - mdname(mddev)); - out_free_conf: - if (conf) { - if (conf->r1bio_pool) - mempool_destroy(conf->r1bio_pool); - if (conf->mirrors) - kfree(conf->mirrors); - if (conf->poolinfo) - kfree(conf->poolinfo); - kfree(conf); - mddev->private = NULL; - } + if (conf->r1bio_pool) + mempool_destroy(conf->r1bio_pool); + if (conf->mirrors) + kfree(conf->mirrors); + kfree(conf); + mddev->private = NULL; out: return -EIO; } @@ -1275,108 +1251,11 @@ static int stop(mddev_t *mddev) mempool_destroy(conf->r1bio_pool); if (conf->mirrors) kfree(conf->mirrors); - if (conf->poolinfo) - kfree(conf->poolinfo); kfree(conf); mddev->private = NULL; return 0; } -static int raid1_resize(mddev_t *mddev, sector_t sectors) -{ - /* no resync is happening, and there is enough space - * on all devices, so we can resize. - * We need to make sure resync covers any new space. - * If the array is shrinking we should possibly wait until - * any io in the removed space completes, but it hardly seems - * worth it. - */ - mddev->array_size = sectors>>1; - set_capacity(mddev->gendisk, mddev->array_size << 1); - mddev->changed = 1; - if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) { - mddev->recovery_cp = mddev->size << 1; - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - } - mddev->size = mddev->array_size; - return 0; -} - -static int raid1_reshape(mddev_t *mddev, int raid_disks) -{ - /* We need to: - * 1/ resize the r1bio_pool - * 2/ resize conf->mirrors - * - * We allocate a new r1bio_pool if we can. - * Then raise a device barrier and wait until all IO stops. - * Then resize conf->mirrors and swap in the new r1bio pool. - */ - mempool_t *newpool, *oldpool; - struct pool_info *newpoolinfo; - mirror_info_t *newmirrors; - conf_t *conf = mddev_to_conf(mddev); - - int d; - - for (d= raid_disks; d < conf->raid_disks; d++) - if (conf->mirrors[d].rdev) - return -EBUSY; - - newpoolinfo = kmalloc(sizeof(newpoolinfo), GFP_KERNEL); - if (!newpoolinfo) - return -ENOMEM; - newpoolinfo->mddev = mddev; - newpoolinfo->raid_disks = raid_disks; - - newpool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, newpoolinfo); - if (!newpool) { - kfree(newpoolinfo); - return -ENOMEM; - } - newmirrors = kmalloc(sizeof(struct mirror_info) * raid_disks, GFP_KERNEL); - if (!newmirrors) { - kfree(newpoolinfo); - mempool_destroy(newpool); - return -ENOMEM; - } - memset(newmirrors, 0, sizeof(struct mirror_info)*raid_disks); - - spin_lock_irq(&conf->resync_lock); - conf->barrier++; - wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, - conf->resync_lock, unplug_slaves(mddev)); - spin_unlock_irq(&conf->resync_lock); - - /* ok, everything is stopped */ - oldpool = conf->r1bio_pool; - conf->r1bio_pool = newpool; - for (d=0; d < raid_disks && d < conf->raid_disks; d++) - newmirrors[d] = conf->mirrors[d]; - kfree(conf->mirrors); - conf->mirrors = newmirrors; - kfree(conf->poolinfo); - conf->poolinfo = newpoolinfo; - - mddev->degraded += (raid_disks - conf->raid_disks); - conf->raid_disks = mddev->raid_disks = raid_disks; - - spin_lock_irq(&conf->resync_lock); - conf->barrier--; - spin_unlock_irq(&conf->resync_lock); - wake_up(&conf->wait_resume); - wake_up(&conf->wait_idle); - - - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - md_wakeup_thread(mddev->thread); - - mempool_destroy(oldpool); - return 0; -} - - static mdk_personality_t raid1_personality = { .name = "raid1", @@ -1390,8 +1269,6 @@ static mdk_personality_t raid1_personality = .hot_remove_disk= raid1_remove_disk, .spare_active = raid1_spare_active, .sync_request = sync_request, - .resize = raid1_resize, - .reshape = raid1_reshape, }; static int __init raid_init(void) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 773f9bfe7..402edd5e3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -395,7 +395,7 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done, md_error(conf->mddev, conf->disks[i].rdev); clear_bit(R5_UPTODATE, &sh->dev[i].flags); } - rdev_dec_pending(conf->disks[i].rdev, conf->mddev); + atomic_dec(&conf->disks[i].rdev->nr_pending); #if 0 /* must restore b_page before unlocking buffer... */ if (sh->bh_page[i] != bh->b_page) { @@ -438,7 +438,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, if (!uptodate) md_error(conf->mddev, conf->disks[i].rdev); - rdev_dec_pending(conf->disks[i].rdev, conf->mddev); + atomic_dec(&conf->disks[i].rdev->nr_pending); clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); @@ -1037,7 +1037,7 @@ static void handle_stripe(struct stripe_head *sh) * parity, or to satisfy requests * or to load a block that is being partially written. */ - if (to_read || non_overwrite || (syncing && (uptodate < disks))) { + if (to_read || non_overwrite || (syncing && (uptodate+failed < disks))) { for (i=disks; i--;) { dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && @@ -1577,9 +1577,6 @@ static int run (mddev_t *mddev) conf->algorithm = mddev->layout; conf->max_nr_stripes = NR_STRIPES; - /* device size must be a multiple of chunk size */ - mddev->size &= ~(mddev->chunk_size/1024 -1); - if (!conf->chunk_size || conf->chunk_size % 4) { printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", conf->chunk_size, mdname(mddev)); @@ -1831,27 +1828,6 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) return found; } -static int raid5_resize(mddev_t *mddev, sector_t sectors) -{ - /* no resync is happening, and there is enough space - * on all devices, so we can resize. - * We need to make sure resync covers any new space. - * If the array is shrinking we should possibly wait until - * any io in the removed space completes, but it hardly seems - * worth it. - */ - sectors &= ~((sector_t)mddev->chunk_size/512 - 1); - mddev->array_size = (sectors * (mddev->raid_disks-1))>>1; - set_capacity(mddev->gendisk, mddev->array_size << 1); - mddev->changed = 1; - if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { - mddev->recovery_cp = mddev->size << 1; - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - } - mddev->size = sectors /2; - return 0; -} - static mdk_personality_t raid5_personality= { .name = "raid5", @@ -1865,7 +1841,6 @@ static mdk_personality_t raid5_personality= .hot_remove_disk= raid5_remove_disk, .spare_active = raid5_spare_active, .sync_request = sync_request, - .resize = raid5_resize, }; static int __init raid5_init (void) diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 714dfb2e1..ceaec272e 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -414,7 +414,7 @@ static int raid6_end_read_request (struct bio * bi, unsigned int bytes_done, md_error(conf->mddev, conf->disks[i].rdev); clear_bit(R5_UPTODATE, &sh->dev[i].flags); } - rdev_dec_pending(conf->disks[i].rdev, conf->mddev); + atomic_dec(&conf->disks[i].rdev->nr_pending); #if 0 /* must restore b_page before unlocking buffer... */ if (sh->bh_page[i] != bh->b_page) { @@ -457,7 +457,7 @@ static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done, if (!uptodate) md_error(conf->mddev, conf->disks[i].rdev); - rdev_dec_pending(conf->disks[i].rdev, conf->mddev); + atomic_dec(&conf->disks[i].rdev->nr_pending); clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); @@ -1157,7 +1157,7 @@ static void handle_stripe(struct stripe_head *sh) * parity, or to satisfy requests * or to load a block that is being partially written. */ - if (to_read || non_overwrite || (syncing && (uptodate < disks))) { + if (to_read || non_overwrite || (syncing && (uptodate+failed < disks))) { for (i=disks; i--;) { dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && @@ -1741,9 +1741,6 @@ static int run (mddev_t *mddev) conf->algorithm = mddev->layout; conf->max_nr_stripes = NR_STRIPES; - /* device size must be a multiple of chunk size */ - mddev->size &= ~(mddev->chunk_size/1024 -1); - if (conf->raid_disks < 4) { printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", mdname(mddev), conf->raid_disks); @@ -2000,27 +1997,6 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) return found; } -static int raid6_resize(mddev_t *mddev, sector_t sectors) -{ - /* no resync is happening, and there is enough space - * on all devices, so we can resize. - * We need to make sure resync covers any new space. - * If the array is shrinking we should possibly wait until - * any io in the removed space completes, but it hardly seems - * worth it. - */ - sectors &= ~((sector_t)mddev->chunk_size/512 - 1); - mddev->array_size = (sectors * (mddev->raid_disks-2))>>1; - set_capacity(mddev->gendisk, mddev->array_size << 1); - mddev->changed = 1; - if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { - mddev->recovery_cp = mddev->size << 1; - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - } - mddev->size = sectors /2; - return 0; -} - static mdk_personality_t raid6_personality= { .name = "raid6", @@ -2034,7 +2010,6 @@ static mdk_personality_t raid6_personality= .hot_remove_disk= raid6_remove_disk, .spare_active = raid6_spare_active, .sync_request = sync_request, - .resize = raid6_resize, }; static int __init raid6_init (void) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 159ccc0b6..ce539ba17 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -108,9 +108,6 @@ #define M29W160DT 0x22C4 #define M29W160DB 0x2249 #define M29W040B 0x00E3 -#define M50FW040 0x002C -#define M50FW080 0x002D -#define M50FW016 0x002E /* SST */ #define SST29EE512 0x005d @@ -1236,45 +1233,6 @@ static const struct amd_flash_info jedec_table[] = { .regions = { ERASEINFO(0x10000,8), } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M50FW040, - .name = "ST M50FW040", - .uaddr = { - [0] = MTD_UADDR_UNNECESSARY, /* x8 */ - }, - .DevSize = SIZE_512KiB, - .CmdSet = P_ID_INTEL_EXT, - .NumEraseRegions= 1, - .regions = { - ERASEINFO(0x10000,8), - } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M50FW080, - .name = "ST M50FW080", - .uaddr = { - [0] = MTD_UADDR_UNNECESSARY, /* x8 */ - }, - .DevSize = SIZE_1MiB, - .CmdSet = P_ID_INTEL_EXT, - .NumEraseRegions= 1, - .regions = { - ERASEINFO(0x10000,16), - } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M50FW016, - .name = "ST M50FW016", - .uaddr = { - [0] = MTD_UADDR_UNNECESSARY, /* x8 */ - }, - .DevSize = SIZE_2MiB, - .CmdSet = P_ID_INTEL_EXT, - .NumEraseRegions= 1, - .regions = { - ERASEINFO(0x10000,32), - } }, { .mfr_id = MANUFACTURER_TOSHIBA, .dev_id = TC58FVT160, diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 03d39d703..e0b957b9e 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -489,13 +489,5 @@ config MTD_UCLINUX help Map driver to support image based filesystems for uClinux. -config MTD_WRSBC8260 - tristate "Map driver for WindRiver PowerQUICC II MPC82xx board" - depends on MTD_PARTITIONS && SBC82xx - help - Map driver for WindRiver PowerQUICC II MPC82xx board. Drives - all three flash regions on CS0, CS1 and CS6 if they are configured - correctly by the boot loader. - endmenu diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 929d66861..230c88c30 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -56,4 +56,3 @@ obj-$(CONFIG_MTD_BEECH) += beech-mtd.o obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o obj-$(CONFIG_MTD_H720X) += h720x-flash.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o -obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a450864a9..9d436ae8d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -884,7 +884,7 @@ static struct media_table { static int vortex_probe1(struct device *gendev, long ioaddr, int irq, int chip_idx, int card_idx); static void vortex_up(struct net_device *dev); -static void vortex_down(struct net_device *dev); +static void vortex_down(struct net_device *dev, int final); static int vortex_open(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); static int mdio_read(struct net_device *dev, int phy_id, int location); @@ -948,7 +948,7 @@ static int vortex_suspend (struct pci_dev *pdev, u32 state) if (dev && dev->priv) { if (netif_running(dev)) { netif_device_detach(dev); - vortex_down(dev); + vortex_down(dev, 1); } } return 0; @@ -2059,7 +2059,8 @@ vortex_error(struct net_device *dev, int status) printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); /* In this case, blow the card away */ - vortex_down(dev); + /* Must not enter D3 or we can't legally issue the reset! */ + vortex_down(dev, 0); issue_and_wait(dev, TotalReset | 0xff); vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */ } else if (fifo_diag & 0x0400) @@ -2656,7 +2657,7 @@ rx_oom_timer(unsigned long arg) } static void -vortex_down(struct net_device *dev) +vortex_down(struct net_device *dev, int final_down) { struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; @@ -2685,7 +2686,7 @@ vortex_down(struct net_device *dev) if (vp->full_bus_master_tx) outl(0, ioaddr + DownListPtr); - if (VORTEX_PCI(vp) && vp->enable_wol) { + if (final_down && VORTEX_PCI(vp) && vp->enable_wol) { pci_save_state(VORTEX_PCI(vp), vp->power_state); acpi_set_WOL(dev); } @@ -2699,7 +2700,7 @@ vortex_close(struct net_device *dev) int i; if (netif_device_present(dev)) - vortex_down(dev); + vortex_down(dev, 1); if (vortex_debug > 1) { printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", @@ -2869,11 +2870,11 @@ static struct ethtool_ops vortex_ethtool_ops = { .get_drvinfo = vortex_get_drvinfo, }; -static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int vortex_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = if_mii(rq); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; int retval; @@ -2904,6 +2905,30 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return retval; } +/* + * Must power the device up to do MDIO operations + */ +static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int err; + struct vortex_private *vp = netdev_priv(dev); + int state = 0; + + if(VORTEX_PCI(vp)) + state = VORTEX_PCI(vp)->current_state; + + /* The kernel core really should have pci_get_power_state() */ + + if(state != 0) + pci_set_power_state(VORTEX_PCI(vp), 0); + err = vortex_do_ioctl(dev, rq, cmd); + if(state != 0) + pci_set_power_state(VORTEX_PCI(vp), state); + + return err; +} + + /* Pre-Cyclone chips have no documented multicast filter, so the only multicast setting is to receive all multicast frames. At least the chip has a very clean way to set the mode, unlike many others. */ @@ -3059,14 +3084,14 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) * here */ unregister_netdev(dev); - /* Should really use issue_and_wait() here */ - outw(TotalReset|0x14, dev->base_addr + EL3_CMD); if (VORTEX_PCI(vp) && vp->enable_wol) { pci_set_power_state(VORTEX_PCI(vp), 0); /* Go active */ if (vp->pm_state_valid) pci_restore_state(VORTEX_PCI(vp), vp->power_state); } + /* Should really use issue_and_wait() here */ + outw(TotalReset|0x14, dev->base_addr + EL3_CMD); pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 83a1bd11b..511c2c814 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2458,13 +2458,14 @@ static struct ethtool_ops rtl8139_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *np = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); + rc = generic_mii_ioctl(&np->mii, data, cmd, NULL); spin_unlock_irq(&np->lock); return rc; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 23ae50c44..346f595b6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1057,7 +1057,6 @@ config ETH16I config NE2000 tristate "NE2000/NE1000 support" - depends on NET_ISA || (Q40 && m) select CRC32 ---help--- If you have a network (Ethernet) card of this type, say Y and read diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 51cf16430..d2c237035 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -439,7 +439,7 @@ MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descript MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)"); -static char version[] __initdata = +static char version[] = "acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; diff --git a/drivers/net/arm/smc91x.c b/drivers/net/arm/smc91x.c new file mode 100644 index 000000000..3968a1cd5 --- /dev/null +++ b/drivers/net/arm/smc91x.c @@ -0,0 +1,2171 @@ +/* + * smc91x.c + * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. + * + * Copyright (C) 1996 by Erik Stahlman + * Copyright (C) 2001 Standard Microsystems Corporation + * Developed by Simple Network Magic Corporation + * Copyright (C) 2003 Monta Vista Software, Inc. + * Unified SMC91x driver by Nicolas Pitre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Arguments: + * io = for the base address + * irq = for the IRQ + * nowait = 0 for normal wait states, 1 eliminates additional wait states + * + * original author: + * Erik Stahlman + * + * hardware multicast code: + * Peter Cammaert + * + * contributors: + * Daris A Nevil + * Nicolas Pitre + * Russell King + * + * History: + * 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet + * 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" + * 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 + * 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 + * 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 + * 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support + * 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, + * more bus abstraction, big cleanup, etc. + * 29/09/03 Russell King - add driver model support + * - ethtool support + * - convert to use generic MII interface + * - add link up/down notification + * - don't try to handle full negotiation in + * smc_phy_configure + * - clean up (and fix stack overrun) in PHY + * MII read/write functions + */ +static const char version[] = + "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre \n"; + +/* Debugging level */ +#ifndef SMC_DEBUG +#define SMC_DEBUG 0 +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "smc91x.h" + +#ifdef CONFIG_ISA +/* + * the LAN91C111 can be at any of the following port addresses. To change, + * for a slightly different card, you can add it to the array. Keep in + * mind that the array must end in zero. + */ +static unsigned int smc_portlist[] __initdata = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 +}; + +#ifndef SMC_IOADDR +# define SMC_IOADDR -1 +#endif +static unsigned long io = SMC_IOADDR; +module_param(io, ulong, 0400); +MODULE_PARM_DESC(io, "I/O base address"); + +#ifndef SMC_IRQ +# define SMC_IRQ -1 +#endif +static int irq = SMC_IRQ; +module_param(irq, int, 0400); +MODULE_PARM_DESC(irq, "IRQ number"); + +#endif /* CONFIG_ISA */ + +#ifndef SMC_NOWAIT +# define SMC_NOWAIT 0 +#endif +static int nowait = SMC_NOWAIT; +module_param(nowait, int, 0400); +MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); + +/* + * Transmit timeout, default 5 seconds. + */ +static int watchdog = 5000; +module_param(watchdog, int, 0400); +MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); + +MODULE_LICENSE("GPL"); + +/* + * The internal workings of the driver. If you are changing anything + * here with the SMC stuff, you should have the datasheet and know + * what you are doing. + */ +#define CARDNAME "smc91x" + +/* + * Use power-down feature of the chip + */ +#define POWER_DOWN 1 + +/* + * Wait time for memory to be free. This probably shouldn't be + * tuned that much, as waiting for this means nothing else happens + * in the system + */ +#define MEMORY_WAIT_TIME 16 + +/* + * This selects whether TX packets are sent one by one to the SMC91x internal + * memory and throttled until transmission completes. This may prevent + * RX overruns a litle by keeping much of the memory free for RX packets + * but to the expense of reduced TX throughput and increased IRQ overhead. + * Note this is not a cure for a too slow data bus or too high IRQ latency. + */ +#define THROTTLE_TX_PKTS 0 + +/* + * The MII clock high/low times. 2x this number gives the MII clock period + * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!) + */ +#define MII_DELAY 1 + +/* store this information for the driver.. */ +struct smc_local { + /* + * If I have to wait until memory is available to send a + * packet, I will store the skbuff here, until I get the + * desired memory. Then, I'll send it out and free it. + */ + struct sk_buff *saved_skb; + + /* + * these are things that the kernel wants me to keep, so users + * can find out semi-useless statistics of how well the card is + * performing + */ + struct net_device_stats stats; + + /* version/revision of the SMC91x chip */ + int version; + + /* Contains the current active transmission mode */ + int tcr_cur_mode; + + /* Contains the current active receive mode */ + int rcr_cur_mode; + + /* Contains the current active receive/phy mode */ + int rpc_cur_mode; + int ctl_rfduplx; + int ctl_rspeed; + + u32 msg_enable; + u32 phy_type; + struct mii_if_info mii; + spinlock_t lock; + +#ifdef SMC_USE_PXA_DMA + /* DMA needs the physical address of the chip */ + u_long physaddr; +#endif +}; + +#if SMC_DEBUG > 0 +#define DBG(n, args...) \ + do { \ + if (SMC_DEBUG >= (n)) \ + printk(KERN_DEBUG args); \ + } while (0) + +#define PRINTK(args...) printk(args) +#else +#define DBG(n, args...) do { } while(0) +#define PRINTK(args...) printk(KERN_DEBUG args) +#endif + +#if SMC_DEBUG > 3 +static void PRINT_PKT(u_char *buf, int length) +{ + int i; + int remainder; + int lines; + + lines = length / 16; + remainder = length % 16; + + for (i = 0; i < lines ; i ++) { + int cur; + for (cur = 0; cur < 8; cur++) { + u_char a, b; + a = *buf++; + b = *buf++; + printk("%02x%02x ", a, b); + } + printk("\n"); + } + for (i = 0; i < remainder/2 ; i++) { + u_char a, b; + a = *buf++; + b = *buf++; + printk("%02x%02x ", a, b); + } + printk("\n"); +} +#else +#define PRINT_PKT(x...) do { } while(0) +#endif + + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) do { \ + unsigned long flags; \ + unsigned char mask; \ + spin_lock_irqsave(&lp->lock, flags); \ + mask = SMC_GET_INT_MASK(); \ + mask |= (x); \ + SMC_SET_INT_MASK(mask); \ + spin_unlock_irqrestore(&lp->lock, flags); \ +} while (0) + +/* this disables an interrupt from the interrupt mask register */ +#define SMC_DISABLE_INT(x) do { \ + unsigned long flags; \ + unsigned char mask; \ + spin_lock_irqsave(&lp->lock, flags); \ + mask = SMC_GET_INT_MASK(); \ + mask &= ~(x); \ + SMC_SET_INT_MASK(mask); \ + spin_unlock_irqrestore(&lp->lock, flags); \ +} while (0) + +/* + * Wait while MMU is busy. This is usually in the order of a few nanosecs + * if at all, but let's avoid deadlocking the system if the hardware + * decides to go south. + */ +#define SMC_WAIT_MMU_BUSY() do { \ + if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) { \ + unsigned long timeout = jiffies + 2; \ + while (SMC_GET_MMU_CMD() & MC_BUSY) { \ + if (time_after(jiffies, timeout)) { \ + printk("%s: timeout %s line %d\n", \ + dev->name, __FILE__, __LINE__); \ + break; \ + } \ + cpu_relax(); \ + } \ + } \ +} while (0) + + +/* + * this does a soft reset on the device + */ +static void smc_reset(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int ctl, cfg; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + /* + * This resets the registers mostly to defaults, but doesn't + * affect EEPROM. That seems unnecessary + */ + SMC_SELECT_BANK(0); + SMC_SET_RCR(RCR_SOFTRST); + + /* + * Setup the Configuration Register + * This is necessary because the CONFIG_REG is not affected + * by a soft reset + */ + SMC_SELECT_BANK(1); + + cfg = CONFIG_DEFAULT; + + /* + * Setup for fast accesses if requested. If the card/system + * can't handle it then there will be no recovery except for + * a hard reset or power cycle + */ + if (nowait) + cfg |= CONFIG_NO_WAIT; + + /* + * Release from possible power-down state + * Configuration register is not affected by Soft Reset + */ + cfg |= CONFIG_EPH_POWER_EN; + + SMC_SET_CONFIG(cfg); + + /* this should pause enough for the chip to be happy */ + /* + * elaborate? What does the chip _need_? --jgarzik + * + * This seems to be undocumented, but something the original + * driver(s) have always done. Suspect undocumented timing + * info/determined empirically. --rmk + */ + udelay(1); + + /* Disable transmit and receive functionality */ + SMC_SELECT_BANK(0); + SMC_SET_RCR(RCR_CLEAR); + SMC_SET_TCR(TCR_CLEAR); + + SMC_SELECT_BANK(1); + ctl = SMC_GET_CTL() | CTL_LE_ENABLE; + + /* + * Set the control register to automatically release successfully + * transmitted packets, to make the best use out of our limited + * memory + */ +#if ! THROTTLE_TX_PKTS + ctl |= CTL_AUTO_RELEASE; +#else + ctl &= ~CTL_AUTO_RELEASE; +#endif + SMC_SET_CTL(ctl); + + /* Disable all interrupts */ + SMC_SELECT_BANK(2); + SMC_SET_INT_MASK(0); + + /* Reset the MMU */ + SMC_SET_MMU_CMD(MC_RESET); + SMC_WAIT_MMU_BUSY(); +} + +/* + * Enable Interrupts, Receive, and Transmit + */ +static void smc_enable(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); + int mask; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + /* see the header file for options in TCR/RCR DEFAULT */ + SMC_SELECT_BANK(0); + SMC_SET_TCR(lp->tcr_cur_mode); + SMC_SET_RCR(lp->rcr_cur_mode); + + /* now, enable interrupts */ + mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; + if (lp->version >= (CHIP_91100 << 4)) + mask |= IM_MDINT; + SMC_SELECT_BANK(2); + SMC_SET_INT_MASK(mask); +} + +/* + * this puts the device in an inactive state + */ +static void smc_shutdown(unsigned long ioaddr) +{ + DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + + /* no more interrupts for me */ + SMC_SELECT_BANK(2); + SMC_SET_INT_MASK(0); + + /* and tell the card to stay away from that nasty outside world */ + SMC_SELECT_BANK(0); + SMC_SET_RCR(RCR_CLEAR); + SMC_SET_TCR(TCR_CLEAR); + +#ifdef POWER_DOWN + /* finally, shut the chip down */ + SMC_SELECT_BANK(1); + SMC_SET_CONFIG(SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN); +#endif +} + +/* + * This is the procedure to handle the receipt of a packet. + */ +static inline void smc_rcv(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned int packet_number, status, packet_len; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + packet_number = SMC_GET_RXFIFO(); + if (unlikely(packet_number & RXFIFO_REMPTY)) { + PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); + return; + } + + /* read from start of packet */ + SMC_SET_PTR(PTR_READ | PTR_RCV | PTR_AUTOINC); + + /* First two words are status and packet length */ + SMC_GET_PKT_HDR(status, packet_len); + packet_len &= 0x07ff; /* mask off top bits */ + DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", + dev->name, packet_number, status, + packet_len, packet_len); + + if (unlikely(status & RS_ERRORS)) { + lp->stats.rx_errors++; + if (status & RS_ALGNERR) + lp->stats.rx_frame_errors++; + if (status & (RS_TOOSHORT | RS_TOOLONG)) + lp->stats.rx_length_errors++; + if (status & RS_BADCRC) + lp->stats.rx_crc_errors++; + } else { + struct sk_buff *skb; + unsigned char *data; + unsigned int data_len; + + /* set multicast stats */ + if (status & RS_MULTICAST) + lp->stats.multicast++; + + /* + * Actual payload is packet_len - 4 (or 3 if odd byte). + * We want skb_reserve(2) and the final ctrl word + * (2 bytes, possibly containing the payload odd byte). + * Ence packet_len - 4 + 2 + 2. + */ + skb = dev_alloc_skb(packet_len); + if (unlikely(skb == NULL)) { + printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", + dev->name); + lp->stats.rx_dropped++; + goto done; + } + + /* Align IP header to 32 bits */ + skb_reserve(skb, 2); + + /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ + if (lp->version == 0x90) + status |= RS_ODDFRAME; + + /* + * If odd length: packet_len - 3, + * otherwise packet_len - 4. + */ + data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); + data = skb_put(skb, data_len); + SMC_PULL_DATA(data, packet_len - 2); + + PRINT_PKT(data, packet_len - 2); + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes += data_len; + } + +done: + SMC_WAIT_MMU_BUSY(); + SMC_SET_MMU_CMD(MC_RELEASE); +} + +/* + * This is called to actually send a packet to the chip. + * Returns non-zero when successful. + */ +static void smc_hardware_send_packet(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + struct sk_buff *skb = lp->saved_skb; + unsigned int packet_no, len; + unsigned char *buf; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + packet_no = SMC_GET_AR(); + if (unlikely(packet_no & AR_FAILED)) { + printk("%s: Memory allocation failed.\n", dev->name); + lp->saved_skb = NULL; + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + dev_kfree_skb_any(skb); + return; + } + + /* point to the beginning of the packet */ + SMC_SET_PN(packet_no); + SMC_SET_PTR(PTR_AUTOINC); + + buf = skb->data; + len = skb->len; + DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", + dev->name, packet_no, len, len, buf); + PRINT_PKT(buf, len); + + /* + * Send the packet length (+6 for status words, length, and ctl. + * The card will pad to 64 bytes with zeroes if packet is too small. + */ + SMC_PUT_PKT_HDR(0, len + 6); + + /* send the actual data */ + SMC_PUSH_DATA(buf, len & ~1); + + /* Send final ctl word with the last byte if there is one */ + SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG); + + /* and let the chipset deal with it */ + SMC_SET_MMU_CMD(MC_ENQUEUE); + SMC_ACK_INT(IM_TX_EMPTY_INT); + + dev->trans_start = jiffies; + dev_kfree_skb_any(skb); + lp->saved_skb = NULL; + lp->stats.tx_packets++; + lp->stats.tx_bytes += len; +} + +/* + * Since I am not sure if I will have enough room in the chip's ram + * to store the packet, I call this routine which either sends it + * now, or set the card to generates an interrupt when ready + * for the packet. + */ +static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned int numPages, poll_count, status, saved_bank; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + BUG_ON(lp->saved_skb != NULL); + lp->saved_skb = skb; + + /* + * The MMU wants the number of pages to be the number of 256 bytes + * 'pages', minus 1 (since a packet can't ever have 0 pages :)) + * + * The 91C111 ignores the size bits, but earlier models don't. + * + * Pkt size for allocating is data length +6 (for additional status + * words, length and ctl) + * + * If odd size then last byte is included in ctl word. + */ + numPages = ((skb->len & ~1) + (6 - 1)) >> 8; + if (unlikely(numPages > 7)) { + printk("%s: Far too big packet error.\n", dev->name); + lp->saved_skb = NULL; + lp->stats.tx_errors++; + lp->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + /* now, try to allocate the memory */ + saved_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(2); + SMC_SET_MMU_CMD(MC_ALLOC | numPages); + + /* + * Poll the chip for a short amount of time in case the + * allocation succeeds quickly. + */ + poll_count = MEMORY_WAIT_TIME; + do { + status = SMC_GET_INT(); + if (status & IM_ALLOC_INT) { + SMC_ACK_INT(IM_ALLOC_INT); + break; + } + } while (--poll_count); + + if (!poll_count) { + /* oh well, wait until the chip finds memory later */ + netif_stop_queue(dev); + DBG(2, "%s: TX memory allocation deferred.\n", dev->name); + SMC_ENABLE_INT(IM_ALLOC_INT); + } else { + /* + * Allocation succeeded: push packet to the chip's own memory + * immediately. + * + * If THROTTLE_TX_PKTS is selected that means we don't want + * more than a single TX packet taking up space in the chip's + * internal memory at all time, in which case we stop the + * queue right here until we're notified of TX completion. + * + * Otherwise we're quite happy to feed more TX packets right + * away for better TX throughput, in which case the queue is + * left active. + */ +#if THROTTLE_TX_PKTS + netif_stop_queue(dev); +#endif + smc_hardware_send_packet(dev); + SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); + } + + SMC_SELECT_BANK(saved_bank); + return 0; +} + +/* + * This handles a TX interrupt, which is only called when: + * - a TX error occurred, or + * - CTL_AUTO_RELEASE is not set and TX of a packet completed. + */ +static void smc_tx(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); + unsigned int saved_packet, packet_no, tx_status, pkt_len; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + /* If the TX FIFO is empty then nothing to do */ + packet_no = SMC_GET_TXFIFO(); + if (unlikely(packet_no & TXFIFO_TEMPTY)) { + PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); + return; + } + + /* select packet to read from */ + saved_packet = SMC_GET_PN(); + SMC_SET_PN(packet_no); + + /* read the first word (status word) from this packet */ + SMC_SET_PTR(PTR_AUTOINC | PTR_READ); + SMC_GET_PKT_HDR(tx_status, pkt_len); + DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n", + dev->name, tx_status, packet_no); + + if (!(tx_status & TS_SUCCESS)) + lp->stats.tx_errors++; + if (tx_status & TS_LOSTCAR) + lp->stats.tx_carrier_errors++; + + SMC_WAIT_MMU_BUSY(); + + if (tx_status & TS_LATCOL) { + PRINTK("%s: late collision occurred on last xmit\n", dev->name); + lp->stats.tx_window_errors++; + /* It's really cheap to requeue the pkt here */ + SMC_SET_MMU_CMD( MC_ENQUEUE ); + } else { + /* kill the packet */ + SMC_SET_MMU_CMD(MC_FREEPKT); + } + + /* Don't restore Packet Number Reg until busy bit is cleared */ + SMC_WAIT_MMU_BUSY(); + SMC_SET_PN(saved_packet); + + /* re-enable transmit */ + SMC_SELECT_BANK(0); + SMC_SET_TCR(lp->tcr_cur_mode); + SMC_SELECT_BANK(2); +} + + +/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ + +static void smc_mii_out(struct net_device *dev, unsigned int val, int bits) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int mii_reg, mask; + + mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO); + mii_reg |= MII_MDOE; + + for (mask = 1 << (bits - 1); mask; mask >>= 1) { + if (val & mask) + mii_reg |= MII_MDO; + else + mii_reg &= ~MII_MDO; + + SMC_SET_MII(mii_reg); + udelay(MII_DELAY); + SMC_SET_MII(mii_reg | MII_MCLK); + udelay(MII_DELAY); + } +} + +static unsigned int smc_mii_in(struct net_device *dev, int bits) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int mii_reg, mask, val; + + mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO); + SMC_SET_MII(mii_reg); + + for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) { + if (SMC_GET_MII() & MII_MDI) + val |= mask; + + SMC_SET_MII(mii_reg); + udelay(MII_DELAY); + SMC_SET_MII(mii_reg | MII_MCLK); + udelay(MII_DELAY); + } + + return val; +} + +/* + * Reads a register from the MII Management serial interface + */ +static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int phydata, old_bank; + + /* Save the current bank, and select bank 3 */ + old_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(3); + + /* Idle - 32 ones */ + smc_mii_out(dev, 0xffffffff, 32); + + /* Start code (01) + read (10) + phyaddr + phyreg */ + smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14); + + /* Turnaround (2bits) + phydata */ + phydata = smc_mii_in(dev, 18); + + /* Return to idle state */ + SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); + + /* And select original bank */ + SMC_SELECT_BANK(old_bank); + + DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", + __FUNCTION__, phyaddr, phyreg, phydata); + + return phydata; +} + +/* + * Writes a register to the MII Management serial interface + */ +static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, + int phydata) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int old_bank; + + /* Save the current bank, and select bank 3 */ + old_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(3); + + /* Idle - 32 ones */ + smc_mii_out(dev, 0xffffffff, 32); + + /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */ + smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32); + + /* Return to idle state */ + SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); + + /* And select original bank */ + SMC_SELECT_BANK(old_bank); + + DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", + __FUNCTION__, phyaddr, phyreg, phydata); +} + +/* + * Finds and reports the PHY address + */ +static void smc_detect_phy(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + int phyaddr; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + lp->phy_type = 0; + + /* + * Scan all 32 PHY addresses if necessary, starting at + * PHY#1 to PHY#31, and then PHY#0 last. + */ + for (phyaddr = 1; phyaddr < 33; ++phyaddr) { + unsigned int id1, id2; + + /* Read the PHY identifiers */ + id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1); + id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2); + + DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n", + dev->name, id1, id2); + + /* Make sure it is a valid identifier */ + if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 && + id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) { + /* Save the PHY's address */ + lp->mii.phy_id = phyaddr & 31; + lp->phy_type = id1 << 16 | id2; + break; + } + } +} + +/* + * Sets the PHY to a configuration as determined by the user + */ +static int smc_phy_fixed(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + int phyaddr = lp->mii.phy_id; + int bmcr, cfg1; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + /* Enter Link Disable state */ + cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG); + cfg1 |= PHY_CFG1_LNKDIS; + smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1); + + /* + * Set our fixed capabilities + * Disable auto-negotiation + */ + bmcr = 0; + + if (lp->ctl_rfduplx) + bmcr |= BMCR_FULLDPLX; + + if (lp->ctl_rspeed == 100) + bmcr |= BMCR_SPEED100; + + /* Write our capabilities to the phy control register */ + smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); + + /* Re-Configure the Receive/Phy Control register */ + SMC_SET_RPC(lp->rpc_cur_mode); + + return 1; +} + +/* + * smc_phy_reset - reset the phy + * @dev: net device + * @phy: phy address + * + * Issue a software reset for the specified PHY and + * wait up to 100ms for the reset to complete. We should + * not access the PHY for 50ms after issuing the reset. + * + * The time to wait appears to be dependent on the PHY. + * + * Must be called with lp->lock locked. + */ +static int smc_phy_reset(struct net_device *dev, int phy) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned int bmcr; + int timeout; + + smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET); + + for (timeout = 2; timeout; timeout--) { + spin_unlock_irq(&lp->lock); + msleep(50); + spin_lock_irq(&lp->lock); + + bmcr = smc_phy_read(dev, phy, MII_BMCR); + if (!(bmcr & BMCR_RESET)) + break; + } + + return bmcr & BMCR_RESET; +} + +/* + * smc_phy_powerdown - powerdown phy + * @dev: net device + * @phy: phy address + * + * Power down the specified PHY + */ +static void smc_phy_powerdown(struct net_device *dev, int phy) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned int bmcr; + + spin_lock_irq(&lp->lock); + bmcr = smc_phy_read(dev, phy, MII_BMCR); + smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); + spin_unlock_irq(&lp->lock); +} + +/* + * smc_phy_check_media - check the media status and adjust TCR + * @dev: net device + * @init: set true for initialisation + * + * Select duplex mode depending on negotiation state. This + * also updates our carrier state. + */ +static void smc_phy_check_media(struct net_device *dev, int init) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { + unsigned int old_bank; + + /* duplex state has changed */ + if (lp->mii.full_duplex) { + lp->tcr_cur_mode |= TCR_SWFDUP; + } else { + lp->tcr_cur_mode &= ~TCR_SWFDUP; + } + + old_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(0); + SMC_SET_TCR(lp->tcr_cur_mode); + SMC_SELECT_BANK(old_bank); + } +} + +/* + * Configures the specified PHY through the MII management interface + * using Autonegotiation. + * Calls smc_phy_fixed() if the user has requested a certain config. + * If RPC ANEG bit is set, the media selection is dependent purely on + * the selection by the MII (either in the MII BMCR reg or the result + * of autonegotiation.) If the RPC ANEG bit is cleared, the selection + * is controlled by the RPC SPEED and RPC DPLX bits. + */ +static void smc_phy_configure(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + int phyaddr = lp->mii.phy_id; + int my_phy_caps; /* My PHY capabilities */ + int my_ad_caps; /* My Advertised capabilities */ + int status; + + DBG(3, "%s:smc_program_phy()\n", dev->name); + + spin_lock_irq(&lp->lock); + + /* + * We should not be called if phy_type is zero. + */ + if (lp->phy_type == 0) + goto smc_phy_configure_exit; + + if (smc_phy_reset(dev, phyaddr)) { + printk("%s: PHY reset timed out\n", dev->name); + goto smc_phy_configure_exit; + } + + /* + * Enable PHY Interrupts (for register 18) + * Interrupts listed here are disabled + */ + smc_phy_write(dev, phyaddr, PHY_MASK_REG, + PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | + PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | + PHY_INT_SPDDET | PHY_INT_DPLXDET); + + /* Configure the Receive/Phy Control register */ + SMC_SELECT_BANK(0); + SMC_SET_RPC(lp->rpc_cur_mode); + + /* If the user requested no auto neg, then go set his request */ + if (lp->mii.force_media) { + smc_phy_fixed(dev); + goto smc_phy_configure_exit; + } + + /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ + my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR); + + if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { + printk(KERN_INFO "Auto negotiation NOT supported\n"); + smc_phy_fixed(dev); + goto smc_phy_configure_exit; + } + + my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */ + + if (my_phy_caps & BMSR_100BASE4) + my_ad_caps |= ADVERTISE_100BASE4; + if (my_phy_caps & BMSR_100FULL) + my_ad_caps |= ADVERTISE_100FULL; + if (my_phy_caps & BMSR_100HALF) + my_ad_caps |= ADVERTISE_100HALF; + if (my_phy_caps & BMSR_10FULL) + my_ad_caps |= ADVERTISE_10FULL; + if (my_phy_caps & BMSR_10HALF) + my_ad_caps |= ADVERTISE_10HALF; + + /* Disable capabilities not selected by our user */ + if (lp->ctl_rspeed != 100) + my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); + + if (!lp->ctl_rfduplx) + my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); + + /* Update our Auto-Neg Advertisement Register */ + smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps); + lp->mii.advertising = my_ad_caps; + + /* + * Read the register back. Without this, it appears that when + * auto-negotiation is restarted, sometimes it isn't ready and + * the link does not come up. + */ + status = smc_phy_read(dev, phyaddr, MII_ADVERTISE); + + DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps); + DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps); + + /* Restart auto-negotiation process in order to advertise my caps */ + smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + + smc_phy_check_media(dev, 1); + +smc_phy_configure_exit: + spin_unlock_irq(&lp->lock); +} + +/* + * smc_phy_interrupt + * + * Purpose: Handle interrupts relating to PHY register 18. This is + * called from the "hard" interrupt handler under our private spinlock. + */ +static void smc_phy_interrupt(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + int phyaddr = lp->mii.phy_id; + int phy18; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + if (lp->phy_type == 0) + return; + + for(;;) { + smc_phy_check_media(dev, 0); + + /* Read PHY Register 18, Status Output */ + phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG); + if ((phy18 & PHY_INT_INT) == 0) + break; + } +} + +/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ + +static void smc_10bt_check_media(struct net_device *dev, int init) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned int old_carrier, new_carrier, old_bank; + + old_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(0); + old_carrier = netif_carrier_ok(dev) ? 1 : 0; + new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0; + + if (init || (old_carrier != new_carrier)) { + if (!new_carrier) { + netif_carrier_off(dev); + } else { + netif_carrier_on(dev); + } + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: link %s\n", dev->name, + new_carrier ? "up" : "down"); + } + SMC_SELECT_BANK(old_bank); +} + +static void smc_eph_interrupt(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + unsigned int old_bank, ctl; + + smc_10bt_check_media(dev, 0); + + old_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(1); + + ctl = SMC_GET_CTL(); + SMC_SET_CTL(ctl & ~CTL_LE_ENABLE); + SMC_SET_CTL(ctl); + + SMC_SELECT_BANK(old_bank); +} + +/* + * This is the main routine of the driver, to handle the device when + * it needs some attention. + */ +static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + unsigned long ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); + int status, mask, timeout, card_stats; + int saved_bank, saved_pointer; + + DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + + saved_bank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK(2); + saved_pointer = SMC_GET_PTR(); + mask = SMC_GET_INT_MASK(); + SMC_SET_INT_MASK(0); + + /* set a timeout value, so I don't stay here forever */ + timeout = 8; + + do { + status = SMC_GET_INT(); + + DBG(2, "%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", + dev->name, status, mask, + ({ int meminfo; SMC_SELECT_BANK(0); + meminfo = SMC_GET_MIR(); + SMC_SELECT_BANK(2); meminfo; }), + SMC_GET_FIFO()); + + status &= mask; + if (!status) + break; + + spin_lock(&lp->lock); + + if (status & IM_RCV_INT) { + DBG(3, "%s: RX irq\n", dev->name); + smc_rcv(dev); + } else if (status & IM_TX_INT) { + DBG(3, "%s: TX int\n", dev->name); + smc_tx(dev); + SMC_ACK_INT(IM_TX_INT); +#if THROTTLE_TX_PKTS + netif_wake_queue(dev); +#endif + } else if (status & IM_ALLOC_INT) { + DBG(3, "%s: Allocation irq\n", dev->name); + smc_hardware_send_packet(dev); + mask |= (IM_TX_INT | IM_TX_EMPTY_INT); + mask &= ~IM_ALLOC_INT; +#if ! THROTTLE_TX_PKTS + netif_wake_queue(dev); +#endif + } else if (status & IM_TX_EMPTY_INT) { + DBG(3, "%s: TX empty\n", dev->name); + mask &= ~IM_TX_EMPTY_INT; + + /* update stats */ + SMC_SELECT_BANK(0); + card_stats = SMC_GET_COUNTER(); + SMC_SELECT_BANK(2); + + /* single collisions */ + lp->stats.collisions += card_stats & 0xF; + card_stats >>= 4; + + /* multiple collisions */ + lp->stats.collisions += card_stats & 0xF; + } else if (status & IM_RX_OVRN_INT) { + DBG(1, "%s: RX overrun\n", dev->name); + SMC_ACK_INT(IM_RX_OVRN_INT); + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + } else if (status & IM_EPH_INT) { + smc_eph_interrupt(dev); + } else if (status & IM_MDINT) { + SMC_ACK_INT(IM_MDINT); + smc_phy_interrupt(dev); + } else if (status & IM_ERCV_INT) { + SMC_ACK_INT(IM_ERCV_INT); + PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); + } + + spin_unlock(&lp->lock); + } while (--timeout); + + /* restore register states */ + SMC_SET_INT_MASK(mask); + SMC_SET_PTR(saved_pointer); + SMC_SELECT_BANK(saved_bank); + + DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); + + /* + * We return IRQ_HANDLED unconditionally here even if there was + * nothing to do. There is a possibility that a packet might + * get enqueued into the chip right after TX_EMPTY_INT is raised + * but just before the CPU acknowledges the IRQ. + * Better take an unneeded IRQ in some occasions than complexifying + * the code for all cases. + */ + return IRQ_HANDLED; +} + +/* Our watchdog timed out. Called by the networking layer */ +static void smc_timeout(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + smc_reset(dev); + smc_enable(dev); + +#if 0 + /* + * Reconfiguring the PHY doesn't seem like a bad idea here, but + * it introduced a problem. Now that this is a timeout routine, + * we are getting called from within an interrupt context. + * smc_phy_configure() calls msleep() which calls + * schedule_timeout() which calls schedule(). When schedule() + * is called from an interrupt context, it prints out + * "Scheduling in interrupt" and then calls BUG(). This is + * obviously not desirable. This was worked around by removing + * the call to smc_phy_configure() here because it didn't seem + * absolutely necessary. Ultimately, if msleep() is + * supposed to be usable from an interrupt context (which it + * looks like it thinks it should handle), it should be fixed. + */ + if (lp->phy_type != 0) + smc_phy_configure(dev); +#endif + + /* clear anything saved */ + if (lp->saved_skb != NULL) { + dev_kfree_skb (lp->saved_skb); + lp->saved_skb = NULL; + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + } + /* We can accept TX packets again */ + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +/* + * This sets the internal hardware table to filter out unwanted multicast + * packets before they take up memory. + * + * The SMC chip uses a hash table where the high 6 bits of the CRC of + * address are the offset into the table. If that bit is 1, then the + * multicast packet is accepted. Otherwise, it's dropped silently. + * + * To use the 6 bits as an offset into the table, the high 3 bits are the + * number of the 8 bit register, while the low 3 bits are the bit within + * that register. + * + * This routine is based very heavily on the one provided by Peter Cammaert. + */ +static void +smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs) +{ + int i; + unsigned char multicast_table[8]; + struct dev_mc_list *cur_addr; + + /* table for flipping the order of 3 bits */ + static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + + /* start with a table of all zeros: reject all */ + memset(multicast_table, 0, sizeof(multicast_table)); + + cur_addr = addrs; + for (i = 0; i < count; i++, cur_addr = cur_addr->next) { + int position; + + /* do we have a pointer here? */ + if (!cur_addr) + break; + /* make sure this is a multicast address - shouldn't this + be a given if we have it here ? */ + if (!(*cur_addr->dmi_addr & 1)) + continue; + + /* only use the low order bits */ + position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f; + + /* do some messy swapping to put the bit in the right spot */ + multicast_table[invert3[position&7]] |= + (1<>3)&7]); + + } + /* now, the table can be loaded into the chipset */ + SMC_SELECT_BANK(3); + SMC_SET_MCAST(multicast_table); +} + +/* + * This routine will, depending on the values passed to it, + * either make it accept multicast packets, go into + * promiscuous mode (for TCPDUMP and cousins) or accept + * a select set of multicast packets + */ +static void smc_set_multicast_list(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + SMC_SELECT_BANK(0); + if (dev->flags & IFF_PROMISC) { + DBG(2, "%s: RCR_PRMS\n", dev->name); + lp->rcr_cur_mode |= RCR_PRMS; + SMC_SET_RCR(lp->rcr_cur_mode); + } + +/* BUG? I never disable promiscuous mode if multicasting was turned on. + Now, I turn off promiscuous mode, but I don't do anything to multicasting + when promiscuous mode is turned on. +*/ + + /* + * Here, I am setting this to accept all multicast packets. + * I don't need to zero the multicast table, because the flag is + * checked before the table is + */ + else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { + lp->rcr_cur_mode |= RCR_ALMUL; + SMC_SET_RCR(lp->rcr_cur_mode); + DBG(2, "%s: RCR_ALMUL\n", dev->name); + } + + /* + * We just get all multicast packets even if we only want them + * from one source. This will be changed at some future point. + */ + else if (dev->mc_count) { + /* support hardware multicasting */ + + /* be sure I get rid of flags I might have set */ + lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); + SMC_SET_RCR(lp->rcr_cur_mode); + /* + * NOTE: this has to set the bank, so make sure it is the + * last thing called. The bank is set to zero at the top + */ + smc_setmulticast(ioaddr, dev->mc_count, dev->mc_list); + } else { + DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); + lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); + SMC_SET_RCR(lp->rcr_cur_mode); + + /* + * since I'm disabling all multicast entirely, I need to + * clear the multicast list + */ + SMC_SELECT_BANK(3); + SMC_CLEAR_MCAST(); + } +} + + +/* + * Open and Initialize the board + * + * Set up everything, reset the card, etc.. + */ +static int +smc_open(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + /* + * Check that the address is valid. If its not, refuse + * to bring the device up. The user must specify an + * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx + */ + if (!is_valid_ether_addr(dev->dev_addr)) { + DBG(2, (KERN_DEBUG "smc_open: no valid ethernet hw addr\n")); + return -EINVAL; + } + + /* clear out all the junk that was put here before... */ + lp->saved_skb = NULL; + + /* Setup the default Register Modes */ + lp->tcr_cur_mode = TCR_DEFAULT; + lp->rcr_cur_mode = RCR_DEFAULT; + lp->rpc_cur_mode = RPC_DEFAULT; + + /* + * If we are not using a MII interface, we need to + * monitor our own carrier signal to detect faults. + */ + if (lp->phy_type == 0) + lp->tcr_cur_mode |= TCR_MON_CSN; + + /* reset the hardware */ + smc_reset(dev); + smc_enable(dev); + + SMC_SELECT_BANK(1); + SMC_SET_MAC_ADDR(dev->dev_addr); + + /* Configure the PHY */ + if (lp->phy_type != 0) + smc_phy_configure(dev); + else { + spin_lock_irq(&lp->lock); + smc_10bt_check_media(dev, 1); + spin_unlock_irq(&lp->lock); + } + + /* + * make sure to initialize the link state with netif_carrier_off() + * somewhere, too --jgarzik + * + * smc_phy_configure() and smc_10bt_check_media() does that. --rmk + */ + netif_start_queue(dev); + return 0; +} + +/* + * smc_close + * + * this makes the board clean up everything that it can + * and not talk to the outside world. Caused by + * an 'ifconfig ethX down' + */ +static int smc_close(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + netif_stop_queue(dev); + netif_carrier_off(dev); + + /* clear everything */ + smc_shutdown(dev->base_addr); + + if (lp->phy_type != 0) + smc_phy_powerdown(dev, lp->mii.phy_id); + + return 0; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats *smc_query_statistics(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + + DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + + return &lp->stats; +} + +/* + * Ethtool support + */ +static int +smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smc_local *lp = netdev_priv(dev); + int ret; + + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; + + if (lp->phy_type != 0) { + spin_lock_irq(&lp->lock); + ret = mii_ethtool_gset(&lp->mii, cmd); + spin_unlock_irq(&lp->lock); + } else { + cmd->supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_TP | SUPPORTED_AUI; + + if (lp->ctl_rspeed == 10) + cmd->speed = SPEED_10; + else if (lp->ctl_rspeed == 100) + cmd->speed = SPEED_100; + + cmd->autoneg = AUTONEG_DISABLE; + cmd->transceiver = XCVR_INTERNAL; + cmd->port = 0; + cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF; + + ret = 0; + } + + return ret; +} + +static int +smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smc_local *lp = netdev_priv(dev); + int ret; + + if (lp->phy_type != 0) { + spin_lock_irq(&lp->lock); + ret = mii_ethtool_sset(&lp->mii, cmd); + spin_unlock_irq(&lp->lock); + } else { + if (cmd->autoneg != AUTONEG_DISABLE || + cmd->speed != SPEED_10 || + (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) || + (cmd->port != PORT_TP && cmd->port != PORT_AUI)) + return -EINVAL; + +// lp->port = cmd->port; + lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL; + +// if (netif_running(dev)) +// smc_set_port(dev); + + ret = 0; + } + + return ret; +} + +static void +smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strncpy(info->driver, CARDNAME, sizeof(info->driver)); + strncpy(info->version, version, sizeof(info->version)); + strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); +} + +static int smc_ethtool_nwayreset(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + int ret = -EINVAL; + + if (lp->phy_type != 0) { + spin_lock_irq(&lp->lock); + ret = mii_nway_restart(&lp->mii); + spin_unlock_irq(&lp->lock); + } + + return ret; +} + +static u32 smc_ethtool_getmsglevel(struct net_device *dev) +{ + struct smc_local *lp = netdev_priv(dev); + return lp->msg_enable; +} + +static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level) +{ + struct smc_local *lp = netdev_priv(dev); + lp->msg_enable = level; +} + +static struct ethtool_ops smc_ethtool_ops = { + .get_settings = smc_ethtool_getsettings, + .set_settings = smc_ethtool_setsettings, + .get_drvinfo = smc_ethtool_getdrvinfo, + + .get_msglevel = smc_ethtool_getmsglevel, + .set_msglevel = smc_ethtool_setmsglevel, + .nway_reset = smc_ethtool_nwayreset, + .get_link = ethtool_op_get_link, +// .get_eeprom = smc_ethtool_geteeprom, +// .set_eeprom = smc_ethtool_seteeprom, +}; + +/* + * smc_findirq + * + * This routine has a simple purpose -- make the SMC chip generate an + * interrupt, so an auto-detect routine can detect it, and find the IRQ, + */ +/* + * does this still work? + * + * I just deleted auto_irq.c, since it was never built... + * --jgarzik + */ +static int __init smc_findirq(unsigned long ioaddr) +{ + int timeout = 20; + unsigned long cookie; + + DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + + cookie = probe_irq_on(); + + /* + * What I try to do here is trigger an ALLOC_INT. This is done + * by allocating a small chunk of memory, which will give an interrupt + * when done. + */ + /* enable ALLOCation interrupts ONLY */ + SMC_SELECT_BANK(2); + SMC_SET_INT_MASK(IM_ALLOC_INT); + + /* + * Allocate 512 bytes of memory. Note that the chip was just + * reset so all the memory is available + */ + SMC_SET_MMU_CMD(MC_ALLOC | 1); + + /* + * Wait until positive that the interrupt has been generated + */ + do { + int int_status; + udelay(10); + int_status = SMC_GET_INT(); + if (int_status & IM_ALLOC_INT) + break; /* got the interrupt */ + } while (--timeout); + + /* + * there is really nothing that I can do here if timeout fails, + * as autoirq_report will return a 0 anyway, which is what I + * want in this case. Plus, the clean up is needed in both + * cases. + */ + + /* and disable all interrupts again */ + SMC_SET_INT_MASK(0); + + /* and return what I found */ + return probe_irq_off(cookie); +} + +/* + * Function: smc_probe(unsigned long ioaddr) + * + * Purpose: + * Tests to see if a given ioaddr points to an SMC91x chip. + * Returns a 0 on success + * + * Algorithm: + * (1) see if the high byte of BANK_SELECT is 0x33 + * (2) compare the ioaddr with the base register's address + * (3) see if I recognize the chip ID in the appropriate register + * + * Here I do typical initialization tasks. + * + * o Initialize the structure if needed + * o print out my vanity message if not done so already + * o print out what type of hardware is detected + * o print out the ethernet address + * o find the IRQ + * o set up my private data + * o configure the dev structure with my subroutines + * o actually GRAB the irq. + * o GRAB the region + */ +static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) +{ + struct smc_local *lp = netdev_priv(dev); + static int version_printed = 0; + int i, retval; + unsigned int val, revision_register; + const char *version_string; + + DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); + + /* First, see if the high byte is 0x33 */ + val = SMC_CURRENT_BANK(); + DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val); + if ((val & 0xFF00) != 0x3300) { + if ((val & 0xFF) == 0x33) { + printk(KERN_WARNING + "%s: Detected possible byte-swapped interface" + " at IOADDR 0x%lx\n", CARDNAME, ioaddr); + } + retval = -ENODEV; + goto err_out; + } + + /* + * The above MIGHT indicate a device, but I need to write to + * further test this. + */ + SMC_SELECT_BANK(0); + val = SMC_CURRENT_BANK(); + if ((val & 0xFF00) != 0x3300) { + retval = -ENODEV; + goto err_out; + } + + /* + * well, we've already written once, so hopefully another + * time won't hurt. This time, I need to switch the bank + * register to bank 1, so I can access the base address + * register + */ + SMC_SELECT_BANK(1); + val = SMC_GET_BASE(); + val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; + if ((ioaddr & ((PAGE_SIZE-1)<> 4) & 0xF]; + if (!version_string || (revision_register & 0xff00) != 0x3300) { + /* I don't recognize this chip, so... */ + printk("%s: IO 0x%lx: Unrecognized revision register 0x%04x" + ", Contact author.\n", CARDNAME, + ioaddr, revision_register); + + retval = -ENODEV; + goto err_out; + } + + /* At this point I'll assume that the chip is an SMC91x. */ + if (version_printed++ == 0) + printk("%s", version); + + /* fill in some of the fields */ + dev->base_addr = ioaddr; + lp->version = revision_register & 0xff; + + /* Get the MAC address */ + SMC_SELECT_BANK(1); + SMC_GET_MAC_ADDR(dev->dev_addr); + + /* now, reset the chip, and put it into a known state */ + smc_reset(dev); + + /* + * If dev->irq is 0, then the device has to be banged on to see + * what the IRQ is. + * + * This banging doesn't always detect the IRQ, for unknown reasons. + * a workaround is to reset the chip and try again. + * + * Interestingly, the DOS packet driver *SETS* the IRQ on the card to + * be what is requested on the command line. I don't do that, mostly + * because the card that I have uses a non-standard method of accessing + * the IRQs, and because this _should_ work in most configurations. + * + * Specifying an IRQ is done with the assumption that the user knows + * what (s)he is doing. No checking is done!!!! + */ + if (dev->irq < 1) { + int trials; + + trials = 3; + while (trials--) { + dev->irq = smc_findirq(ioaddr); + if (dev->irq) + break; + /* kick the card and try again */ + smc_reset(dev); + } + } + if (dev->irq == 0) { + printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", + dev->name); + retval = -ENODEV; + goto err_out; + } + dev->irq = irq_canonicalize(dev->irq); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + dev->open = smc_open; + dev->stop = smc_close; + dev->hard_start_xmit = smc_hard_start_xmit; + dev->tx_timeout = smc_timeout; + dev->watchdog_timeo = msecs_to_jiffies(watchdog); + dev->get_stats = smc_query_statistics; + dev->set_multicast_list = smc_set_multicast_list; + dev->ethtool_ops = &smc_ethtool_ops; + + spin_lock_init(&lp->lock); + lp->mii.phy_id_mask = 0x1f; + lp->mii.reg_num_mask = 0x1f; + lp->mii.force_media = 0; + lp->mii.full_duplex = 0; + lp->mii.dev = dev; + lp->mii.mdio_read = smc_phy_read; + lp->mii.mdio_write = smc_phy_write; + + /* + * Locate the phy, if any. + */ + if (lp->version >= (CHIP_91100 << 4)) + smc_detect_phy(dev); + + /* Set default parameters */ + lp->msg_enable = NETIF_MSG_LINK; + lp->ctl_rfduplx = 0; + lp->ctl_rspeed = 10; + + if (lp->version >= (CHIP_91100 << 4)) { + lp->ctl_rfduplx = 1; + lp->ctl_rspeed = 100; + } + + /* Grab the IRQ */ + retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); + if (retval) + goto err_out; + + set_irq_type(dev->irq, IRQT_RISING); +#ifdef SMC_USE_PXA_DMA + { + int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, + smc_pxa_dma_irq, NULL); + if (dma >= 0) + dev->dma = dma; + } +#endif + + retval = register_netdev(dev); + if (retval == 0) { + /* now, print out the card info, in a short format.. */ + printk("%s: %s (rev %d) at %#lx IRQ %d", + dev->name, version_string, revision_register & 0x0f, + dev->base_addr, dev->irq); + + if (dev->dma != (unsigned char)-1) + printk(" DMA %d", dev->dma); + + printk("%s%s\n", nowait ? " [nowait]" : "", + THROTTLE_TX_PKTS ? " [throttle_tx]" : ""); + + if (!is_valid_ether_addr(dev->dev_addr)) { + printk("%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", dev->name); + } else { + /* Print the Ethernet address */ + printk("%s: Ethernet addr: ", dev->name); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x\n", dev->dev_addr[5]); + } + + if (lp->phy_type == 0) { + PRINTK("%s: No PHY found\n", dev->name); + } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) { + PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name); + } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) { + PRINTK("%s: PHY LAN83C180\n", dev->name); + } + } + +err_out: +#ifdef SMC_USE_PXA_DMA + if (retval && dev->dma != (unsigned char)-1) + pxa_free_dma(dev->dma); +#endif + return retval; +} + +static int smc_enable_device(unsigned long attrib_phys) +{ + unsigned long flags; + unsigned char ecor, ecsr; + void *addr; + + /* + * Map the attribute space. This is overkill, but clean. + */ + addr = ioremap(attrib_phys, ATTRIB_SIZE); + if (!addr) + return -ENOMEM; + + /* + * Reset the device. We must disable IRQs around this + * since a reset causes the IRQ line become active. + */ + local_irq_save(flags); + ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET; + writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT)); + readb(addr + (ECOR << SMC_IO_SHIFT)); + + /* + * Wait 100us for the chip to reset. + */ + udelay(100); + + /* + * The device will ignore all writes to the enable bit while + * reset is asserted, even if the reset bit is cleared in the + * same write. Must clear reset first, then enable the device. + */ + writeb(ecor, addr + (ECOR << SMC_IO_SHIFT)); + writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT)); + + /* + * Set the appropriate byte/word mode. + */ + ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; +#ifndef SMC_CAN_USE_16BIT + ecsr |= ECSR_IOIS8; +#endif + writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); + local_irq_restore(flags); + + iounmap(addr); + + /* + * Wait for the chip to wake up. We could poll the control + * register in the main register space, but that isn't mapped + * yet. We know this is going to take 750us. + */ + msleep(1); + + return 0; +} + +/* + * smc_init(void) + * Input parameters: + * dev->base_addr == 0, try to find all possible locations + * dev->base_addr > 0x1ff, this is the address to check + * dev->base_addr == , return failure code + * + * Output: + * 0 --> there is a device + * anything else, error + */ +static int smc_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev; + struct resource *res, *ext = NULL; + unsigned int *addr; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto out; + } + + /* + * Request the regions. + */ + if (!request_mem_region(res->start, SMC_IO_EXTENT, "smc91x")) { + ret = -EBUSY; + goto out; + } + + ndev = alloc_etherdev(sizeof(struct smc_local)); + if (!ndev) { + printk("%s: could not allocate device.\n", CARDNAME); + ret = -ENOMEM; + goto release_1; + } + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, dev); + + ndev->dma = (unsigned char)-1; + ndev->irq = platform_get_irq(pdev, 0); + + ext = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (ext) { + if (!request_mem_region(ext->start, ATTRIB_SIZE, ndev->name)) { + ret = -EBUSY; + goto release_1; + } + +#if defined(CONFIG_SA1100_ASSABET) + NCR_0 |= NCR_ENET_OSC_EN; +#endif + + ret = smc_enable_device(ext->start); + if (ret) + goto release_both; + } + + addr = ioremap(res->start, SMC_IO_EXTENT); + if (!addr) { + ret = -ENOMEM; + goto release_both; + } + + dev_set_drvdata(dev, ndev); + ret = smc_probe(ndev, (unsigned long)addr); + if (ret != 0) { + dev_set_drvdata(dev, NULL); + iounmap(addr); + release_both: + if (ext) + release_mem_region(ext->start, ATTRIB_SIZE); + free_netdev(ndev); + release_1: + release_mem_region(res->start, SMC_IO_EXTENT); + out: + printk("%s: not found (%d).\n", CARDNAME, ret); + } +#ifdef SMC_USE_PXA_DMA + else { + struct smc_local *lp = netdev_priv(ndev); + lp->physaddr = res->start; + } +#endif + + return ret; +} + +static int smc_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct resource *res; + + dev_set_drvdata(dev, NULL); + + unregister_netdev(ndev); + + free_irq(ndev->irq, ndev); + +#ifdef SMC_USE_PXA_DMA + if (ndev->dma != (unsigned char)-1) + pxa_free_dma(ndev->dma); +#endif + iounmap((void *)ndev->base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) + release_mem_region(res->start, ATTRIB_SIZE); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, SMC_IO_EXTENT); + + free_netdev(ndev); + + return 0; +} + +static int smc_drv_suspend(struct device *dev, u32 state, u32 level) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + if (ndev && level == SUSPEND_DISABLE) { + if (netif_running(ndev)) { + netif_device_detach(ndev); + smc_shutdown(ndev->base_addr); + } + } + return 0; +} + +static int smc_drv_resume(struct device *dev, u32 level) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = dev_get_drvdata(dev); + + if (ndev && level == RESUME_ENABLE) { + struct smc_local *lp = netdev_priv(ndev); + unsigned long ioaddr = ndev->base_addr; + + if (pdev->num_resources == 3) + smc_enable_device(pdev->resource[2].start); + if (netif_running(ndev)) { + smc_reset(ndev); + smc_enable(ndev); + SMC_SELECT_BANK(1); + SMC_SET_MAC_ADDR(ndev->dev_addr); + if (lp->phy_type != 0) + smc_phy_configure(ndev); + netif_device_attach(ndev); + } + } + return 0; +} + +static struct device_driver smc_driver = { + .name = CARDNAME, + .bus = &platform_bus_type, + .probe = smc_drv_probe, + .remove = smc_drv_remove, + .suspend = smc_drv_suspend, + .resume = smc_drv_resume, +}; + +static int __init smc_init(void) +{ +#ifdef MODULE + if (io == -1) + printk(KERN_WARNING + "%s: You shouldn't use auto-probing with insmod!\n", + CARDNAME); +#endif + + return driver_register(&smc_driver); +} + +static void __exit smc_cleanup(void) +{ + driver_unregister(&smc_driver); +} + +module_init(smc_init); +module_exit(smc_cleanup); diff --git a/drivers/net/arm/smc91x.h b/drivers/net/arm/smc91x.h new file mode 100644 index 000000000..5212e3763 --- /dev/null +++ b/drivers/net/arm/smc91x.h @@ -0,0 +1,829 @@ +/*------------------------------------------------------------------------ + . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device. + . + . Copyright (C) 1996 by Erik Stahlman + . Copyright (C) 2001 Standard Microsystems Corporation + . Developed by Simple Network Magic Corporation + . Copyright (C) 2003 Monta Vista Software, Inc. + . Unified SMC91x driver by Nicolas Pitre + . + . This program is free software; you can redistribute it and/or modify + . it under the terms of the GNU General Public License as published by + . the Free Software Foundation; either version 2 of the License, or + . (at your option) any later version. + . + . This program is distributed in the hope that it will be useful, + . but WITHOUT ANY WARRANTY; without even the implied warranty of + . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + . GNU General Public License for more details. + . + . You should have received a copy of the GNU General Public License + . along with this program; if not, write to the Free Software + . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + . + . Information contained in this file was obtained from the LAN91C111 + . manual from SMC. To get a copy, if you really want one, you can find + . information under www.smsc.com. + . + . Authors + . Erik Stahlman + . Daris A Nevil + . Nicolas Pitre + . + ---------------------------------------------------------------------------*/ +#ifndef _SMC91X_H_ +#define _SMC91X_H_ + + +/* + * Define your architecture specific bus configuration parameters here. + */ + +#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ + defined(CONFIG_SA1100_PFS168) || \ + defined(CONFIG_SA1100_FLEXANET) || \ + defined(CONFIG_SA1100_GRAPHICSMASTER) || \ + defined(CONFIG_ARCH_LUBBOCK) + +/* We can only do 16-bit reads and writes in the static memory space. */ +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_NOWAIT 1 + +/* The first two address lines aren't connected... */ +#define SMC_IO_SHIFT 2 + +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) + +#elif defined(CONFIG_SA1100_ASSABET) + +#include + +/* We can only do 8-bit reads and writes in the static memory space. */ +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 0 +#define SMC_CAN_USE_32BIT 0 +#define SMC_NOWAIT 1 + +/* The first two address lines aren't connected... */ +#define SMC_IO_SHIFT 2 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l)) +#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l)) + +#elif defined(CONFIG_ARCH_INNOKOM) || \ + defined(CONFIG_MACH_MAINSTONE) || \ + defined(CONFIG_ARCH_PXA_IDP) || \ + defined(CONFIG_ARCH_RAMSES) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_IO_SHIFT 0 +#define SMC_NOWAIT 1 +#define SMC_USE_PXA_DMA 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +/* We actually can't write halfwords properly if not word aligned */ +static inline void +SMC_outw(u16 val, unsigned long ioaddr, int reg) +{ + if (reg & 2) { + unsigned int v = val << 16; + v |= readl(ioaddr + (reg & ~2)) & 0xffff; + writel(v, ioaddr + (reg & ~2)); + } else { + writew(val, ioaddr + reg); + } +} + +#elif defined(CONFIG_ISA) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 + +#define SMC_inb(a, r) inb((a) + (r)) +#define SMC_inw(a, r) inw((a) + (r)) +#define SMC_outb(v, a, r) outb(v, (a) + (r)) +#define SMC_outw(v, a, r) outw(v, (a) + (r)) +#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) + +#else + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define RPC_LSA_DEFAULT RPC_LED_100_10 +#define RPC_LSB_DEFAULT RPC_LED_TX_RX + +#endif + + +#ifdef SMC_USE_PXA_DMA +/* + * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is + * always happening in irq context so no need to worry about races. TX is + * different and probably not worth it for that reason, and not as critical + * as RX which can overrun memory and lose packets. + */ +#include +#include + +#ifdef SMC_insl +#undef SMC_insl +#define SMC_insl(a, r, p, l) \ + smc_pxa_dma_insl(a, lp->physaddr, r, dev->dma, p, l) +static inline void +smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma, + u_char *buf, int len) +{ + dma_addr_t dmabuf; + + /* fallback if no DMA available */ + if (dma == (unsigned char)-1) { + readsl(ioaddr + reg, buf, len); + return; + } + + /* 64 bit alignment is required for memory to memory DMA */ + if ((long)buf & 4) { + *((u32 *)buf)++ = SMC_inl(ioaddr, reg); + len--; + } + + len *= 4; + dmabuf = dma_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); + DCSR(dma) = DCSR_NODESC; + DTADR(dma) = dmabuf; + DSADR(dma) = physaddr + reg; + DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | + DCMD_WIDTH4 | (DCMD_LENGTH & len)); + DCSR(dma) = DCSR_NODESC | DCSR_RUN; + while (!(DCSR(dma) & DCSR_STOPSTATE)); + DCSR(dma) = 0; + dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); +} +#endif + +#ifdef SMC_insw +#undef SMC_insw +#define SMC_insw(a, r, p, l) \ + smc_pxa_dma_insw(a, lp->physaddr, r, dev->dma, p, l) +static inline void +smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma, + u_char *buf, int len) +{ + dma_addr_t dmabuf; + + /* fallback if no DMA available */ + if (dma == (unsigned char)-1) { + readsw(ioaddr + reg, buf, len); + return; + } + + /* 64 bit alignment is required for memory to memory DMA */ + while ((long)buf & 6) { + *((u16 *)buf)++ = SMC_inw(ioaddr, reg); + len--; + } + + len *= 2; + dmabuf = dma_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); + DCSR(dma) = DCSR_NODESC; + DTADR(dma) = dmabuf; + DSADR(dma) = physaddr + reg; + DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | + DCMD_WIDTH2 | (DCMD_LENGTH & len)); + DCSR(dma) = DCSR_NODESC | DCSR_RUN; + while (!(DCSR(dma) & DCSR_STOPSTATE)); + DCSR(dma) = 0; + dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); +} +#endif + +static void +smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs) +{ + DCSR(dma) = 0; +} +#endif /* SMC_USE_PXA_DMA */ + + +/* Because of bank switching, the LAN91x uses only 16 I/O ports */ +#ifndef SMC_IO_SHIFT +#define SMC_IO_SHIFT 0 +#endif +#define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) + + +/* + . Bank Select Register: + . + . yyyy yyyy 0000 00xx + . xx = bank number + . yyyy yyyy = 0x33, for identification purposes. +*/ +#define BANK_SELECT (14 << SMC_IO_SHIFT) + + +// Transmit Control Register +/* BANK 0 */ +#define TCR_REG SMC_REG(0x0000, 0) +#define TCR_ENABLE 0x0001 // When 1 we can transmit +#define TCR_LOOP 0x0002 // Controls output pin LBK +#define TCR_FORCOL 0x0004 // When 1 will force a collision +#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 +#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames +#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier +#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation +#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error +#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback +#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode + +#define TCR_CLEAR 0 /* do NOTHING */ +/* the default settings for the TCR register : */ +#define TCR_DEFAULT (TCR_ENABLE | TCR_PAD_EN) + + +// EPH Status Register +/* BANK 0 */ +#define EPH_STATUS_REG SMC_REG(0x0002, 0) +#define ES_TX_SUC 0x0001 // Last TX was successful +#define ES_SNGL_COL 0x0002 // Single collision detected for last tx +#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx +#define ES_LTX_MULT 0x0008 // Last tx was a multicast +#define ES_16COL 0x0010 // 16 Collisions Reached +#define ES_SQET 0x0020 // Signal Quality Error Test +#define ES_LTXBRD 0x0040 // Last tx was a broadcast +#define ES_TXDEFR 0x0080 // Transmit Deferred +#define ES_LATCOL 0x0200 // Late collision detected on last tx +#define ES_LOSTCARR 0x0400 // Lost Carrier Sense +#define ES_EXC_DEF 0x0800 // Excessive Deferral +#define ES_CTR_ROL 0x1000 // Counter Roll Over indication +#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin +#define ES_TXUNRN 0x8000 // Tx Underrun + + +// Receive Control Register +/* BANK 0 */ +#define RCR_REG SMC_REG(0x0004, 0) +#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted +#define RCR_PRMS 0x0002 // Enable promiscuous mode +#define RCR_ALMUL 0x0004 // When set accepts all multicast frames +#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets +#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets +#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision +#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier +#define RCR_SOFTRST 0x8000 // resets the chip + +/* the normal settings for the RCR register : */ +#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) +#define RCR_CLEAR 0x0 // set it to a base state + + +// Counter Register +/* BANK 0 */ +#define COUNTER_REG SMC_REG(0x0006, 0) + + +// Memory Information Register +/* BANK 0 */ +#define MIR_REG SMC_REG(0x0008, 0) + + +// Receive/Phy Control Register +/* BANK 0 */ +#define RPC_REG SMC_REG(0x000A, 0) +#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. +#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode +#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode +#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb +#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb +#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect +#define RPC_LED_RES (0x01) // LED = Reserved +#define RPC_LED_10 (0x02) // LED = 10Mbps link detect +#define RPC_LED_FD (0x03) // LED = Full Duplex Mode +#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred +#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect +#define RPC_LED_TX (0x06) // LED = TX packet occurred +#define RPC_LED_RX (0x07) // LED = RX packet occurred + +#ifndef RPC_LSA_DEFAULT +#define RPC_LSA_DEFAULT RPC_LED_100 +#endif +#ifndef RPC_LSB_DEFAULT +#define RPC_LSB_DEFAULT RPC_LED_FD +#endif + +#define RPC_DEFAULT (RPC_ANEG | (RPC_LSA_DEFAULT << RPC_LSXA_SHFT) | (RPC_LSB_DEFAULT << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) + + +/* Bank 0 0x0C is reserved */ + +// Bank Select Register +/* All Banks */ +#define BSR_REG 0x000E + + +// Configuration Reg +/* BANK 1 */ +#define CONFIG_REG SMC_REG(0x0000, 1) +#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy +#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL +#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus +#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. + +// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low +#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) + + +// Base Address Register +/* BANK 1 */ +#define BASE_REG SMC_REG(0x0002, 1) + + +// Individual Address Registers +/* BANK 1 */ +#define ADDR0_REG SMC_REG(0x0004, 1) +#define ADDR1_REG SMC_REG(0x0006, 1) +#define ADDR2_REG SMC_REG(0x0008, 1) + + +// General Purpose Register +/* BANK 1 */ +#define GP_REG SMC_REG(0x000A, 1) + + +// Control Register +/* BANK 1 */ +#define CTL_REG SMC_REG(0x000C, 1) +#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received +#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically +#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt +#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt +#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt +#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store +#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers +#define CTL_STORE 0x0001 // When set stores registers into EEPROM + + +// MMU Command Register +/* BANK 2 */ +#define MMU_CMD_REG SMC_REG(0x0000, 2) +#define MC_BUSY 1 // When 1 the last release has not completed +#define MC_NOP (0<<5) // No Op +#define MC_ALLOC (1<<5) // OR with number of 256 byte packets +#define MC_RESET (2<<5) // Reset MMU to initial state +#define MC_REMOVE (3<<5) // Remove the current rx packet +#define MC_RELEASE (4<<5) // Remove and release the current rx packet +#define MC_FREEPKT (5<<5) // Release packet in PNR register +#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit +#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs + + +// Packet Number Register +/* BANK 2 */ +#define PN_REG SMC_REG(0x0002, 2) + + +// Allocation Result Register +/* BANK 2 */ +#define AR_REG SMC_REG(0x0003, 2) +#define AR_FAILED 0x80 // Alocation Failed + + +// TX FIFO Ports Register +/* BANK 2 */ +#define TXFIFO_REG SMC_REG(0x0004, 2) +#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty + +// RX FIFO Ports Register +/* BANK 2 */ +#define RXFIFO_REG SMC_REG(0x0005, 2) +#define RXFIFO_REMPTY 0x80 // RX FIFO Empty + +#define FIFO_REG SMC_REG(0x0004, 2) + +// Pointer Register +/* BANK 2 */ +#define PTR_REG SMC_REG(0x0006, 2) +#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area +#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access +#define PTR_READ 0x2000 // When 1 the operation is a read + + +// Data Register +/* BANK 2 */ +#define DATA_REG SMC_REG(0x0008, 2) + + +// Interrupt Status/Acknowledge Register +/* BANK 2 */ +#define INT_REG SMC_REG(0x000C, 2) + + +// Interrupt Mask Register +/* BANK 2 */ +#define IM_REG SMC_REG(0x000D, 2) +#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt +#define IM_ERCV_INT 0x40 // Early Receive Interrupt +#define IM_EPH_INT 0x20 // Set by Ethernet Protocol Handler section +#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns +#define IM_ALLOC_INT 0x08 // Set when allocation request is completed +#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty +#define IM_TX_INT 0x02 // Transmit Interrupt +#define IM_RCV_INT 0x01 // Receive Interrupt + + +// Multicast Table Registers +/* BANK 3 */ +#define MCAST_REG1 SMC_REG(0x0000, 3) +#define MCAST_REG2 SMC_REG(0x0002, 3) +#define MCAST_REG3 SMC_REG(0x0004, 3) +#define MCAST_REG4 SMC_REG(0x0006, 3) + + +// Management Interface Register (MII) +/* BANK 3 */ +#define MII_REG SMC_REG(0x0008, 3) +#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup +#define MII_MDOE 0x0008 // MII Output Enable +#define MII_MCLK 0x0004 // MII Clock, pin MDCLK +#define MII_MDI 0x0002 // MII Input, pin MDI +#define MII_MDO 0x0001 // MII Output, pin MDO + + +// Revision Register +/* BANK 3 */ +/* ( hi: chip id low: rev # ) */ +#define REV_REG SMC_REG(0x000A, 3) + + +// Early RCV Register +/* BANK 3 */ +/* this is NOT on SMC9192 */ +#define ERCV_REG SMC_REG(0x000C, 3) +#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received +#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask + + +// External Register +/* BANK 7 */ +#define EXT_REG SMC_REG(0x0000, 7) + + +#define CHIP_9192 3 +#define CHIP_9194 4 +#define CHIP_9195 5 +#define CHIP_9196 6 +#define CHIP_91100 7 +#define CHIP_91100FD 8 +#define CHIP_91111FD 9 + +static const char * chip_ids[ 16 ] = { + NULL, NULL, NULL, + /* 3 */ "SMC91C90/91C92", + /* 4 */ "SMC91C94", + /* 5 */ "SMC91C95", + /* 6 */ "SMC91C96", + /* 7 */ "SMC91C100", + /* 8 */ "SMC91C100FD", + /* 9 */ "SMC91C11xFD", + NULL, NULL, NULL, + NULL, NULL, NULL}; + + +/* + . Transmit status bits +*/ +#define TS_SUCCESS 0x0001 +#define TS_LOSTCAR 0x0400 +#define TS_LATCOL 0x0200 +#define TS_16COL 0x0010 + +/* + . Receive status bits +*/ +#define RS_ALGNERR 0x8000 +#define RS_BRODCAST 0x4000 +#define RS_BADCRC 0x2000 +#define RS_ODDFRAME 0x1000 +#define RS_TOOLONG 0x0800 +#define RS_TOOSHORT 0x0400 +#define RS_MULTICAST 0x0001 +#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) + + +/* + * PHY IDs + * LAN83C183 == LAN91C111 Internal PHY + */ +#define PHY_LAN83C183 0x0016f840 +#define PHY_LAN83C180 0x02821c50 + +/* + * PHY Register Addresses (LAN91C111 Internal PHY) + * + * Generic PHY registers can be found in + * + * These phy registers are specific to our on-board phy. + */ + +// PHY Configuration Register 1 +#define PHY_CFG1_REG 0x10 +#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled +#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled +#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down +#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler +#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable +#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled +#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) +#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db +#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust +#define PHY_CFG1_TLVL_MASK 0x003C +#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time + + +// PHY Configuration Register 2 +#define PHY_CFG2_REG 0x11 +#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled +#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled +#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) +#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo + +// PHY Status Output (and Interrupt status) Register +#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) +#define PHY_INT_INT 0x8000 // 1=bits have changed since last read +#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected +#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync +#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx +#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx +#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx +#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected +#define PHY_INT_JAB 0x0100 // 1=Jabber detected +#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode +#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex + +// PHY Interrupt/Status Mask Register +#define PHY_MASK_REG 0x13 // Interrupt Mask +// Uses the same bit definitions as PHY_INT_REG + + +/* + * SMC91C96 ethernet config and status registers. + * These are in the "attribute" space. + */ +#define ECOR 0x8000 +#define ECOR_RESET 0x80 +#define ECOR_LEVEL_IRQ 0x40 +#define ECOR_WR_ATTRIB 0x04 +#define ECOR_ENABLE 0x01 + +#define ECSR 0x8002 +#define ECSR_IOIS8 0x20 +#define ECSR_PWRDWN 0x04 +#define ECSR_INT 0x02 + +#define ATTRIB_SIZE ((64*1024) << SMC_IO_SHIFT) + + +/* + * Macros to abstract register access according to the data bus + * capabilities. Please use those and not the in/out primitives. + * Note: the following macros do *not* select the bank -- this must + * be done separately as needed in the main code. The SMC_REG() macro + * only uses the bank argument for debugging purposes (when enabled). + */ + +#if SMC_DEBUG > 0 +#define SMC_REG(reg, bank) \ + ({ \ + int __b = SMC_CURRENT_BANK(); \ + if (unlikely((__b & ~0xf0) != (0x3300 | bank))) { \ + printk( "%s: bank reg screwed (0x%04x)\n", \ + CARDNAME, __b ); \ + BUG(); \ + } \ + reg<> 8) +#define SMC_GET_TXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF) +#define SMC_GET_RXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) >> 8) +#define SMC_GET_INT() (SMC_inw( ioaddr, INT_REG ) & 0xFF) +#define SMC_ACK_INT(x) \ + do { \ + unsigned long __flags; \ + int __mask; \ + local_irq_save(__flags); \ + __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \ + SMC_outw( __mask | (x), ioaddr, INT_REG ); \ + local_irq_restore(__flags); \ + } while (0) +#define SMC_GET_INT_MASK() (SMC_inw( ioaddr, INT_REG ) >> 8) +#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr, INT_REG ) +#endif + +#define SMC_CURRENT_BANK() SMC_inw( ioaddr, BANK_SELECT ) +#define SMC_SELECT_BANK(x) SMC_outw( x, ioaddr, BANK_SELECT ) +#define SMC_GET_BASE() SMC_inw( ioaddr, BASE_REG ) +#define SMC_SET_BASE(x) SMC_outw( x, ioaddr, BASE_REG ) +#define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG ) +#define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG ) +#define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG ) +#define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG ) +#define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG ) +#define SMC_GET_MII() SMC_inw( ioaddr, MII_REG ) +#define SMC_SET_MII(x) SMC_outw( x, ioaddr, MII_REG ) +#define SMC_GET_MIR() SMC_inw( ioaddr, MIR_REG ) +#define SMC_SET_MIR(x) SMC_outw( x, ioaddr, MIR_REG ) +#define SMC_GET_MMU_CMD() SMC_inw( ioaddr, MMU_CMD_REG ) +#define SMC_SET_MMU_CMD(x) SMC_outw( x, ioaddr, MMU_CMD_REG ) +#define SMC_GET_FIFO() SMC_inw( ioaddr, FIFO_REG ) +#define SMC_GET_PTR() SMC_inw( ioaddr, PTR_REG ) +#define SMC_SET_PTR(x) SMC_outw( x, ioaddr, PTR_REG ) +#define SMC_GET_RCR() SMC_inw( ioaddr, RCR_REG ) +#define SMC_SET_RCR(x) SMC_outw( x, ioaddr, RCR_REG ) +#define SMC_GET_REV() SMC_inw( ioaddr, REV_REG ) +#define SMC_GET_RPC() SMC_inw( ioaddr, RPC_REG ) +#define SMC_SET_RPC(x) SMC_outw( x, ioaddr, RPC_REG ) +#define SMC_GET_TCR() SMC_inw( ioaddr, TCR_REG ) +#define SMC_SET_TCR(x) SMC_outw( x, ioaddr, TCR_REG ) + +#ifndef SMC_GET_MAC_ADDR +#define SMC_GET_MAC_ADDR(addr) \ + do { \ + unsigned int __v; \ + __v = SMC_inw( ioaddr, ADDR0_REG ); \ + addr[0] = __v; addr[1] = __v >> 8; \ + __v = SMC_inw( ioaddr, ADDR1_REG ); \ + addr[2] = __v; addr[3] = __v >> 8; \ + __v = SMC_inw( ioaddr, ADDR2_REG ); \ + addr[4] = __v; addr[5] = __v >> 8; \ + } while (0) +#endif + +#define SMC_SET_MAC_ADDR(addr) \ + do { \ + SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG ); \ + SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG ); \ + SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \ + } while (0) + +#define SMC_CLEAR_MCAST() \ + do { \ + SMC_outw( 0, ioaddr, MCAST_REG1 ); \ + SMC_outw( 0, ioaddr, MCAST_REG2 ); \ + SMC_outw( 0, ioaddr, MCAST_REG3 ); \ + SMC_outw( 0, ioaddr, MCAST_REG4 ); \ + } while (0) +#define SMC_SET_MCAST(x) \ + do { \ + unsigned char *mt = (x); \ + SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \ + SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \ + SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \ + SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 ); \ + } while (0) + +#if SMC_CAN_USE_32BIT +/* + * Some setups just can't write 8 or 16 bits reliably when not aligned + * to a 32 bit boundary. I tell you that exists! + * We re-do the ones here that can be easily worked around if they can have + * their low parts written to 0 without adverse effects. + */ +#undef SMC_SELECT_BANK +#define SMC_SELECT_BANK(x) SMC_outl( (x)<<16, ioaddr, 12<> 16; \ + } while (0) +#else +#define SMC_PUT_PKT_HDR(status, length) \ + do { \ + SMC_outw( status, ioaddr, DATA_REG ); \ + SMC_outw( length, ioaddr, DATA_REG ); \ + } while (0) +#define SMC_GET_PKT_HDR(status, length) \ + do { \ + (status) = SMC_inw( ioaddr, DATA_REG ); \ + (length) = SMC_inw( ioaddr, DATA_REG ); \ + } while (0) +#endif + +#if SMC_CAN_USE_32BIT +#define SMC_PUSH_DATA(p, l) \ + do { \ + char *__ptr = (p); \ + int __len = (l); \ + if (__len >= 2 && (long)__ptr & 2) { \ + __len -= 2; \ + SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\ + } \ + SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ + if (__len & 2) { \ + __ptr += (__len & ~3); \ + SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ + } \ + } while (0) +#define SMC_PULL_DATA(p, l) \ + do { \ + char *__ptr = (p); \ + int __len = (l); \ + if ((long)__ptr & 2) { \ + /* \ + * We want 32bit alignment here. \ + * Since some buses perform a full 32bit \ + * fetch even for 16bit data we can't use \ + * SMC_inw() here. Back both source (on chip \ + * and destination) pointers of 2 bytes. \ + */ \ + (long)__ptr &= ~2; \ + __len += 2; \ + SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ + } \ + __len += 2; \ + SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \ + } while (0) +#elif SMC_CAN_USE_16BIT +#define SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) +#define SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) +#elif SMC_CAN_USE_8BIT +#define SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) +#define SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) +#endif + +#if ! SMC_CAN_USE_16BIT +#define SMC_outw(x, ioaddr, reg) \ + do { \ + unsigned int __val16 = (x); \ + SMC_outb( __val16, ioaddr, reg ); \ + SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\ + } while (0) +#define SMC_inw(ioaddr, reg) \ + ({ \ + unsigned int __val16; \ + __val16 = SMC_inb( ioaddr, reg ); \ + __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \ + __val16; \ + }) +#endif + + +#endif /* _SMC91X_H_ */ diff --git a/drivers/net/auto_irq.c b/drivers/net/auto_irq.c deleted file mode 100644 index 96ddc77b7..000000000 --- a/drivers/net/auto_irq.c +++ /dev/null @@ -1,68 +0,0 @@ -/* auto_irq.c: Auto-configure IRQ lines for linux. */ -/* - Written 1994 by Donald Becker. - - The author may be reached as becker@scyld.com - - This code is a general-purpose IRQ line detector for devices with - jumpered IRQ lines. If you can make the device raise an IRQ (and - that IRQ line isn't already being used), these routines will tell - you what IRQ line it's using -- perfect for those oh-so-cool boot-time - device probes! - - To use this, first call autoirq_setup(timeout). TIMEOUT is how many - 'jiffies' (1/100 sec.) to detect other devices that have active IRQ lines, - and can usually be zero at boot. 'autoirq_setup()' returns the bit - vector of nominally-available IRQ lines (lines may be physically in-use, - but not yet registered to a device). - Next, set up your device to trigger an interrupt. - Finally call autoirq_report(TIMEOUT) to find out which IRQ line was - most recently active. The TIMEOUT should usually be zero, but may - be set to the number of jiffies to wait for a slow device to raise an IRQ. - - The idea of using the setup timeout to filter out bogus IRQs came from - the serial driver. -*/ - - -#ifdef version -static const char *version= -"auto_irq.c:v1.11 Donald Becker (becker@scyld.com)"; -#endif - -#include -#include -#include -#include -#include -#include -#include - -static unsigned long irqs; - -void autoirq_setup(int waittime) -{ - irqs = probe_irq_on(); -} - -#define BUSY_LOOP_UNTIL(j) while ((long)(jiffies-(j)) < 0) ; -int autoirq_report(int waittime) -{ - unsigned long delay = jiffies + waittime; - BUSY_LOOP_UNTIL(delay) - return probe_irq_off(irqs); -} - -EXPORT_SYMBOL(autoirq_setup); -EXPORT_SYMBOL(autoirq_report); - - -/* - * Local variables: - * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c" - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ba1d4fc9a..d7f2142f8 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1633,7 +1633,7 @@ static struct ethtool_ops b44_ethtool_ops = { static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mii_ioctl_data *data = if_mii(ifr); + struct mii_ioctl_data __user *data = (struct mii_ioctl_data __user *)&ifr->ifr_data; struct b44 *bp = netdev_priv(dev); int err; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 8855b20e3..4b9558068 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -827,8 +827,8 @@ static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, cb->prev->command &= cpu_to_le16(~cb_s); while(nic->cb_to_send != nic->cb_to_use) { - if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd, - nic->cb_to_send->dma_addr))) { + if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd, + nic->cb_to_send->dma_addr)))) { /* Ok, here's where things get sticky. It's * possible that we can't schedule the command * because the controller is too busy, so @@ -1323,7 +1323,7 @@ static inline int e100_tx_clean(struct nic *nic) static void e100_clean_cbs(struct nic *nic) { if(nic->cbs) { - while(nic->cbs_avail != nic->params.cbs.count) { + while(nic->cb_to_clean != nic->cb_to_use) { struct cb *cb = nic->cb_to_clean; if(cb->skb) { pci_unmap_single(nic->pdev, @@ -1333,8 +1333,8 @@ static void e100_clean_cbs(struct nic *nic) dev_kfree_skb(cb->skb); } nic->cb_to_clean = nic->cb_to_clean->next; - nic->cbs_avail++; } + nic->cbs_avail = nic->params.cbs.count; pci_free_consistent(nic->pdev, sizeof(struct cb) * nic->params.cbs.count, nic->cbs, nic->cbs_dma_addr); @@ -1659,16 +1659,17 @@ static int e100_up(struct nic *nic) goto err_clean_cbs; e100_set_multicast_list(nic->netdev); e100_start_receiver(nic); + netif_start_queue(nic->netdev); mod_timer(&nic->watchdog, jiffies); if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, nic->netdev->name, nic->netdev))) goto err_no_irq; e100_enable_irq(nic); - netif_wake_queue(nic->netdev); return 0; err_no_irq: del_timer_sync(&nic->watchdog); + netif_stop_queue(nic->netdev); err_clean_cbs: e100_clean_cbs(nic); err_rx_clean_list: @@ -2074,8 +2075,9 @@ static struct ethtool_ops e100_ethtool_ops = { static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct nic *nic = netdev_priv(netdev); + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data; - return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL); + return generic_mii_ioctl(&nic->mii, mii, cmd, NULL); } static int e100_alloc(struct nic *nic) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 256e86c1b..8a8173c6a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -52,7 +52,7 @@ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.52-k4"; +char e1000_driver_version[] = "5.2.52-k2"; char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -2143,7 +2143,6 @@ e1000_clean(struct net_device *netdev, int *budget) if(work_done < work_to_do || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); - return 0; } return (work_done >= work_to_do); @@ -2504,7 +2503,7 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct e1000_adapter *adapter = netdev->priv; - struct mii_ioctl_data *data = if_mii(ifr); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; int retval; uint16_t mii_reg; uint16_t spddplx; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 56fc87881..f460db444 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -2017,7 +2017,7 @@ speedo_get_stats(struct net_device *dev) return &sp->stats; } -static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { u32 ethcmd; struct speedo_private *sp = netdev_priv(dev); @@ -2096,7 +2096,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(rq); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; int saved_acpi; int t; @@ -2129,7 +2129,7 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) pci_set_power_state(sp->pdev, saved_acpi); return 0; case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, rq->ifr_data); + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; } diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index b0fbb861c..b81777d75 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1923,13 +1923,14 @@ static struct ethtool_ops netdev_ethtool_ops = { static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); + rc = generic_mii_ioctl(&np->mii, data, cmd, NULL); spin_unlock_irq(&np->lock); return rc; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5fa162f6c..4e4e87678 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -901,7 +901,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ adapter = netdev->priv; memset(adapter, 0, sizeof(adapter)); - dev->dev.driver_data = netdev; + dev->driver_data = netdev; adapter->vdev = dev; adapter->netdev = netdev; @@ -971,7 +971,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ static int __devexit ibmveth_remove(struct vio_dev *dev) { - struct net_device *netdev = dev->dev.driver_data; + struct net_device *netdev = dev->driver_data; struct ibmveth_adapter *adapter = netdev->priv; unregister_netdev(netdev); diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 605a6873e..7bd6fe2ce 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -362,7 +362,7 @@ ixgb_ethtool_geeprom(struct ixgb_adapter *adapter, static int ixgb_ethtool_seeprom(struct ixgb_adapter *adapter, - struct ethtool_eeprom *eeprom, void __user *user_data) + struct ethtool_eeprom *eeprom, void *user_data) { struct ixgb_hw *hw = &adapter->hw; uint16_t eeprom_buff[256]; @@ -457,10 +457,10 @@ ixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id) int ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) { struct ixgb_adapter *adapter = netdev->priv; - void __user *addr = ifr->ifr_data; + void *addr = ifr->ifr_data; uint32_t cmd; - if (get_user(cmd, (uint32_t __user *) addr)) + if (get_user(cmd, (uint32_t *) addr)) return -EFAULT; switch (cmd) { diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 86f34b5ec..84e291e24 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -34,6 +34,8 @@ static const char version1[] = #include "8390.h" +#define DRV_NAME "ne-h8300" + /* Some defines that people can play with if so inclined. */ /* Do we perform extra sanity checks on stuff ? */ @@ -156,6 +158,7 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, NE_IO_EXTENT); } +#ifndef MODULE struct net_device * __init ne_probe(int unit) { struct net_device *dev = alloc_ei_netdev(); @@ -187,6 +190,7 @@ out: free_netdev(dev); return ERR_PTR(err); } +#endif static int __init ne_probe1(struct net_device *dev, int ioaddr) { @@ -200,7 +204,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char bus_width; - if (!request_region(ioaddr, NE_IO_EXTENT, dev->name)) + if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; reg0 = inb_p(ioaddr); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index ea5a88cf7..9a46c5626 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -778,7 +778,7 @@ static struct ethtool_ops netdev_ethtool_ops = { static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { axnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_ifru; + u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { case SIOCGMIIPHY: diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index bdf90d4e6..511bc109b 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2170,13 +2170,14 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct pcnet32_private *lp = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int rc; unsigned long flags; /* SIOC[GS]MIIxxx ioctls */ if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); - rc = generic_mii_ioctl(&lp->mii_if, if_mii(rq), cmd, NULL); + rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); spin_unlock_irqrestore(&lp->lock, flags); } else { rc = -EOPNOTSUPP; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 43f923c96..31bbff4f0 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1217,7 +1217,7 @@ static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct net_local *nl = netdev_priv(dev); - struct plipconf *pc = (struct plipconf *) &rq->ifr_ifru; + struct plipconf *pc = (struct plipconf *) &rq->ifr_data; if (cmd != SIOCDEVPLIP) return -EOPNOTSUPP; diff --git a/drivers/net/rcif.h b/drivers/net/rcif.h deleted file mode 100644 index 85ff8615c..000000000 --- a/drivers/net/rcif.h +++ /dev/null @@ -1,292 +0,0 @@ -/* -** ************************************************************************* -** -** -** R C I F . H -** -** -** RedCreek InterFace include file. -** -** --------------------------------------------------------------------- -** --- Copyright (c) 1998-1999, RedCreek Communications Inc. --- -** --- All rights reserved. --- -** --------------------------------------------------------------------- -** -** File Description: -** -** Header file private ioctl commands. -** -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. - -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. - -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** ************************************************************************* -*/ - -#ifndef RCIF_H -#define RCIF_H - -/* The following protocol revision # should be incremented every time - a new protocol or new structures are used in this file. */ -int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */ - -/* define a single TCB & buffer */ -typedef struct { /* a single buffer */ - U32 context; /* context */ - U32 scount; /* segment count */ - U32 size; /* segment size */ - U32 addr; /* segment physical address */ -} __attribute__ ((packed)) - singleB, *psingleB; -typedef struct { /* a single TCB */ - /* - ** +-----------------------+ - ** | 1 | one buffer in the TCB - ** +-----------------------+ - ** | | user's buffer reference - ** +-----------------------+ - ** | 1 | one segment buffer - ** +-----------------------+ _ - ** | | size \ - ** +-----------------------+ \ segment descriptor - ** | | physical address of buffer / - ** +-----------------------+ _/ - */ - U32 bcount; /* buffer count */ - singleB b; /* buffer */ - -} __attribute__ ((packed)) - singleTCB, *psingleTCB; - -/* - When adding new entries, please add all 5 related changes, since - it helps keep everything consistent: - 1) User structure entry - 2) User data entry - 3) Structure short-cut entry - 4) Data short-cut entry - 5) Command identifier entry - - For Example ("GETSPEED"): - 1) struct RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed; - 2) struct RCgetspeed_tag *getspeed; - 3) #define RCUS_GETSPEED data.RCgetspeed; - 4) #define RCUD_GETSPEED _RC_user_data.getspeed - 5) #define RCUC_GETSPEED 0x02 - - Notes for the "GETSPEED" entry, above: - 1) RCgetspeed - RC{name} - RCgetspeed_tag - RC{name}_tag - LinkSpeedCode - create any structure format desired (not too large, - since memory will be unioned with all other entries) - 2) RCgetspeed_tag - RC{name}_tag chosen in #1 - getspeed - arbitrary name (ptr to structure in #1) - 3) RCUS_GETSPEED - RCUS_{NAME} ("NAME" & "name" do not have to the same) - data.RCgetspeed - data.RC{name} ("RC{name}" from #1) - 4) RCUD_GETSPEED - _RC_user_data.getspeed ("getspeed" from #2) - 5) RCUC_GETSPEED - unique hex identifier entry. -*/ - -typedef struct RC_user_tag RCuser_struct; - -/* 1) User structure entry */ -struct RC_user_tag { - int cmd; - union { - /* GETINFO structure */ - struct RCgetinfo_tag { - unsigned long int mem_start; - unsigned long int mem_end; - unsigned long int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; - } RCgetinfo; /* <---- RCgetinfo */ - - /* GETSPEED structure */ - struct RCgetspeed_tag { - U32 LinkSpeedCode; - } RCgetspeed; /* <---- RCgetspeed */ - - /* SETSPEED structure */ - struct RCsetspeed_tag { - U16 LinkSpeedCode; - } RCsetspeed; /* <---- RCsetspeed */ - - /* GETPROM structure */ - struct RCgetprom_tag { - U32 PromMode; - } RCgetprom; /* <---- RCgetprom */ - - /* SETPROM structure */ - struct RCsetprom_tag { - U16 PromMode; - } RCsetprom; /* <---- RCsetprom */ - - /* GETBROADCAST structure */ - struct RCgetbroadcast_tag { - U32 BroadcastMode; - } RCgetbroadcast; /* <---- RCgetbroadcast */ - - /* SETBROADCAST structure */ - struct RCsetbroadcast_tag { - U16 BroadcastMode; - } RCsetbroadcast; /* <---- RCsetbroadcast */ - - /* GETFIRMWAREVER structure */ -#define FirmStringLen 80 - struct RCgetfwver_tag { - U8 FirmString[FirmStringLen]; - } RCgetfwver; /* <---- RCgetfwver */ - - /* GETIPANDMASK structure */ - struct RCgetipnmask_tag { - U32 IpAddr; - U32 NetMask; - } RCgetipandmask; /* <---- RCgetipandmask */ - - /* SETIPANDMASK structure */ - struct RCsetipnmask_tag { - U32 IpAddr; - U32 NetMask; - } RCsetipandmask; /* <---- RCsetipandmask */ - - /* GETMAC structure */ -#define MAC_SIZE 10 - struct RCgetmac_tag { - U8 mac[MAC_SIZE]; - } RCgetmac; /* <---- RCgetmac */ - - /* SETMAC structure */ - struct RCsetmac_tag { - U8 mac[MAC_SIZE]; - } RCsetmac; /* <---- RCsetmac */ - - /* GETLINKSTATUS structure */ - struct RCgetlnkstatus_tag { - U32 ReturnStatus; - } RCgetlnkstatus; /* <---- RCgetlnkstatus */ - - /* GETLINKSTATISTICS structure */ - struct RCgetlinkstats_tag { - RCLINKSTATS StatsReturn; - } RCgetlinkstats; /* <---- RCgetlinkstats */ - - /* DEFAULT structure (when no command was recognized) */ - struct RCdefault_tag { - int rc; - } RCdefault; /* <---- RCdefault */ - - } data; - -}; /* struct RC_user_tag { ... } */ - -/* 2) User data entry */ -/* RCUD = RedCreek User Data */ -union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */ - struct RCgetinfo_tag *getinfo; - struct RCgetspeed_tag *getspeed; - struct RCgetprom_tag *getprom; - struct RCgetbroadcast_tag *getbroadcast; - struct RCgetfwver_tag *getfwver; - struct RCgetipnmask_tag *getipandmask; - struct RCgetmac_tag *getmac; - struct RCgetlnkstatus_tag *getlinkstatus; - struct RCgetlinkstats_tag *getlinkstatistics; - struct RCdefault_tag *rcdefault; - struct RCsetspeed_tag *setspeed; - struct RCsetprom_tag *setprom; - struct RCsetbroadcast_tag *setbroadcast; - struct RCsetipnmask_tag *setipandmask; - struct RCsetmac_tag *setmac; -} _RC_user_data; /* declare as a global, so the defines below will work */ - -/* 3) Structure short-cut entry */ -/* define structure short-cuts *//* structure names are taken from RC_user_tag structure above */ -#define RCUS_GETINFO data.RCgetinfo; -#define RCUS_GETSPEED data.RCgetspeed; -#define RCUS_GETPROM data.RCgetprom; -#define RCUS_GETBROADCAST data.RCgetbroadcast; -#define RCUS_GETFWVER data.RCgetfwver; -#define RCUS_GETIPANDMASK data.RCgetipandmask; -#define RCUS_GETMAC data.RCgetmac; -#define RCUS_GETLINKSTATUS data.RCgetlnkstatus; -#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats; -#define RCUS_DEFAULT data.RCdefault; -#define RCUS_SETSPEED data.RCsetspeed; -#define RCUS_SETPROM data.RCsetprom; -#define RCUS_SETBROADCAST data.RCsetbroadcast; -#define RCUS_SETIPANDMASK data.RCsetipandmask; -#define RCUS_SETMAC data.RCsetmac; - -/* 4) Data short-cut entry */ -/* define data short-cuts *//* pointer names are from RC_user_data_tag union (just below RC_user_tag) */ -#define RCUD_GETINFO _RC_user_data.getinfo -#define RCUD_GETSPEED _RC_user_data.getspeed -#define RCUD_GETPROM _RC_user_data.getprom -#define RCUD_GETBROADCAST _RC_user_data.getbroadcast -#define RCUD_GETFWVER _RC_user_data.getfwver -#define RCUD_GETIPANDMASK _RC_user_data.getipandmask -#define RCUD_GETMAC _RC_user_data.getmac -#define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus -#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics -#define RCUD_DEFAULT _RC_user_data.rcdefault -#define RCUD_SETSPEED _RC_user_data.setspeed -#define RCUD_SETPROM _RC_user_data.setprom -#define RCUD_SETBROADCAST _RC_user_data.setbroadcast -#define RCUD_SETIPANDMASK _RC_user_data.setipandmask -#define RCUD_SETMAC _RC_user_data.setmac - -/* 5) Command identifier entry */ -/* define command identifiers */ -#define RCUC_GETINFO 0x01 -#define RCUC_GETSPEED 0x02 -#define RCUC_GETFWVER 0x03 -#define RCUC_GETIPANDMASK 0x04 -#define RCUC_GETMAC 0x05 -#define RCUC_GETLINKSTATUS 0x06 -#define RCUC_GETLINKSTATISTICS 0x07 -#define RCUC_GETPROM 0x14 -#define RCUC_GETBROADCAST 0x15 -#define RCUC_DEFAULT 0xff -#define RCUC_SETSPEED 0x08 -#define RCUC_SETIPANDMASK 0x09 -#define RCUC_SETMAC 0x0a -#define RCUC_SETPROM 0x16 -#define RCUC_SETBROADCAST 0x17 - -/* define ioctl commands to use, when talking to RC 45/PCI driver */ -#define RCU_PROTOCOL_REV SIOCDEVPRIVATE -#define RCU_COMMAND SIOCDEVPRIVATE+1 - -/* - Intended use for the above defines is shown below (GETINFO, as this example): - - RCuser_struct RCuser; // declare RCuser structure - struct ifreq ifr; // declare an interface request structure - - RCuser.cmd = RCUC_GETINFO; // set user command to GETINFO - ifr->ifr_data = (caddr_t) &RCuser; // set point to user structure - - sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); // get a socket - ioctl(sock, RCU_COMMAND, &ifr); // do ioctl on socket - - RCUD_GETINFO = &RCuser.RCUS_GETINFO; // set data pointer for GETINFO - - // print results - printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n", - RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end, - RCUD_GETINFO->base_addr, RCUD_GETINFO->irq); -*/ - -#endif /* RCIF_H */ diff --git a/drivers/net/rclanmtl.c b/drivers/net/rclanmtl.c deleted file mode 100644 index 14bd88ab2..000000000 --- a/drivers/net/rclanmtl.c +++ /dev/null @@ -1,2029 +0,0 @@ -/* -** ************************************************************************* -** -** -** R C L A N M T L . C $Revision: 6 $ -** -** -** RedCreek I2O LAN Message Transport Layer program module. -** -** --------------------------------------------------------------------- -** --- Copyright (c) 1997-1999, RedCreek Communications Inc. --- -** --- All rights reserved. --- -** --------------------------------------------------------------------- -** -** File Description: -** -** Host side I2O (Intelligent I/O) LAN message transport layer. -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. - -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. - -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -** 1998-1999, LAN API was modified and enhanced by Alice Hennessy. -** -** Sometime in 1997, LAN API was written from scratch by Wendell Nichols. -** ************************************************************************* -*/ - -#define DEBUG 1 - -#define RC_LINUX_MODULE -#include "rclanmtl.h" - - /* RedCreek LAN device Target ID */ -#define RC_LAN_TARGET_ID 0x10 - /* RedCreek's OSM default LAN receive Initiator */ -#define DEFAULT_RECV_INIT_CONTEXT 0xA17 - -/* -** I2O message structures -*/ - -#define I2O_TID_SZ 12 -#define I2O_FUNCTION_SZ 8 - -/* Transaction Reply Lists (TRL) Control Word structure */ - -#define I2O_TRL_FLAGS_SINGLE_FIXED_LENGTH 0x00 -#define I2O_TRL_FLAGS_SINGLE_VARIABLE_LENGTH 0x40 -#define I2O_TRL_FLAGS_MULTIPLE_FIXED_LENGTH 0x80 - -/* LAN Class specific functions */ - -#define I2O_LAN_PACKET_SEND 0x3B -#define I2O_LAN_SDU_SEND 0x3D -#define I2O_LAN_RECEIVE_POST 0x3E -#define I2O_LAN_RESET 0x35 -#define I2O_LAN_SHUTDOWN 0x37 - -/* Private Class specfic function */ -#define I2O_PRIVATE 0xFF - -/* I2O Executive Function Codes. */ - -#define I2O_EXEC_ADAPTER_ASSIGN 0xB3 -#define I2O_EXEC_ADAPTER_READ 0xB2 -#define I2O_EXEC_ADAPTER_RELEASE 0xB5 -#define I2O_EXEC_BIOS_INFO_SET 0xA5 -#define I2O_EXEC_BOOT_DEVICE_SET 0xA7 -#define I2O_EXEC_CONFIG_VALIDATE 0xBB -#define I2O_EXEC_CONN_SETUP 0xCA -#define I2O_EXEC_DEVICE_ASSIGN 0xB7 -#define I2O_EXEC_DEVICE_RELEASE 0xB9 -#define I2O_EXEC_HRT_GET 0xA8 -#define I2O_EXEC_IOP_CLEAR 0xBE -#define I2O_EXEC_IOP_CONNECT 0xC9 -#define I2O_EXEC_IOP_RESET 0xBD -#define I2O_EXEC_LCT_NOTIFY 0xA2 -#define I2O_EXEC_OUTBOUND_INIT 0xA1 -#define I2O_EXEC_PATH_ENABLE 0xD3 -#define I2O_EXEC_PATH_QUIESCE 0xC5 -#define I2O_EXEC_PATH_RESET 0xD7 -#define I2O_EXEC_STATIC_MF_CREATE 0xDD -#define I2O_EXEC_STATIC_MF_RELEASE 0xDF -#define I2O_EXEC_STATUS_GET 0xA0 -#define I2O_EXEC_SW_DOWNLOAD 0xA9 -#define I2O_EXEC_SW_UPLOAD 0xAB -#define I2O_EXEC_SW_REMOVE 0xAD -#define I2O_EXEC_SYS_ENABLE 0xD1 -#define I2O_EXEC_SYS_MODIFY 0xC1 -#define I2O_EXEC_SYS_QUIESCE 0xC3 -#define I2O_EXEC_SYS_TAB_SET 0xA3 - - /* Init Outbound Q status */ -#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01 -#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02 -#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03 -#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04 - -#define I2O_UTIL_NOP 0x00 - -/* I2O Get Status State values */ - -#define I2O_IOP_STATE_INITIALIZING 0x01 -#define I2O_IOP_STATE_RESET 0x02 -#define I2O_IOP_STATE_HOLD 0x04 -#define I2O_IOP_STATE_READY 0x05 -#define I2O_IOP_STATE_OPERATIONAL 0x08 -#define I2O_IOP_STATE_FAILED 0x10 -#define I2O_IOP_STATE_FAULTED 0x11 - -/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */ - -#define I2O_REPLY_STATUS_SUCCESS 0x00 -#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01 -#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 -#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03 -#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04 -#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05 -#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06 -#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07 -#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08 -#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09 -#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A -#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80 - -/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/ - -#define I2O_DETAIL_STATUS_SUCCESS 0x0000 -#define I2O_DETAIL_STATUS_BAD_KEY 0x0001 -#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0002 -#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x0003 -#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x0004 -#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x0005 -#define I2O_DETAIL_STATUS_DEVICE_RESET 0x0006 -#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x0007 -#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0008 -#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0009 -#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000A -#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000B -#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x000C -#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x000D -#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x000E -#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x000F -#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0010 -#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0011 -#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0012 -#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0013 -#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0014 -#define I2O_DETAIL_STATUS_TCL_ERROR 0x0015 -#define I2O_DETAIL_STATUS_TIMEOUT 0x0016 -#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0017 -#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0018 -#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x0019 -#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001A - - /* I2O msg header defines for VersionOffset */ -#define I2OMSGVER_1_5 0x0001 -#define SGL_OFFSET_0 I2OMSGVER_1_5 -#define SGL_OFFSET_4 (0x0040 | I2OMSGVER_1_5) -#define TRL_OFFSET_5 (0x0050 | I2OMSGVER_1_5) -#define TRL_OFFSET_6 (0x0060 | I2OMSGVER_1_5) - - /* I2O msg header defines for MsgFlags */ -#define MSG_STATIC 0x0100 -#define MSG_64BIT_CNTXT 0x0200 -#define MSG_MULTI_TRANS 0x1000 -#define MSG_FAIL 0x2000 -#define MSG_LAST 0x4000 -#define MSG_REPLY 0x8000 - - /* normal LAN request message MsgFlags and VersionOffset (0x1041) */ -#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4) - - /* minimum size msg */ -#define THREE_WORD_MSG_SIZE 0x00030000 -#define FOUR_WORD_MSG_SIZE 0x00040000 -#define FIVE_WORD_MSG_SIZE 0x00050000 -#define SIX_WORD_MSG_SIZE 0x00060000 -#define SEVEN_WORD_MSG_SIZE 0x00070000 -#define EIGHT_WORD_MSG_SIZE 0x00080000 -#define NINE_WORD_MSG_SIZE 0x00090000 - -/* Special TID Assignments */ - -#define I2O_IOP_TID 0 -#define I2O_HOST_TID 0xB91 - - /* RedCreek I2O private message codes */ -#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */ -#define RC_PRIVATE_SET_MAC_ADDR 0x0002 -#define RC_PRIVATE_GET_NIC_STATS 0x0003 -#define RC_PRIVATE_GET_LINK_STATUS 0x0004 -#define RC_PRIVATE_SET_LINK_SPEED 0x0005 -#define RC_PRIVATE_SET_IP_AND_MASK 0x0006 -/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 *//* OBSOLETE */ -#define RC_PRIVATE_GET_LINK_SPEED 0x0008 -#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009 -/* #define RC_PRIVATE_GET_MAC_ADDR 0x000A */ -#define RC_PRIVATE_GET_IP_AND_MASK 0x000B -#define RC_PRIVATE_DEBUG_MSG 0x000C -#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D -#define RC_PRIVATE_SET_PROMISCUOUS_MODE 0x000e -#define RC_PRIVATE_GET_PROMISCUOUS_MODE 0x000f -#define RC_PRIVATE_SET_BROADCAST_MODE 0x0010 -#define RC_PRIVATE_GET_BROADCAST_MODE 0x0011 - -#define RC_PRIVATE_REBOOT 0x00FF - -/* I2O message header */ -typedef struct _I2O_MESSAGE_FRAME { - U8 VersionOffset; - U8 MsgFlags; - U16 MessageSize; - BF TargetAddress:I2O_TID_SZ; - BF InitiatorAddress:I2O_TID_SZ; - BF Function:I2O_FUNCTION_SZ; - U32 InitiatorContext; - /* SGL[] */ -} I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME; - - /* assumed a 16K minus 256 byte space for outbound queue message frames */ -#define MSG_FRAME_SIZE 512 -#define NMBR_MSG_FRAMES 30 - - /* - ** in reserved space right after PAB in host memory is area for returning - ** values from card - */ - -/* -** typedef NICSTAT -** -** Data structure for NIC statistics retruned from PCI card. Data copied from -** here to user allocated RCLINKSTATS (see rclanmtl.h) structure. -*/ -typedef struct tag_NicStat { - unsigned long TX_good; - unsigned long TX_maxcol; - unsigned long TX_latecol; - unsigned long TX_urun; - unsigned long TX_crs; /* lost carrier sense */ - unsigned long TX_def; /* transmit deferred */ - unsigned long TX_singlecol; /* single collisions */ - unsigned long TX_multcol; - unsigned long TX_totcol; - unsigned long Rcv_good; - unsigned long Rcv_CRCerr; - unsigned long Rcv_alignerr; - unsigned long Rcv_reserr; /* rnr'd pkts */ - unsigned long Rcv_orun; - unsigned long Rcv_cdt; - unsigned long Rcv_runt; - unsigned long dump_status; /* last field directly from the chip */ -} NICSTAT, *P_NICSTAT; - -#define DUMP_DONE 0x0000A005 /* completed statistical dump */ -#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */ - -static volatile int msgFlag; - -/* local function prototypes */ -static void ProcessOutboundI2OMsg (PPAB pPab, U32 phyMsgAddr); -static int FillI2OMsgSGLFromTCB (PU32 pMsg, PRCTCB pXmitCntrlBlock); -static int GetI2OStatus (PPAB pPab); -static int SendI2OOutboundQInitMsg (PPAB pPab); -static int SendEnableSysMsg (PPAB pPab); - -/* -** ========================================================================= -** RCInitI2OMsgLayer() -** -** Initialize the RedCreek I2O Module and adapter. -** -** Inputs: dev - the devices net_device struct -** TransmitCallbackFunction - address of transmit callback function -** ReceiveCallbackFunction - address of receive callback function -** -** private message block is allocated by user. It must be in locked pages. -** p_msgbuf and p_phymsgbuf point to the same location. Must be contigous -** memory block of a minimum of 16K byte and long word aligned. -** ========================================================================= -*/ -RC_RETURN -RCInitI2OMsgLayer (struct net_device *dev, - PFNTXCALLBACK TransmitCallbackFunction, - PFNRXCALLBACK ReceiveCallbackFunction, - PFNCALLBACK RebootCallbackFunction) -{ - int result; - PPAB pPab; - U32 pciBaseAddr = dev->base_addr; - PDPA pDpa = dev->priv; - PU8 p_msgbuf = pDpa->msgbuf; - PU8 p_phymsgbuf = (PU8) pDpa->msgbuf_dma; - - dprintk - ("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:%p phymsgbuf:0x%08ulx\n" - "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", - pDpa->id, pciBaseAddr, p_msgbuf, (u32) p_phymsgbuf, - (u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction); - - /* Check if this interface already initialized - if so, shut it down */ - if (pDpa->pPab != NULL) { - printk (KERN_WARNING - "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", - pDpa->id); -/* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ - pDpa->pPab = NULL; - } - - /* store adapter instance values in adapter block. - * Adapter block is at beginning of message buffer */ - - pPab = kmalloc (sizeof (*pPab), GFP_KERNEL); - if (!pPab) { - printk (KERN_ERR - "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); - result = RC_RTN_MALLOC_ERROR; - goto err_out; - } - - memset (pPab, 0, sizeof (*pPab)); - pDpa->pPab = pPab; - pPab->p_atu = (PATU) pciBaseAddr; - pPab->pPci45LinBaseAddr = (PU8) pciBaseAddr; - - /* Set outbound message frame addr */ - pPab->outMsgBlockPhyAddr = (U32) p_phymsgbuf; - pPab->pLinOutMsgBlock = (PU8) p_msgbuf; - - /* store callback function addresses */ - pPab->pTransCallbackFunc = TransmitCallbackFunction; - pPab->pRecvCallbackFunc = ReceiveCallbackFunction; - pPab->pRebootCallbackFunc = RebootCallbackFunction; - pPab->pCallbackFunc = (PFNCALLBACK) NULL; - - /* - ** Initialize I2O IOP - */ - result = GetI2OStatus (pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { - printk (KERN_INFO - "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); - RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL); - } - - result = SendI2OOutboundQInitMsg (pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - result = SendEnableSysMsg (pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - return RC_RTN_NO_ERROR; - - err_out_dealloc: - kfree (pPab); - err_out: - return result; -} - -/* -** ========================================================================= -** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time -** but can be disabled and re-enabled through these two function calls. -** Packets will still be put into any posted received buffers and packets will -** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts -** will prevent hardware interrupt to host even though the outbound I2O msg -** queue is not emtpy. -** ========================================================================= -*/ -#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */ - -RC_RETURN -RCDisableI2OInterrupts (struct net_device * dev) -{ - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT; - - return RC_RTN_NO_ERROR; -} - -RC_RETURN -RCEnableI2OInterrupts (struct net_device * dev) -{ - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT; - - return RC_RTN_NO_ERROR; - -} - -/* -** ========================================================================= -** RCI2OSendPacket() -** ========================================================================= -*/ -RC_RETURN -RCI2OSendPacket (struct net_device * dev, U32 InitiatorContext, - PRCTCB pTransCtrlBlock) -{ - U32 msgOffset; - PU32 pMsg; - int size; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - dprintk ("RCI2OSendPacket()...\n"); - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - /* get Inbound free Q entry - reading from In Q gets free Q entry */ - /* offset to Msg Frame in PCI msg block */ - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("RCI2OSendPacket(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); - - if (size == -1) { /* error processing TCB - send NOP msg */ - dprintk ("RCI2OSendPacket(): Error Rrocess TCB!\n"); - pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = - I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - return RC_RTN_TCB_ERROR; - } else { /* send over msg header */ - - pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ - pMsg[1] = - I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 | - RC_LAN_TARGET_ID; - pMsg[2] = InitiatorContext; - pMsg[3] = 0; /* batch reply */ - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_NO_ERROR; - } -} - -/* -** ========================================================================= -** RCI2OPostRecvBuffer() -** -** inputs: pBufrCntrlBlock - pointer to buffer control block -** -** returns TRUE if successful in sending message, else FALSE. -** ========================================================================= -*/ -RC_RETURN -RCPostRecvBuffers (struct net_device * dev, PRCTCB pTransCtrlBlock) -{ - U32 msgOffset; - PU32 pMsg; - int size; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - dprintk ("RCPostRecvBuffers()...\n"); - - /* search for DeviceHandle */ - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - /* get Inbound free Q entry - reading from In Q gets free Q entry */ - /* offset to Msg Frame in PCI msg block */ - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); - - if (size == -1) { /* error prcessing TCB - send 3 DWORD private msg == NOP */ - dprintk - ("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", - size); - pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = - I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - /* post to Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_TCB_ERROR; - } else { /* send over size msg header */ - - pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ - pMsg[1] = - I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | - RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = *(PU32) pTransCtrlBlock; /* number of packet buffers */ - /* post to Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_NO_ERROR; - } -} - -/* -** ========================================================================= -** RCProcI2OMsgQ() -** -** Process I2O outbound message queue until empty. -** ========================================================================= -*/ -irqreturn_t -RCProcI2OMsgQ (struct net_device *dev) -{ - U32 phyAddrMsg; - PU8 p8Msg; - PU32 p32; - U16 count; - PPAB pPab = ((PDPA) dev->priv)->pPab; - unsigned char debug_msg[20]; - - if (pPab == NULL) - return IRQ_NONE; - - phyAddrMsg = pPab->p_atu->OutQueue; - - while (phyAddrMsg != 0xFFFFFFFF) { - p8Msg = - pPab->pLinOutMsgBlock + (phyAddrMsg - - pPab->outMsgBlockPhyAddr); - p32 = (PU32) p8Msg; - - dprintk ("msg: 0x%x 0x%x \n", p8Msg[7], p32[5]); - - /* Send Packet Reply Msg */ - if (I2O_LAN_PACKET_SEND == p8Msg[7]) { /* function code byte */ - count = *(PU16) (p8Msg + 2); - count -= p8Msg[0] >> 4; - /* status, count, context[], adapter */ - (*pPab->pTransCallbackFunc) (p8Msg[19], count, p32 + 5, - dev); - } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ - dprintk - ("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", - (u32) pPab, (u32) p8Msg, (u32) p32); - dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); - /* status, count, buckets remaining, packetParmBlock, adapter */ - (*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12], - p32[5], p32 + 6, dev); - } else if (I2O_LAN_RESET == p8Msg[7] - || I2O_LAN_SHUTDOWN == p8Msg[7]) - if (pPab->pCallbackFunc) - (*pPab->pCallbackFunc) (p8Msg[19], 0, 0, dev); - else - pPab->pCallbackFunc = (PFNCALLBACK) 1; - else if (I2O_PRIVATE == p8Msg[7]) { - dprintk ("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]); - switch (p32[5]) { - case RC_PRIVATE_DEBUG_MSG: - msgFlag = 1; - dprintk ("Received I2O_PRIVATE msg\n"); - debug_msg[15] = (p32[6] & 0xff000000) >> 24; - debug_msg[14] = (p32[6] & 0x00ff0000) >> 16; - debug_msg[13] = (p32[6] & 0x0000ff00) >> 8; - debug_msg[12] = (p32[6] & 0x000000ff); - - debug_msg[11] = (p32[7] & 0xff000000) >> 24; - debug_msg[10] = (p32[7] & 0x00ff0000) >> 16; - debug_msg[9] = (p32[7] & 0x0000ff00) >> 8; - debug_msg[8] = (p32[7] & 0x000000ff); - - debug_msg[7] = (p32[8] & 0xff000000) >> 24; - debug_msg[6] = (p32[8] & 0x00ff0000) >> 16; - debug_msg[5] = (p32[8] & 0x0000ff00) >> 8; - debug_msg[4] = (p32[8] & 0x000000ff); - - debug_msg[3] = (p32[9] & 0xff000000) >> 24; - debug_msg[2] = (p32[9] & 0x00ff0000) >> 16; - debug_msg[1] = (p32[9] & 0x0000ff00) >> 8; - debug_msg[0] = (p32[9] & 0x000000ff); - - debug_msg[16] = '\0'; - dprintk ("%s", debug_msg); - break; - case RC_PRIVATE_REBOOT: - dprintk ("Adapter reboot initiated...\n"); - if (pPab->pRebootCallbackFunc) - (*pPab->pRebootCallbackFunc) (0, 0, 0, - dev); - break; - default: - printk (KERN_WARNING - "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", - p32[5]); - break; - } - } - - /* - ** Process other Msg's - */ - else - ProcessOutboundI2OMsg (pPab, phyAddrMsg); - - /* return MFA to outbound free Q */ - pPab->p_atu->OutQueue = phyAddrMsg; - - /* any more msgs? */ - phyAddrMsg = pPab->p_atu->OutQueue; - } - - return IRQ_HANDLED; -} - -/* -** ========================================================================= -** Returns LAN interface statistical counters to space provided by caller at -** StatsReturnAddr. Returns 0 if success, else RC_RETURN code. -** This function will call the WaitCallback function provided by -** user while waiting for card to respond. -** ========================================================================= -*/ -RC_RETURN -RCGetLinkStatistics (struct net_device *dev, - P_RCLINKSTATS StatsReturnAddr, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32, pReturnAddr; - P_NICSTAT pStats; - int i; - PPAB pPab = ((PDPA) dev->priv)->pPab; - -/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("Get8255XStats(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - -/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ -/*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ - - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x112; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p32 = (PU32) pPab->outMsgBlockPhyAddr; - pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; - pStats->dump_status = 0xFFFFFFFF; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (pStats->dump_status != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk - ("RCGet82558Stats() Timeout waiting for NIC statistics\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - pReturnAddr = (PU32) StatsReturnAddr; - - /* copy Nic stats to user's structure */ - for (i = 0; i < (int) sizeof (RCLINKSTATS) / 4; i++) - pReturnAddr[i] = p32[i]; - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** Get82558LinkStatus() -** ========================================================================= -*/ -RC_RETURN -RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", - (u32) ReturnAddr); - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("Get82558LinkStatus(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ -/*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ - - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x112; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p32 = (PU32) pPab->pLinOutMsgBlock; - *p32 = 0xFFFFFFFF; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (*p32 != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link status\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - *ReturnAddr = *p32; /* 1 = up 0 = down */ - - return RC_RTN_NO_ERROR; - -} - -/* -** ========================================================================= -** RCGetMAC() -** -** get the MAC address the adapter is listening for in non-promiscous mode. -** MAC address is in media format. -** ========================================================================= -*/ -RC_RETURN -RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback) -{ - unsigned timeout; - U32 off; - PU8 mac = dev->dev_addr; - PU32 p; - U32 temp[2]; - PPAB pPab = ((PDPA) dev->priv)->pPab; - PATU p_atu; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - p_atu = pPab->p_atu; - - p_atu->EtherMacLow = 0; /* first zero return data */ - p_atu->EtherMacHi = 0; - - off = p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - p = (PU32) (pPab->pPci45LinBaseAddr + off); - - dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", - (uint) p_atu, (uint) off, (uint) p); - /* setup private message */ - p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - p[2] = 0; /* initiator context */ - p[3] = 0x218; /* transaction context */ - p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR; - - p_atu->InQueue = off; /* send it to the I2O device */ - dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", - (uint) p_atu, (uint) off, (uint) p); - - /* wait for the rcpci45 board to update the info */ - timeout = 1000000; - while (0 == p_atu->EtherMacLow) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { - printk ("rc_getmac: Timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - /* read the mac address */ - temp[0] = p_atu->EtherMacLow; - temp[1] = p_atu->EtherMacHi; - memcpy ((char *) mac, (char *) temp, 6); - - dprintk ("rc_getmac: 0x%x\n", (u32) mac); - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCSetMAC() -** -** set MAC address the adapter is listening for in non-promiscous mode. -** MAC address is in media format. -** ========================================================================= -*/ -RC_RETURN -RCSetMAC (struct net_device * dev, PU8 mac) -{ - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR; - pMsg[5] = *(unsigned *) mac; /* first four bytes */ - pMsg[6] = *(unsigned *) (mac + 4); /* last two bytes */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCSetLinkSpeed() -** -** set ethernet link speed. -** input: speedControl - determines action to take as follows -** 0 = reset and auto-negotiate (NWay) -** 1 = Full Duplex 100BaseT -** 2 = Half duplex 100BaseT -** 3 = Full Duplex 10BaseT -** 4 = Half duplex 10BaseT -** all other values are ignore (do nothing) -** ========================================================================= -*/ -RC_RETURN -RCSetLinkSpeed (struct net_device * dev, U16 LinkSpeedCode) -{ - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED; - pMsg[5] = LinkSpeedCode; /* link speed code */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCSetPromiscuousMode() -** -** Defined values for Mode: -** 0 - turn off promiscuous mode -** 1 - turn on promiscuous mode -** -** ========================================================================= -*/ -RC_RETURN -RCSetPromiscuousMode (struct net_device * dev, U16 Mode) -{ - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE; - pMsg[5] = Mode; /* promiscuous mode setting */ - - pPab->p_atu->InQueue = off; /* send it to the device */ - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCGetPromiscuousMode() -** -** get promiscuous mode setting -** -** Possible return values placed in pMode: -** 0 = promisuous mode not set -** 1 = promisuous mode is set -** -** ========================================================================= -*/ -RC_RETURN -RCGetPromiscuousMode (struct net_device * dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk - ("Timeout waiting for promiscuous mode from adapter\n"); - dprintk ("0x%8x\n", p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get mode */ - *pMode = (U8) ((volatile PU8) p32)[0] & 0x0f; - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCSetBroadcastMode() -** -** Defined values for Mode: -** 0 - turn off promiscuous mode -** 1 - turn on promiscuous mode -** -** ========================================================================= -*/ -RC_RETURN -RCSetBroadcastMode (struct net_device * dev, U16 Mode) -{ - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE; - pMsg[5] = Mode; /* promiscuous mode setting */ - - pPab->p_atu->InQueue = off; /* send it to the device */ - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCGetBroadcastMode() -** -** get promiscuous mode setting -** -** Possible return values placed in pMode: -** 0 = promisuous mode not set -** 1 = promisuous mode is set -** -** ========================================================================= -*/ -RC_RETURN -RCGetBroadcastMode (struct net_device * dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - printk (KERN_WARNING - "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); - printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n", - p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get mode */ - *pMode = (U8) ((volatile PU8) p32)[0] & 0x0f; - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCGetLinkSpeed() -** -** get ethernet link speed. -** -** 0 = Unknown -** 1 = Full Duplex 100BaseT -** 2 = Half duplex 100BaseT -** 3 = Full Duplex 10BaseT -** 4 = Half duplex 10BaseT -** -** ========================================================================= -*/ -RC_RETURN -RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - U8 IOPLinkSpeed; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); - dprintk ("0x%8x\n", p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get Link speed */ - IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f; - - *pLinkSpeedCode = IOPLinkSpeed; - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCReportDriverCapability(struct net_device *dev, U32 capability) -** -** Currently defined bits: -** WARM_REBOOT_CAPABLE 0x01 -** -** ========================================================================= -*/ -RC_RETURN -RCReportDriverCapability (struct net_device * dev, U32 capability) -{ - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = - RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY; - pMsg[5] = capability; - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCGetFirmwareVer() -** -** Return firmware version in the form "SoftwareVersion : Bt BootVersion" -** -** ========================================================================= -*/ -RC_RETURN -RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString, - PFNWAITCALLBACK WaitCallback) -{ - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - msgOffset = pPab->p_atu->InQueue; - if (msgOffset == 0xFFFFFFFF) { - dprintk ("RCGetFirmwareVer(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); - return RC_RTN_NO_FIRM_VER; - } - } - - strcpy (pFirmString, (PU8) p32); - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCResetLANCard() -** -** ResourceFlags indicates whether to return buffer resource explicitly -** to host or keep and reuse. -** CallbackFunction (if not NULL) is the function to be called when -** reset is complete. -** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when -** reset is done (if not NULL). -** -** ========================================================================= -*/ -RC_RETURN -RCResetLANCard (struct net_device * dev, U16 ResourceFlags, PU32 ReturnAddr, - PFNCALLBACK CallbackFunction) -{ - unsigned long off; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - long timeout = 0; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pPab->pCallbackFunc = CallbackFunction; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup message */ - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = ResourceFlags << 16; /* resource flags */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - if (CallbackFunction == (PFNCALLBACK) NULL) { - /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc - or until timer goes off */ - while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { - RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ - timeout++; - if (timeout > 10000) { - break; - } - } - if (ReturnAddr != (PU32) NULL) - *ReturnAddr = (U32) pPab->pCallbackFunc; - } - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCResetIOP() -** -** Send StatusGet Msg, wait for results return directly to buffer. -** -** ========================================================================= -*/ -RC_RETURN -RCResetIOP (struct net_device * dev) -{ - U32 msgOffset, timeout; - PU32 pMsg; - PPAB pPab = ((PDPA) dev->priv)->pPab; - volatile PU32 p32; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = 0; /* universal context */ - pMsg[3] = 0; /* universal context */ - pMsg[4] = 0; /* universal context */ - pMsg[5] = 0; /* universal context */ - /* phys address to return status - area right after PAB */ - pMsg[6] = pPab->outMsgBlockPhyAddr; - pMsg[7] = 0; - pMsg[8] = 1; /* return 1 byte */ - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0; - p32[1] = 0; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] || p32[1]) - break; - - if (!timeout--) { - dprintk ("RCResetIOP timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCShutdownLANCard() -** -** ResourceFlags indicates whether to return buffer resource explicitly -** to host or keep and reuse. -** CallbackFunction (if not NULL) is the function to be called when -** shutdown is complete. -** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when -** shutdown is done (if not NULL). -** -** ========================================================================= -*/ -RC_RETURN -RCShutdownLANCard (struct net_device * dev, U16 ResourceFlags, - PU32 ReturnAddr, PFNCALLBACK CallbackFunction) -{ - volatile PU32 pMsg; - U32 off; - PPAB pPab = ((PDPA) dev->priv)->pPab; - long timeout = 0; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pPab->pCallbackFunc = CallbackFunction; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup message */ - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = - I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = ResourceFlags << 16; /* resource flags */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - if (CallbackFunction == (PFNCALLBACK) NULL) { - /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc - or until timer goes off */ - while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { - RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ - timeout++; - if (timeout > 10000) { - printk (KERN_WARNING - "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); - break; - } - } - if (ReturnAddr != (PU32) NULL) - *ReturnAddr = (U32) pPab->pCallbackFunc; - } - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** RCSetRavlinIPandMask() -** -** Set the Ravlin 45/PCI cards IP address and network mask. -** -** IP address and mask must be in network byte order. -** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be -** 0x04030201 and 0x00FFFFFF on a little endian machine. -** -** ========================================================================= -*/ -RC_RETURN -RCSetRavlinIPandMask (struct net_device * dev, U32 ipAddr, U32 netMask) -{ - volatile PU32 pMsg; - U32 off; - PPAB pPab = ((PDPA) dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK; - pMsg[5] = ipAddr; - pMsg[6] = netMask; - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - return RC_RTN_NO_ERROR; - -} - -/* -** ========================================================================= -** RCGetRavlinIPandMask() -** -** get the IP address and MASK from the card -** -** ========================================================================= -*/ -RC_RETURN -RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask, - PFNWAITCALLBACK WaitCallback) -{ - unsigned timeout; - U32 off; - PU32 pMsg, p32; - PPAB pPab = ((PDPA) dev->priv)->pPab; - PATU p_atu; - - dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", - (u32) pIpAddr, *pIpAddr); - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - p_atu = pPab->p_atu; - off = p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - *p32 = 0xFFFFFFFF; - - pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); - - dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", - (u32) p_atu, off, (u32) p32); - /* setup private message */ - pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x218; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p_atu->InQueue = off; /* send it to the I2O device */ - dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", - (u32) p_atu, off, (u32) p32); - - /* wait for the rcpci45 board to update the info */ - timeout = 100000; - while (0xffffffff == *p32) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { - dprintk ("RCGetRavlinIPandMask: Timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - dprintk - ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", - p32[0], p32[1]); - - /* send IP and mask to user's space */ - *pIpAddr = p32[0]; - *pNetMask = p32[1]; - - dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", - (u32) pIpAddr, *pIpAddr); - - return RC_RTN_NO_ERROR; -} - -/* -** ///////////////////////////////////////////////////////////////////////// -** ///////////////////////////////////////////////////////////////////////// -** -** local functions -** -** ///////////////////////////////////////////////////////////////////////// -** ///////////////////////////////////////////////////////////////////////// -*/ - -/* -** ========================================================================= -** SendI2OOutboundQInitMsg() -** -** ========================================================================= -*/ -static int -SendI2OOutboundQInitMsg (PPAB pPab) -{ - U32 msgOffset, timeout, phyOutQFrames, i; - volatile PU32 pMsg; - volatile PU32 p32; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - dprintk - ("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", - (u32) pMsg, msgOffset); - - pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; - pMsg[1] = - I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x106; /* transaction context */ - pMsg[4] = 4096; /* Host page frame size */ - pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */ - pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */ - /* phys address to return status - area right after PAB */ - pMsg[7] = pPab->outMsgBlockPhyAddr; - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (PU32) pPab->pLinOutMsgBlock; - p32[0] = 0; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0]) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ InPrgress status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } - } - - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ Complete status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } - } - - /* load PCI outbound free Q with MF physical addresses */ - phyOutQFrames = pPab->outMsgBlockPhyAddr; - - for (i = 0; i < NMBR_MSG_FRAMES; i++) { - pPab->p_atu->OutQueue = phyOutQFrames; - phyOutQFrames += MSG_FRAME_SIZE; - } - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** GetI2OStatus() -** -** Send StatusGet Msg, wait for results return directly to buffer. -** -** ========================================================================= -*/ -static int -GetI2OStatus (PPAB pPab) -{ - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - - msgOffset = pPab->p_atu->InQueue; - dprintk ("GetI2OStatus: msg offset = 0x%x\n", msgOffset); - if (msgOffset == 0xFFFFFFFF) { - dprintk ("GetI2OStatus(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = 0; /* universal context */ - pMsg[3] = 0; /* universal context */ - pMsg[4] = 0; /* universal context */ - pMsg[5] = 0; /* universal context */ - /* phys address to return status - area right after PAB */ - pMsg[6] = pPab->outMsgBlockPhyAddr; - pMsg[7] = 0; - pMsg[8] = 88; /* return 88 bytes */ - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32) pPab->pLinOutMsgBlock; - p32[0] = 0; - p32[1] = 0; - - dprintk - ("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", - (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32); - - /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] && p32[1]) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for status from IOP\n"); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); - return RC_RTN_NO_I2O_STATUS; - } - } - - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], - p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], - p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], - p32[10], p32[11]); - /* get IOP state */ - pPab->IOPState = ((volatile PU8) p32)[10]; - pPab->InboundMFrameSize = ((volatile PU16) p32)[6]; - - dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n", - pPab->IOPState, pPab->InboundMFrameSize); - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** SendEnableSysMsg() -** -** -** ========================================================================= -*/ -static int -SendEnableSysMsg (PPAB pPab) -{ - U32 msgOffset; - volatile PU32 pMsg; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) { - dprintk ("SendEnableSysMsg(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - - dprintk - ("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", - (u32) pMsg, msgOffset); - - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x110; /* transaction context */ - pMsg[4] = 0x50657465; /* RedCreek Private */ - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - return RC_RTN_NO_ERROR; -} - -/* -** ========================================================================= -** FillI2OMsgFromTCB() -** -** inputs pMsgU32 - virtual pointer (mapped to physical) of message frame -** pXmitCntrlBlock - pointer to caller buffer control block. -** -** fills in LAN SGL after Transaction Control Word or Bucket Count. -** ========================================================================= -*/ -static int -FillI2OMsgSGLFromTCB (PU32 pMsgFrame, PRCTCB pTransCtrlBlock) -{ - unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags; - PU32 pTCB, pMsg; - - /* SGL element flags */ -#define EOB 0x40000000 -#define LE 0x80000000 -#define SIMPLE_SGL 0x10000000 -#define BC_PRESENT 0x01000000 - - pTCB = (PU32) pTransCtrlBlock; - pMsg = pMsgFrame; - nmbrDwords = 0; - - dprintk ("FillI2OMsgSGLFromTCBX\n"); - dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); - dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg); - - nmbrBuffers = *pTCB++; - - if (!nmbrBuffers) { - return -1; - } - - do { - context = *pTCB++; /* buffer tag (context) */ - nmbrSeg = *pTCB++; /* number of segments */ - - if (!nmbrSeg) { - return -1; - } - - flags = SIMPLE_SGL | BC_PRESENT; - - if (1 == nmbrSeg) { - flags |= EOB; - - if (1 == nmbrBuffers) - flags |= LE; - } - - /* 1st SGL buffer element has context */ - pMsg[0] = pTCB[0] | flags; /* send over count (segment size) */ - pMsg[1] = context; - pMsg[2] = pTCB[1]; /* send buffer segment physical address */ - nmbrDwords += 3; - pMsg += 3; - pTCB += 2; - - if (--nmbrSeg) { - do { - flags = SIMPLE_SGL; - - if (1 == nmbrSeg) { - flags |= EOB; - - if (1 == nmbrBuffers) - flags |= LE; - } - - pMsg[0] = pTCB[0] | flags; /* send over count */ - pMsg[1] = pTCB[1]; /* send buffer segment physical address */ - nmbrDwords += 2; - pTCB += 2; - pMsg += 2; - - } while (--nmbrSeg); - } - - } while (--nmbrBuffers); - - return nmbrDwords; -} - -/* -** ========================================================================= -** ProcessOutboundI2OMsg() -** -** process I2O reply message -** * change to msg structure * -** ========================================================================= -*/ -static void -ProcessOutboundI2OMsg (PPAB pPab, U32 phyAddrMsg) -{ - PU8 p8Msg; - PU32 p32; -/* U16 count; */ - - p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); - p32 = (PU32) p8Msg; - - dprintk - ("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", - (u32) pPab, phyAddrMsg, (u32) p8Msg); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], - p32[2], p32[3]); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], - p32[6], p32[7]); - - if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { - dprintk ("Message reply status not success\n"); - return; - } - - switch (p8Msg[7]) { /* function code byte */ - case I2O_EXEC_SYS_TAB_SET: - msgFlag = 1; - dprintk ("Received I2O_EXEC_SYS_TAB_SET reply\n"); - break; - - case I2O_EXEC_HRT_GET: - msgFlag = 1; - dprintk ("Received I2O_EXEC_HRT_GET reply\n"); - break; - - case I2O_EXEC_LCT_NOTIFY: - msgFlag = 1; - dprintk ("Received I2O_EXEC_LCT_NOTIFY reply\n"); - break; - - case I2O_EXEC_SYS_ENABLE: - msgFlag = 1; - dprintk ("Received I2O_EXEC_SYS_ENABLE reply\n"); - break; - - default: - dprintk ("Received UNKNOWN reply\n"); - break; - } -} diff --git a/drivers/net/rclanmtl.h b/drivers/net/rclanmtl.h deleted file mode 100644 index 9488c0fd5..000000000 --- a/drivers/net/rclanmtl.h +++ /dev/null @@ -1,701 +0,0 @@ -/* -** ************************************************************************* -** -** -** R C L A N M T L . H $Revision: 6 $ -** -** -** RedCreek I2O LAN Message Transport Layer header file. -** -** --------------------------------------------------------------------- -** --- Copyright (c) 1997-1999, RedCreek Communications Inc. --- -** --- All rights reserved. --- -** --------------------------------------------------------------------- -** -** File Description: -** -** Header file for host I2O (Intelligent I/O) LAN message transport layer -** API and data types. -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. - -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. - -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -** ************************************************************************* -*/ - -#ifndef RCLANMTL_H -#define RCLANMTL_H - -/* Linux specific includes */ -#include -#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */ -#include -#else -#include -#endif -#include /* for udelay() */ - -#include -#include -#include -#include - -#include - -/* Debug stuff. Define for debug output */ -#undef RCDEBUG - -#ifdef RCDEBUG -#define dprintk(args...) printk(KERN_DEBUG "rc: " args) -#else -#define dprintk(args...) { } -#endif - -/* Typedefs */ - - /* scalar data types */ -typedef __u8 U8; -typedef __u16 U16; -typedef __u32 U32; -typedef __u8 *PU8; -typedef __u16 *PU16; -typedef __u32 *PU32; -typedef unsigned long BF; -typedef int RC_RETURN; - - /* - ** type PFNWAITCALLBACK - ** - ** pointer to void function - type used for WaitCallback in some functions - */ -typedef void (*PFNWAITCALLBACK) (void); /* void argument avoids compiler complaint */ - - /* - ** type PFNTXCALLBACK - ** - ** Pointer to user's transmit callback function. This user function is - ** called from RCProcI2OMsgQ() when packet have been transmitted from buffers - ** given in the RCI2OSendPacket() function. BufferContext is a pointer to - ** an array of 32 bit context values. These are the values the user assigned - ** and passed in the TCB to the RCI2OSendPacket() function. PcktCount - ** indicates the number of buffer context values in the BufferContext[] array. - ** The User's TransmitCallbackFunction should recover (put back in free queue) - ** the packet buffers associated with the buffer context values. - */ -typedef void (*PFNTXCALLBACK) (U32 Status, - U16 PcktCount, - PU32 BufferContext, struct net_device *); - - /* - ** type PFNRXCALLBACK - ** - ** Pointer to user's receive callback function. This user function - ** is called from RCProcI2OMsgQ() when packets have been received into - ** previously posted packet buffers throught the RCPostRecvBuffers() function. - ** The received callback function should process the Packet Descriptor Block - ** pointed to by PacketDescBlock. See Packet Decription Block below. - */ -typedef void (*PFNRXCALLBACK) (U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, struct net_device *); - - /* - ** type PFNCALLBACK - ** - ** Pointer to user's generic callback function. This user function - ** can be passed to LANReset or LANShutdown and is called when the - ** the reset or shutdown is complete. - ** Param1 and Param2 are invalid for LANReset and LANShutdown. - */ -typedef void (*PFNCALLBACK) (U32 Status, - U32 Param1, U32 Param2, struct net_device * dev); - -/* -** Message Unit CSR definitions for RedCreek PCI45 board -*/ -typedef struct tag_rcatu { - volatile unsigned long APICRegSel; /* APIC Register Select */ - volatile unsigned long reserved0; - volatile unsigned long APICWinReg; /* APIC Window Register */ - volatile unsigned long reserved1; - volatile unsigned long InMsgReg0; /* inbound message register 0 */ - volatile unsigned long InMsgReg1; /* inbound message register 1 */ - volatile unsigned long OutMsgReg0; /* outbound message register 0 */ - volatile unsigned long OutMsgReg1; /* outbound message register 1 */ - volatile unsigned long InDoorReg; /* inbound doorbell register */ - volatile unsigned long InIntStat; /* inbound interrupt status register */ - volatile unsigned long InIntMask; /* inbound interrupt mask register */ - volatile unsigned long OutDoorReg; /* outbound doorbell register */ - volatile unsigned long OutIntStat; /* outbound interrupt status register */ - volatile unsigned long OutIntMask; /* outbound interrupt mask register */ - volatile unsigned long reserved2; - volatile unsigned long reserved3; - volatile unsigned long InQueue; /* inbound queue port */ - volatile unsigned long OutQueue; /* outbound queue port */ - volatile unsigned long reserved4; - volatile unsigned long reserver5; - /* RedCreek extension */ - volatile unsigned long EtherMacLow; - volatile unsigned long EtherMacHi; - volatile unsigned long IPaddr; - volatile unsigned long IPmask; -} *PATU; - - /* - ** typedef PAB - ** - ** PCI Adapter Block - holds instance specific information. - */ -typedef struct { - PATU p_atu; /* ptr to ATU register block */ - PU8 pPci45LinBaseAddr; - PU8 pLinOutMsgBlock; - U32 outMsgBlockPhyAddr; - PFNTXCALLBACK pTransCallbackFunc; - PFNRXCALLBACK pRecvCallbackFunc; - PFNCALLBACK pRebootCallbackFunc; - PFNCALLBACK pCallbackFunc; - U16 IOPState; - U16 InboundMFrameSize; -} *PPAB; - -/* - * Driver Private Area, DPA. - */ -typedef struct { - U8 id; /* the AdapterID */ - - /* These two field are basically for the RCioctl function. - * I could not determine if they could be avoided. (RAA)*/ - U32 pci_addr; /* the pci address of the adapter */ - U32 pci_addr_len; - - struct pci_dev *pci_dev; - struct timer_list timer; /* timer */ - struct net_device_stats stats; /* the statistics structure */ - unsigned long numOutRcvBuffers; /* number of outstanding receive buffers */ - unsigned char shutdown; - unsigned char reboot; - unsigned char nexus; - PU8 msgbuf; /* Pointer to Lan Api Private Area */ - dma_addr_t msgbuf_dma; - PPAB pPab; /* Pointer to the PCI Adapter Block */ -} *PDPA; - -/* PCI/45 Configuration space values */ -#define RC_PCI45_VENDOR_ID 0x4916 -#define RC_PCI45_DEVICE_ID 0x1960 - - /* RedCreek API function return values */ -#define RC_RTN_NO_ERROR 0 -#define RC_RTN_I2O_NOT_INIT 1 -#define RC_RTN_FREE_Q_EMPTY 2 -#define RC_RTN_TCB_ERROR 3 -#define RC_RTN_TRANSACTION_ERROR 4 -#define RC_RTN_ADAPTER_ALREADY_INIT 5 -#define RC_RTN_MALLOC_ERROR 6 -#define RC_RTN_ADPTR_NOT_REGISTERED 7 -#define RC_RTN_MSG_REPLY_TIMEOUT 8 -#define RC_RTN_NO_I2O_STATUS 9 -#define RC_RTN_NO_FIRM_VER 10 -#define RC_RTN_NO_LINK_SPEED 11 - -/* Driver capability flags */ -#define WARM_REBOOT_CAPABLE 0x01 - -/* -** Status - Transmit and Receive callback status word -** -** A 32 bit Status is returned to the TX and RX callback functions. This value -** contains both the reply status and the detailed status as follows: -** -** 32 24 16 0 -** +------+------+------------+ -** | Reply| | Detailed | -** |Status| 0 | Status | -** +------+------+------------+ -** -** Reply Status and Detailed Status of zero indicates No Errors. -*/ - /* reply message status defines */ -#define I2O_REPLY_STATUS_SUCCESS 0x00 -#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 -#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A - -/* DetailedStatusCode defines */ -#define I2O_LAN_DSC_SUCCESS 0x0000 -#define I2O_LAN_DSC_DEVICE_FAILURE 0x0001 -#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x0002 -#define I2O_LAN_DSC_TRANSMIT_ERROR 0x0003 -#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x0004 -#define I2O_LAN_DSC_RECEIVE_ERROR 0x0005 -#define I2O_LAN_DSC_RECEIVE_ABORTED 0x0006 -#define I2O_LAN_DSC_DMA_ERROR 0x0007 -#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x0008 -#define I2O_LAN_DSC_OUT_OF_MEMORY 0x0009 -#define I2O_LAN_DSC_BUCKET_OVERRUN 0x000A -#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x000B -#define I2O_LAN_DSC_CANCELED 0x000C -#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x000D -#define I2O_LAN_DSC_DESTINATION_ADDRESS_DETECTED 0x000E -#define I2O_LAN_DSC_DESTINATION_ADDRESS_OMITTED 0x000F -#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x0010 - -/* -** Packet Description Block (Received packets) -** -** A pointer to this block structure is returned to the ReceiveCallback -** function. It contains the list of packet buffers which have either been -** filled with a packet or returned to host due to a LANReset function. -** Currently there will only be one packet per receive bucket (buffer) posted. -** -** 32 24 0 -** +-----------------------+ -\ -** | Buffer 1 Context | \ -** +-----------------------+ \ -** | 0xC0000000 | / First Bucket Descriptor -** +-----+-----------------+ / -** | 0 | packet 1 length | / -** +-----------------------+ -\ -** | Buffer 2 Context | \ -** +-----------------------+ \ -** | 0xC0000000 | / Second Bucket Descriptor -** +-----+-----------------+ / -** | 0 | packet 2 length | / -** +-----+-----------------+ - -** | ... | ----- more bucket descriptors -** +-----------------------+ -\ -** | Buffer n Context | \ -** +-----------------------+ \ -** | 0xC0000000 | / Last Bucket Descriptor -** +-----+-----------------+ / -** | 0 | packet n length | / -** +-----+-----------------+ - -** -** Buffer Context values are those given to adapter in the TCB on calls to -** RCPostRecvBuffers(). -** -*/ - -/* -** Transaction Control Block (TCB) structure -** -** A structure like this is filled in by the user and passed by reference to -** RCI2OSendPacket() and RCPostRecvBuffers() functions. Minimum size is five -** 32-bit words for one buffer with one segment descriptor. -** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers -** that can be described in a given TCB. -** -** 32 0 -** +-----------------------+ -** | Buffer Count | Number of buffers in the TCB -** +-----------------------+ -** | Buffer 1 Context | first buffer reference -** +-----------------------+ -** | Buffer 1 Seg Count | number of segments in buffer -** +-----------------------+ -** | Buffer 1 Seg Desc 1 | first segment descriptor (size, physical address) -** +-----------------------+ -** | ... | more segment descriptors (size, physical address) -** +-----------------------+ -** | Buffer 1 Seg Desc n | last segment descriptor (size, physical address) -** +-----------------------+ -** | Buffer 2 Context | second buffer reference -** +-----------------------+ -** | Buffer 2 Seg Count | number of segments in buffer -** +-----------------------+ -** | Buffer 2 Seg Desc 1 | segment descriptor (size, physical address) -** +-----------------------+ -** | ... | more segment descriptors (size, physical address) -** +-----------------------+ -** | Buffer 2 Seg Desc n | -** +-----------------------+ -** | ... | more buffer descriptor blocks ... -** +-----------------------+ -** | Buffer n Context | -** +-----------------------+ -** | Buffer n Seg Count | -** +-----------------------+ -** | Buffer n Seg Desc 1 | -** +-----------------------+ -** | ... | -** +-----------------------+ -** | Buffer n Seg Desc n | -** +-----------------------+ -** -** -** A TCB for one contigous packet buffer would look like the following: -** -** 32 0 -** +-----------------------+ -** | 1 | one buffer in the TCB -** +-----------------------+ -** | | user's buffer reference -** +-----------------------+ -** | 1 | one segment buffer -** +-----------------------+ _ -** | | size \ -** +-----------------------+ \ segment descriptor -** | | physical address of buffer / -** +-----------------------+ _/ -** -*/ - - /* Buffer Segment Descriptor */ -typedef struct { - U32 size; - U32 phyAddress; -} BSD, *PBSD; - -typedef PU32 PRCTCB; -/* -** ------------------------------------------------------------------------- -** Exported functions comprising the API to the LAN I2O message transport layer -** ------------------------------------------------------------------------- -*/ - - /* - ** InitRCI2OMsgLayer() - ** - ** Called once prior to using the I2O LAN message transport layer. User - ** provides both the physical and virual address of a locked page buffer - ** that is used as a private buffer for the RedCreek I2O message - ** transport layer. This buffer must be a contigous memory block of a - ** minimum of 16K bytes and long word aligned. The user also must provide - ** the base address of the RedCreek PCI adapter assigned by BIOS or operating - ** system. - ** - ** Inputs: dev - the net_device struct for the device. - ** TransmitCallbackFunction - address of user's TX callback function - ** ReceiveCallbackFunction - address of user's RX callback function - ** RebootCallbackFunction - address of user's reboot callback function - ** - */ -RC_RETURN RCInitI2OMsgLayer (struct net_device *dev, - PFNTXCALLBACK TransmitCallbackFunction, - PFNRXCALLBACK ReceiveCallbackFunction, - PFNCALLBACK RebootCallbackFunction); - - /* - ** RCSetRavlinIPandMask() - ** - ** Set the Ravlin 45/PCI cards IP address and network mask. - ** - ** IP address and mask must be in network byte order. - ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be - ** 0x04030201 and 0x00FFFFFF on a little endian machine. - ** - */ -RC_RETURN RCSetRavlinIPandMask (struct net_device *dev, U32 ipAddr, - U32 netMask); - -/* -** ========================================================================= -** RCGetRavlinIPandMask() -** -** get the IP address and MASK from the card -** -** ========================================================================= -*/ -RC_RETURN -RCGetRavlinIPandMask (struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, - PFNWAITCALLBACK WaitCallback); - - /* - ** RCProcI2OMsgQ() - ** - ** Called from user's polling loop or Interrupt Service Routine for a PCI - ** interrupt from the RedCreek PCI adapter. User responsible for determining - ** and hooking the PCI interrupt. This function will call the registered - ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction, - ** if a TX or RX transaction has completed. - */ -irqreturn_t RCProcI2OMsgQ (struct net_device *dev); - - /* - ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time - ** but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted received buffers and packets will - ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts - ** will prevent hardware interrupt to host even though the outbound I2O msg - ** queue is not emtpy. - */ -RC_RETURN RCEnableI2OInterrupts (struct net_device *dev); -RC_RETURN RCDisableI2OInterrupts (struct net_device *dev); - - /* - ** RCPostRecvBuffers() - ** - ** Post user's page locked buffers for use by the PCI adapter to - ** return ethernet packets received from the LAN. Transaction Control Block, - ** provided by user, contains buffer descriptor(s) which includes a buffer - ** context number along with buffer size and physical address. See TCB above. - ** The buffer context and actual packet length are returned to the - ** ReceiveCallbackFunction when packets have been received. Buffers posted - ** to the RedCreek adapter are considered owned by the adapter until the - ** context is return to user through the ReceiveCallbackFunction. - */ -RC_RETURN RCPostRecvBuffers (struct net_device *dev, - PRCTCB pTransactionCtrlBlock); -#define MAX_NMBR_POST_BUFFERS_PER_MSG 32 - - /* - ** RCI2OSendPacket() - ** - ** Send user's ethernet packet from a locked page buffer. - ** Packet must have full MAC header, however without a CRC. - ** Initiator context is a user provided value that is returned - ** to the TransmitCallbackFunction when packet buffer is free. - ** Transmit buffer are considered owned by the adapter until context's - ** returned to user through the TransmitCallbackFunction. - */ -RC_RETURN RCI2OSendPacket (struct net_device *dev, - U32 context, PRCTCB pTransactionCtrlBlock); - - /* Ethernet Link Statistics structure */ -typedef struct tag_RC_link_stats { - U32 TX_good; /* good transmit frames */ - U32 TX_maxcol; /* frames not TX due to MAX collisions */ - U32 TX_latecol; /* frames not TX due to late collisions */ - U32 TX_urun; /* frames not TX due to DMA underrun */ - U32 TX_crs; /* frames TX with lost carrier sense */ - U32 TX_def; /* frames deferred due to activity on link */ - U32 TX_singlecol; /* frames TX with one and only on collision */ - U32 TX_multcol; /* frames TX with more than one collision */ - U32 TX_totcol; /* total collisions detected during TX */ - U32 Rcv_good; /* good frames received */ - U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */ - U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */ - U32 Rcv_reserr; /* good frames discarded due to no RX buffer */ - U32 Rcv_orun; /* RX frames lost due to FIFO overrun */ - U32 Rcv_cdt; /* RX frames with collision during RX */ - U32 Rcv_runt; /* RX frames shorter than 64 bytes */ -} RCLINKSTATS, *P_RCLINKSTATS; - - /* - ** RCGetLinkStatistics() - ** - ** Returns link statistics in user's structure at address StatsReturnAddr - ** If given, not NULL, the function WaitCallback is called during the wait - ** loop while waiting for the adapter to respond. - */ -RC_RETURN RCGetLinkStatistics (struct net_device *dev, - P_RCLINKSTATS StatsReturnAddr, - PFNWAITCALLBACK WaitCallback); - - /* - ** RCGetLinkStatus() - ** - ** Return link status, up or down, to user's location addressed by ReturnAddr. - ** If given, not NULL, the function WaitCallback is called during the wait - ** loop while waiting for the adapter to respond. - */ -RC_RETURN RCGetLinkStatus (struct net_device *dev, - PU32 pReturnStatus, PFNWAITCALLBACK WaitCallback); - - /* Link Status defines - value returned in pReturnStatus */ -#define RC_LAN_LINK_STATUS_DOWN 0 -#define RC_LAN_LINK_STATUS_UP 1 - - /* - ** RCGetMAC() - ** - ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI - ** has two MAC addresses. One which is private to the PCI Card, and - ** another MAC which is given to the user as its link layer MAC address. The - ** adapter runs in promiscous mode because of the dual address requirement. - ** The MAC address is returned to the unsigned char array pointer to by mac. - */ -RC_RETURN RCGetMAC (struct net_device *dev, PFNWAITCALLBACK WaitCallback); - - /* - ** RCSetMAC() - ** - ** Set a new user port MAC address. This address will be returned on - ** subsequent RCGetMAC() calls. - */ -RC_RETURN RCSetMAC (struct net_device *dev, PU8 mac); - - /* - ** RCSetLinkSpeed() - ** - ** set adapter's link speed based on given input code. - */ -RC_RETURN RCSetLinkSpeed (struct net_device *dev, U16 LinkSpeedCode); - /* Set link speed codes */ -#define LNK_SPD_AUTO_NEG_NWAY 0 -#define LNK_SPD_100MB_FULL 1 -#define LNK_SPD_100MB_HALF 2 -#define LNK_SPD_10MB_FULL 3 -#define LNK_SPD_10MB_HALF 4 - - /* - ** RCGetLinkSpeed() - ** - ** Return link speed code. - */ - /* Return link speed codes */ -#define LNK_SPD_UNKNOWN 0 -#define LNK_SPD_100MB_FULL 1 -#define LNK_SPD_100MB_HALF 2 -#define LNK_SPD_10MB_FULL 3 -#define LNK_SPD_10MB_HALF 4 - -RC_RETURN -RCGetLinkSpeed (struct net_device *dev, PU32 pLinkSpeedCode, - PFNWAITCALLBACK WaitCallback); -/* -** ========================================================================= -** RCSetPromiscuousMode(struct net_device *dev, U16 Mode) -** -** Defined values for Mode: -** 0 - turn off promiscuous mode -** 1 - turn on promiscuous mode -** -** ========================================================================= -*/ -#define PROMISCUOUS_MODE_OFF 0 -#define PROMISCUOUS_MODE_ON 1 -RC_RETURN RCSetPromiscuousMode (struct net_device *dev, U16 Mode); -/* -** ========================================================================= -** RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) -** -** get promiscuous mode setting -** -** Possible return values placed in pMode: -** 0 = promisuous mode not set -** 1 = promisuous mode is set -** -** ========================================================================= -*/ -RC_RETURN -RCGetPromiscuousMode (struct net_device *dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback); - -/* -** ========================================================================= -** RCSetBroadcastMode(struct net_device *dev, U16 Mode) -** -** Defined values for Mode: -** 0 - turn off promiscuous mode -** 1 - turn on promiscuous mode -** -** ========================================================================= -*/ -#define BROADCAST_MODE_OFF 0 -#define BROADCAST_MODE_ON 1 -RC_RETURN RCSetBroadcastMode (struct net_device *dev, U16 Mode); -/* -** ========================================================================= -** RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) -** -** get broadcast mode setting -** -** Possible return values placed in pMode: -** 0 = broadcast mode not set -** 1 = broadcast mode is set -** -** ========================================================================= -*/ -RC_RETURN -RCGetBroadcastMode (struct net_device *dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback); -/* -** ========================================================================= -** RCReportDriverCapability(struct net_device *dev, U32 capability) -** -** Currently defined bits: -** WARM_REBOOT_CAPABLE 0x01 -** -** ========================================================================= -*/ -RC_RETURN RCReportDriverCapability (struct net_device *dev, U32 capability); - -/* -** RCGetFirmwareVer() -** -** Return firmware version in the form "SoftwareVersion : Bt BootVersion" -** -** WARNING: user's space pointed to by pFirmString should be at least 60 bytes. -*/ -RC_RETURN -RCGetFirmwareVer (struct net_device *dev, PU8 pFirmString, - PFNWAITCALLBACK WaitCallback); - -/* -** ---------------------------------------------- -** LAN adapter Reset and Shutdown functions -** ---------------------------------------------- -*/ - /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */ -#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001 -#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002 - - /* - ** RCResetLANCard() - ** - ** Reset LAN card operation. Causes a software reset of the ethernet - ** controller and restarts the command and receive units. Depending on - ** the ResourceFlags given, the buffers are either returned to the - ** host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and - ** detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be - ** posted after issuing this) OR the buffers are kept and reused by - ** the ethernet controller. If CallbackFunction is not NULL, the function - ** will be called when the reset is complete. If the CallbackFunction is - ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset - ** to complete (please disable I2O interrupts during this method). - ** Any outstanding transmit or receive buffers that are complete will be - ** returned via the normal reply messages before the requested resource - ** buffers are returned. - ** A call to RCPostRecvBuffers() is needed to return the ethernet to full - ** operation if the receive buffers were returned during LANReset. - ** Note: The IOP status is not affected by a LAN reset. - */ -RC_RETURN RCResetLANCard (struct net_device *dev, U16 ResourceFlags, - PU32 ReturnAddr, PFNCALLBACK CallbackFunction); - - /* - ** RCShutdownLANCard() - ** - ** Shutdown LAN card operation and put into an idle (suspended) state. - ** The LAN card is restarted with RCResetLANCard() function. - ** Depending on the ResourceFlags given, the buffers are either returned - ** to the host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER - ** and detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be - ** posted after issuing this) OR the buffers are kept and reused by - ** the ethernet controller. If CallbackFunction is not NULL, the function - ** will be called when the reset is complete. If the CallbackFunction is - ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset - ** to complete (please disable I2O interrupts during this method). - ** Any outstanding transmit or receive buffers that are complete will be - ** returned via the normal reply messages before the requested resource - ** buffers are returned. - ** Note: The IOP status is not affected by a LAN shutdown. - */ -RC_RETURN -RCShutdownLANCard (struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, - PFNCALLBACK CallbackFunction); - - /* - ** RCResetIOP(); - ** Initializes IOPState to I2O_IOP_STATE_RESET. - ** Stops access to outbound message Q. - ** Discards any outstanding transmit or posted receive buffers. - ** Clears outbound message Q. - */ -RC_RETURN RCResetIOP (struct net_device *dev); - -#endif /* RCLANMTL_H */ diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c deleted file mode 100644 index 76b63f31b..000000000 --- a/drivers/net/rcpci45.c +++ /dev/null @@ -1,1049 +0,0 @@ -/* -** -** RCpci45.c -** -** -** -** --------------------------------------------------------------------- -** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. --- -** --- All rights reserved. --- -** --------------------------------------------------------------------- -** -** Written by Pete Popov and Brian Moyle. -** -** Known Problems -** -** None known at this time. -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. - -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. - -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -** Francois Romieu, Apr 2003: Converted to pci DMA mapping API. -** -** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional -** again. Note that this card is not supported or manufactured by -** RedCreek anymore. -** -** Rasmus Andersen, December 2000: Converted to new PCI API and general -** cleanup. -** -** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems -** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and -** added a #define(s) to enable the use of the same file for both, the 2.0.x -** kernels as well as the 2.1.x. -** -** Ported to 2.1.x by Alan Cox 1998/12/9. -** -** Sometime in mid 1998, written by Pete Popov and Brian Moyle. -** -***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* For NR_IRQS only. */ -#include -#include - -static char version[] __initdata = - "RedCreek Communications PCI linux driver version 2.21\n"; - -#define RC_LINUX_MODULE -#include "rclanmtl.h" -#include "rcif.h" - -#define RUN_AT(x) (jiffies + (x)) - -#define NEW_MULTICAST - -#define MAX_ETHER_SIZE 1520 -#define MAX_NMBR_RCV_BUFFERS 96 -#define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16 -#define BD_SIZE 3 /* Bucket Descriptor size */ -#define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */ - -/* RedCreek LAN device Target ID */ -#define RC_LAN_TARGET_ID 0x10 -/* RedCreek's OSM default LAN receive Initiator */ -#define DEFAULT_RECV_INIT_CONTEXT 0xA17 - -/* minimum msg buffer size needed by the card - * Note that the size of this buffer is hard code in the - * ipsec card's firmware. Thus, the size MUST be a minimum - * of 16K. Otherwise the card will end up using memory - * that does not belong to it. - */ -#define MSG_BUF_SIZE 16384 - -/* 2003/04/20: I don't know about the hardware ability but the driver won't - * play safe with 64 bit addressing and DAC without NETIF_F_HIGHDMA doesn't - * really make sense anyway. Let's play safe - romieu. - */ -#define RCPCI45_DMA_MASK ((u64) 0xffffffff) - -static U32 DriverControlWord; - -static void rc_timer (unsigned long); - -static int RCopen (struct net_device *); -static int RC_xmit_packet (struct sk_buff *, struct net_device *); -static irqreturn_t RCinterrupt (int, void *, struct pt_regs *); -static int RCclose (struct net_device *dev); -static struct net_device_stats *RCget_stats (struct net_device *); -static int RCioctl (struct net_device *, struct ifreq *, int); -static int RCconfig (struct net_device *, struct ifmap *); -static void RCxmit_callback (U32, U16, PU32, struct net_device *); -static void RCrecv_callback (U32, U8, U32, PU32, struct net_device *); -static void RCreset_callback (U32, U32, U32, struct net_device *); -static void RCreboot_callback (U32, U32, U32, struct net_device *); -static int RC_allocate_and_post_buffers (struct net_device *, int); - -static struct pci_device_id rcpci45_pci_table[] = { - { PCI_VENDOR_ID_REDCREEK, PCI_DEVICE_ID_RC45, PCI_ANY_ID, PCI_ANY_ID,}, - {} -}; -MODULE_DEVICE_TABLE (pci, rcpci45_pci_table); -MODULE_LICENSE("GPL"); - -static void __devexit -rcpci45_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - PDPA pDpa = dev->priv; - - RCResetIOP (dev); - unregister_netdev (dev); - free_irq (dev->irq, dev); - iounmap ((void *) dev->base_addr); - pci_release_regions (pdev); - pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf, - pDpa->msgbuf_dma); - if (pDpa->pPab) - kfree (pDpa->pPab); - free_netdev (dev); - pci_set_drvdata (pdev, NULL); -} - -static int -rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -{ - unsigned long *vaddr; - PDPA pDpa; - int error; - static int card_idx = -1; - struct net_device *dev; - unsigned long pci_start, pci_len; - - card_idx++; - - /* - * Allocate and fill new device structure. - * We need enough for struct net_device plus DPA plus the LAN - * API private area, which requires a minimum of 16KB. The top - * of the allocated area will be assigned to struct net_device; - * the next chunk will be assigned to DPA; and finally, the rest - * will be assigned to the LAN API layer. - */ - - dev = alloc_etherdev(sizeof(*pDpa)); - if (!dev) { - printk (KERN_ERR - "(rcpci45 driver:) alloc_etherdev alloc failed\n"); - error = -ENOMEM; - goto err_out; - } - - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - error = pci_enable_device (pdev); - if (error) { - printk (KERN_ERR - "(rcpci45 driver:) %d: pci enable device error\n", - card_idx); - goto err_out; - } - pci_start = pci_resource_start (pdev, 0); - pci_len = pci_resource_len (pdev, 0); - printk("pci_start %lx pci_len %lx\n", pci_start, pci_len); - - pci_set_drvdata (pdev, dev); - - pDpa = dev->priv; - pDpa->id = card_idx; - pDpa->pci_dev = pdev; - pDpa->pci_addr = pci_start; - - if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { - printk (KERN_ERR - "(rcpci45 driver:) No PCI mem resources! Aborting\n"); - error = -EBUSY; - goto err_out_free_dev; - } - - /* - * pDpa->msgbuf is where the card will dma the I2O - * messages. Thus, we need contiguous physical pages of memory. - * 2003/04/20: pci_alloc_consistent() provides well over the needed - * alignment on a 256 bytes boundary for the LAN API private area. - * Thus it isn't needed anymore to align it by hand. - */ - pDpa->msgbuf = pci_alloc_consistent (pdev, MSG_BUF_SIZE, - &pDpa->msgbuf_dma); - if (!pDpa->msgbuf) { - printk (KERN_ERR "(rcpci45 driver:) \ - Could not allocate %d byte memory for the \ - private msgbuf!\n", MSG_BUF_SIZE); - error = -ENOMEM; - goto err_out_free_dev; - } - - /* The adapter is accessible through memory-access read/write, not - * I/O read/write. Thus, we need to map it to some virtual address - * area in order to access the registers as normal memory. - */ - error = pci_request_regions (pdev, dev->name); - if (error) - goto err_out_free_msgbuf; - - error = pci_set_dma_mask (pdev, RCPCI45_DMA_MASK); - if (error) { - printk (KERN_ERR - "(rcpci45 driver:) pci_set_dma_mask failed!\n"); - goto err_out_free_region; - } - - vaddr = (ulong *) ioremap (pci_start, pci_len); - if (!vaddr) { - printk (KERN_ERR - "(rcpci45 driver:) \ - Unable to remap address range from %lu to %lu\n", - pci_start, pci_start + pci_len); - error = -EIO; - goto err_out_free_region; - } - - dev->base_addr = (unsigned long) vaddr; - dev->irq = pdev->irq; - dev->open = &RCopen; - dev->hard_start_xmit = &RC_xmit_packet; - dev->stop = &RCclose; - dev->get_stats = &RCget_stats; - dev->do_ioctl = &RCioctl; - dev->set_config = &RCconfig; - - if ((error = register_netdev(dev))) - goto err_out_iounmap; - - return 0; /* success */ - -err_out_iounmap: - iounmap((void *) dev->base_addr); -err_out_free_region: - pci_release_regions (pdev); -err_out_free_msgbuf: - pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf, - pDpa->msgbuf_dma); -err_out_free_dev: - free_netdev (dev); -err_out: - card_idx--; - return error; -} - -static struct pci_driver rcpci45_driver = { - .name = "rcpci45", - .id_table = rcpci45_pci_table, - .probe = rcpci45_init_one, - .remove = __devexit_p(rcpci45_remove_one), -}; - -static int __init -rcpci_init_module (void) -{ - int rc = pci_module_init (&rcpci45_driver); - if (!rc) - printk (KERN_ERR "%s", version); - return rc; -} - -static int -RCopen (struct net_device *dev) -{ - int post_buffers = MAX_NMBR_RCV_BUFFERS; - PDPA pDpa = dev->priv; - int count = 0; - int requested = 0; - int error; - - if (pDpa->nexus) { - /* This is not the first time RCopen is called. Thus, - * the interface was previously opened and later closed - * by RCclose(). RCclose() does a Shutdown; to wake up - * the adapter, a reset is mandatory before we can post - * receive buffers. However, if the adapter initiated - * a reboot while the interface was closed -- and interrupts - * were turned off -- we need will need to reinitialize - * the adapter, rather than simply waking it up. - */ - printk (KERN_INFO "Waking up adapter...\n"); - RCResetLANCard (dev, 0, 0, 0); - } else { - pDpa->nexus = 1; - /* - * RCInitI2OMsgLayer is done only once, unless the - * adapter was sent a warm reboot - */ - error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, - (PFNRXCALLBACK) RCrecv_callback, - (PFNCALLBACK) RCreboot_callback); - if (error) { - printk (KERN_ERR "%s: Unable to init msg layer (%x)\n", - dev->name, error); - goto err_out; - } - if ((error = RCGetMAC (dev, NULL))) { - printk (KERN_ERR "%s: Unable to get adapter MAC\n", - dev->name); - goto err_out; - } - } - - /* Request a shared interrupt line. */ - error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); - if (error) { - printk (KERN_ERR "%s: unable to get IRQ %d\n", - dev->name, dev->irq); - goto err_out; - } - - DriverControlWord |= WARM_REBOOT_CAPABLE; - RCReportDriverCapability (dev, DriverControlWord); - - printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", - dev->name); - - RCEnableI2OInterrupts (dev); - - while (post_buffers) { - if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = RC_allocate_and_post_buffers (dev, requested); - - if (count < requested) { - /* - * Check to see if we were able to post - * any buffers at all. - */ - if (post_buffers == MAX_NMBR_RCV_BUFFERS) { - printk (KERN_ERR "%s: \ - unable to allocate any buffers\n", - dev->name); - goto err_out_free_irq; - } - printk (KERN_WARNING "%s: \ - unable to allocate all requested buffers\n", dev->name); - break; /* we'll try to post more buffers later */ - } else - post_buffers -= count; - } - pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; - pDpa->shutdown = 0; /* just in case */ - netif_start_queue (dev); - return 0; - -err_out_free_irq: - free_irq (dev->irq, dev); -err_out: - return error; -} - -static int -RC_xmit_packet (struct sk_buff *skb, struct net_device *dev) -{ - - PDPA pDpa = dev->priv; - singleTCB tcb; - psingleTCB ptcb = &tcb; - RC_RETURN status = 0; - - netif_stop_queue (dev); - - if (pDpa->shutdown || pDpa->reboot) { - printk ("RC_xmit_packet: tbusy!\n"); - return 1; - } - - /* - * The user is free to reuse the TCB after RCI2OSendPacket() - * returns, since the function copies the necessary info into its - * own private space. Thus, our TCB can be a local structure. - * The skb, on the other hand, will be freed up in our interrupt - * handler. - */ - - ptcb->bcount = 1; - - /* - * we'll get the context when the adapter interrupts us to tell us that - * the transmission is done. At that time, we can free skb. - */ - ptcb->b.context = (U32) skb; - ptcb->b.scount = 1; - ptcb->b.size = skb->len; - ptcb->b.addr = pci_map_single(pDpa->pci_dev, skb->data, skb->len, - PCI_DMA_TODEVICE); - - if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) - != RC_RTN_NO_ERROR) { - printk ("%s: send error 0x%x\n", dev->name, (uint) status); - return 1; - } else { - dev->trans_start = jiffies; - netif_wake_queue (dev); - } - /* - * That's it! - */ - return 0; -} - -/* - * RCxmit_callback() - * - * The transmit callback routine. It's called by RCProcI2OMsgQ() - * because the adapter is done with one or more transmit buffers and - * it's returning them to us, or we asked the adapter to return the - * outstanding transmit buffers by calling RCResetLANCard() with - * RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag. - * All we need to do is free the buffers. - */ -static void -RCxmit_callback (U32 Status, - U16 PcktCount, PU32 BufferContext, struct net_device *dev) -{ - struct sk_buff *skb; - PDPA pDpa = dev->priv; - - if (!pDpa) { - printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n", - dev->name); - return; - } - - if (Status != I2O_REPLY_STATUS_SUCCESS) - printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n", - dev->name, (uint) Status); - if (pDpa->shutdown || pDpa->reboot) - printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n", - dev->name); - - while (PcktCount--) { - skb = (struct sk_buff *) (BufferContext[0]); - BufferContext++; - pci_unmap_single(pDpa->pci_dev, BufferContext[1], skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq (skb); - } - netif_wake_queue (dev); -} - -static void -RCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) -{ - PDPA pDpa = dev->priv; - - printk ("RCreset_callback Status 0x%x\n", (uint) Status); - /* - * Check to see why we were called. - */ - if (pDpa->shutdown) { - printk (KERN_INFO "%s: shutting down interface\n", - dev->name); - pDpa->shutdown = 0; - pDpa->reboot = 0; - } else if (pDpa->reboot) { - printk (KERN_INFO "%s: reboot, shutdown adapter\n", - dev->name); - /* - * We don't set any of the flags in RCShutdownLANCard() - * and we don't pass a callback routine to it. - * The adapter will have already initiated the reboot by - * the time the function returns. - */ - RCDisableI2OInterrupts (dev); - RCShutdownLANCard (dev, 0, 0, 0); - printk (KERN_INFO "%s: scheduling timer...\n", dev->name); - init_timer (&pDpa->timer); - pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ - pDpa->timer.data = (unsigned long) dev; - pDpa->timer.function = &rc_timer; /* timer handler */ - add_timer (&pDpa->timer); - } -} - -static void -RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) -{ - PDPA pDpa = dev->priv; - - printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n", - dev->name, (uint) pDpa->numOutRcvBuffers); - - if (pDpa->shutdown) { - printk (KERN_INFO "%s: skip reboot, shutdown initiated\n", - dev->name); - return; - } - pDpa->reboot = 1; - /* - * OK, we reset the adapter and ask it to return all - * outstanding transmit buffers as well as the posted - * receive buffers. When the adapter is done returning - * those buffers, it will call our RCreset_callback() - * routine. In that routine, we'll call RCShutdownLANCard() - * to tell the adapter that it's OK to start the reboot and - * schedule a timer callback routine to execute 3 seconds - * later; this routine will reinitialize the adapter at that time. - */ - RCResetLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | - RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, - (PFNCALLBACK) RCreset_callback); -} - -/* - * RCrecv_callback() - * - * The receive packet callback routine. This is called by - * RCProcI2OMsgQ() after the adapter posts buffers which have been - * filled (one ethernet packet per buffer). - */ -static void -RCrecv_callback (U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, struct net_device *dev) -{ - - U32 len, count; - PDPA pDpa = dev->priv; - struct sk_buff *skb; - singleTCB tcb; - psingleTCB ptcb = &tcb; - - ptcb->bcount = 1; - - if ((pDpa->shutdown || pDpa->reboot) && !Status) - printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n", - dev->name, PktCount); - - if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { - /* - * Free whatever buffers the adapter returned, but don't - * pass them to the kernel. - */ - - if (!pDpa->shutdown && !pDpa->reboot) - printk (KERN_INFO "%s: recv error status = 0x%x\n", - dev->name, (uint) Status); - else - printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n", - dev->name, PktCount, (uint) Status); - /* - * TO DO: check the nature of the failure and put the - * adapter in failed mode if it's a hard failure. - * Send a reset to the adapter and free all outstanding memory. - */ - if (PacketDescBlock) { - while (PktCount--) { - skb = (struct sk_buff *) PacketDescBlock[0]; - dev_kfree_skb (skb); - pDpa->numOutRcvBuffers--; - /* point to next context field */ - PacketDescBlock += BD_SIZE; - } - } - return; - } else { - while (PktCount--) { - skb = (struct sk_buff *) PacketDescBlock[0]; - len = PacketDescBlock[2]; - skb->dev = dev; - skb_put (skb, len); /* adjust length and tail */ - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); /* send the packet to the kernel */ - dev->last_rx = jiffies; - pDpa->numOutRcvBuffers--; - /* point to next context field */ - PacketDescBlock += BD_SIZE; - } - } - - /* - * Replenish the posted receive buffers. - * DO NOT replenish buffers if the driver has already - * initiated a reboot or shutdown! - */ - - if (!pDpa->shutdown && !pDpa->reboot) { - count = RC_allocate_and_post_buffers (dev, - MAX_NMBR_RCV_BUFFERS - - pDpa->numOutRcvBuffers); - pDpa->numOutRcvBuffers += count; - } - -} - -/* - * RCinterrupt() - * - * Interrupt handler. - * This routine sets up a couple of pointers and calls - * RCProcI2OMsgQ(), which in turn process the message and - * calls one of our callback functions. - */ -static irqreturn_t -RCinterrupt (int irq, void *dev_id, struct pt_regs *regs) -{ - - PDPA pDpa; - struct net_device *dev = dev_id; - - pDpa = dev->priv; - - if (pDpa->shutdown) - printk (KERN_DEBUG "%s: shutdown, service irq\n", - dev->name); - - return RCProcI2OMsgQ (dev); -} - -#define REBOOT_REINIT_RETRY_LIMIT 4 -static void -rc_timer (unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - PDPA pDpa = dev->priv; - int init_status; - static int retry; - int post_buffers = MAX_NMBR_RCV_BUFFERS; - int count = 0; - int requested = 0; - - if (pDpa->reboot) { - init_status = - RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, - (PFNRXCALLBACK) RCrecv_callback, - (PFNCALLBACK) RCreboot_callback); - - switch (init_status) { - case RC_RTN_NO_ERROR: - - pDpa->reboot = 0; - pDpa->shutdown = 0; /* just in case */ - RCReportDriverCapability (dev, DriverControlWord); - RCEnableI2OInterrupts (dev); - - - if (!(dev->flags & IFF_UP)) { - retry = 0; - return; - } - while (post_buffers) { - if (post_buffers > - MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = - MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = - RC_allocate_and_post_buffers (dev, - requested); - post_buffers -= count; - if (count < requested) - break; - } - pDpa->numOutRcvBuffers = - MAX_NMBR_RCV_BUFFERS - post_buffers; - printk ("Initialization done.\n"); - netif_wake_queue (dev); - retry = 0; - return; - case RC_RTN_FREE_Q_EMPTY: - retry++; - printk (KERN_WARNING "%s inbound free q empty\n", - dev->name); - break; - default: - retry++; - printk (KERN_WARNING "%s bad stat after reboot: %d\n", - dev->name, init_status); - break; - } - - if (retry > REBOOT_REINIT_RETRY_LIMIT) { - printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); - printk (KERN_WARNING "%s shutting down interface\n", dev->name); - RCDisableI2OInterrupts (dev); - dev->flags &= ~IFF_UP; - } else { - printk (KERN_INFO "%s: rescheduling timer...\n", - dev->name); - init_timer (&pDpa->timer); - pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); - pDpa->timer.data = (unsigned long) dev; - pDpa->timer.function = &rc_timer; - add_timer (&pDpa->timer); - } - } else - printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name); -} - -static int -RCclose (struct net_device *dev) -{ - PDPA pDpa = dev->priv; - - printk("RCclose\n"); - netif_stop_queue (dev); - - if (pDpa->reboot) { - printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name); - dev->flags &= ~IFF_UP; - pDpa->shutdown = 1; - return 0; - } - - pDpa->shutdown = 1; - - /* - * We can't allow the driver to be unloaded until the adapter returns - * all posted receive buffers. It doesn't hurt to tell the adapter - * to return all posted receive buffers and outstanding xmit buffers, - * even if there are none. - */ - - RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | - RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, - (PFNCALLBACK) RCreset_callback); - - dev->flags &= ~IFF_UP; - return 0; -} - -static struct net_device_stats * -RCget_stats (struct net_device *dev) -{ - RCLINKSTATS RCstats; - - PDPA pDpa = dev->priv; - - if (!pDpa) { - return 0; - } else if (!(dev->flags & IFF_UP)) { - return 0; - } - - memset (&RCstats, 0, sizeof (RCLINKSTATS)); - if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == - RC_RTN_NO_ERROR) { - - /* total packets received */ - pDpa->stats.rx_packets = RCstats.Rcv_good - /* total packets transmitted */; - pDpa->stats.tx_packets = RCstats.TX_good; - - pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + - RCstats.Rcv_alignerr + RCstats.Rcv_reserr + - RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; - - pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + - RCstats.TX_def + RCstats.TX_totcol; - - /* - * This needs improvement. - */ - pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ - pDpa->stats.tx_dropped = 0; /* no space available in linux */ - pDpa->stats.multicast = 0; /* multicast packets received */ - pDpa->stats.collisions = RCstats.TX_totcol; - - /* detailed rx_errors: */ - pDpa->stats.rx_length_errors = 0; - pDpa->stats.rx_over_errors = RCstats.Rcv_orun; - pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; - pDpa->stats.rx_frame_errors = 0; - pDpa->stats.rx_fifo_errors = 0; - pDpa->stats.rx_missed_errors = 0; - - /* detailed tx_errors */ - pDpa->stats.tx_aborted_errors = 0; - pDpa->stats.tx_carrier_errors = 0; - pDpa->stats.tx_fifo_errors = 0; - pDpa->stats.tx_heartbeat_errors = 0; - pDpa->stats.tx_window_errors = 0; - - return ((struct net_device_stats *) &(pDpa->stats)); - } - return 0; -} - -static int -RCioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - RCuser_struct RCuser; - PDPA pDpa = dev->priv; - - if (!capable (CAP_NET_ADMIN)) - return -EPERM; - - switch (cmd) { - - case RCU_PROTOCOL_REV: - /* - * Assign user protocol revision, to tell user-level - * controller program whether or not it's in sync. - */ - rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV; - break; - - case RCU_COMMAND: - { - if (copy_from_user - (&RCuser, rq->ifr_data, sizeof (RCuser))) - return -EFAULT; - - dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); - - switch (RCuser.cmd) { - case RCUC_GETFWVER: - RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; - RCGetFirmwareVer (dev, - (PU8) & RCUD_GETFWVER-> - FirmString, NULL); - break; - case RCUC_GETINFO: - RCUD_GETINFO = &RCuser.RCUS_GETINFO; - RCUD_GETINFO->mem_start = dev->base_addr; - RCUD_GETINFO->mem_end = - dev->base_addr + pDpa->pci_addr_len; - RCUD_GETINFO->base_addr = pDpa->pci_addr; - RCUD_GETINFO->irq = dev->irq; - break; - case RCUC_GETIPANDMASK: - RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; - RCGetRavlinIPandMask (dev, - (PU32) & - RCUD_GETIPANDMASK->IpAddr, - (PU32) & - RCUD_GETIPANDMASK-> - NetMask, NULL); - break; - case RCUC_GETLINKSTATISTICS: - RCUD_GETLINKSTATISTICS = - &RCuser.RCUS_GETLINKSTATISTICS; - RCGetLinkStatistics (dev, - (P_RCLINKSTATS) & - RCUD_GETLINKSTATISTICS-> - StatsReturn, NULL); - break; - case RCUC_GETLINKSTATUS: - RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; - RCGetLinkStatus (dev, - (PU32) & RCUD_GETLINKSTATUS-> - ReturnStatus, NULL); - break; - case RCUC_GETMAC: - RCUD_GETMAC = &RCuser.RCUS_GETMAC; - RCGetMAC (dev, NULL); - memcpy(RCUD_GETMAC, dev->dev_addr, 8); - break; - case RCUC_GETPROM: - RCUD_GETPROM = &RCuser.RCUS_GETPROM; - RCGetPromiscuousMode (dev, - (PU32) & RCUD_GETPROM-> - PromMode, NULL); - break; - case RCUC_GETBROADCAST: - RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; - RCGetBroadcastMode (dev, - (PU32) & RCUD_GETBROADCAST-> - BroadcastMode, NULL); - break; - case RCUC_GETSPEED: - if (!(dev->flags & IFF_UP)) { - return -ENODATA; - } - RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; - RCGetLinkSpeed (dev, - (PU32) & RCUD_GETSPEED-> - LinkSpeedCode, NULL); - break; - case RCUC_SETIPANDMASK: - RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - RCSetRavlinIPandMask (dev, - (U32) RCUD_SETIPANDMASK-> - IpAddr, - (U32) RCUD_SETIPANDMASK-> - NetMask); - break; - case RCUC_SETMAC: - RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); - break; - case RCUC_SETSPEED: - RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; - RCSetLinkSpeed (dev, - (U16) RCUD_SETSPEED-> - LinkSpeedCode); - break; - case RCUC_SETPROM: - RCUD_SETPROM = &RCuser.RCUS_SETPROM; - RCSetPromiscuousMode (dev, - (U16) RCUD_SETPROM-> - PromMode); - break; - case RCUC_SETBROADCAST: - RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; - RCSetBroadcastMode (dev, - (U16) RCUD_SETBROADCAST-> - BroadcastMode); - break; - default: - RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; - RCUD_DEFAULT->rc = 0x11223344; - break; - } - if (copy_to_user (rq->ifr_data, &RCuser, - sizeof (RCuser))) - return -EFAULT; - break; - } /* RCU_COMMAND */ - - default: - rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; - return -EINVAL; - } - return 0; -} - -static int -RCconfig (struct net_device *dev, struct ifmap *map) -{ - /* - * To be completed ... - */ - return 0; - if (dev->flags & IFF_UP) /* can't act on a running interface */ - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) { - printk (KERN_WARNING "%s Change I/O address not implemented\n", - dev->name); - return -EOPNOTSUPP; - } - return 0; -} - -static void __exit -rcpci_cleanup_module (void) -{ - pci_unregister_driver (&rcpci45_driver); -} - -module_init (rcpci_init_module); -module_exit (rcpci_cleanup_module); - -static int -RC_allocate_and_post_buffers (struct net_device *dev, int numBuffers) -{ - - int i; - PU32 p; - psingleB pB; - struct sk_buff *skb; - PDPA pDpa = dev->priv; - RC_RETURN status; - U32 res = 0; - - if (!numBuffers) - return 0; - else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { - printk (KERN_ERR "%s: Too many buffers requested!\n", - dev->name); - numBuffers = 32; - } - - p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), - GFP_DMA | GFP_ATOMIC); - - if (!p) { - printk (KERN_WARNING "%s unable to allocate TCB\n", - dev->name); - goto out; - } - - p[0] = 0; /* Buffer Count */ - pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */ - - for (i = 0; i < numBuffers; i++) { - skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); - if (!skb) { - printk (KERN_WARNING - "%s: unable to allocate enough skbs!\n", - dev->name); - goto err_out_unmap; - } - skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ - pB->context = (U32) skb; - pB->scount = 1; /* segment count */ - pB->size = MAX_ETHER_SIZE; - pB->addr = pci_map_single(pDpa->pci_dev, skb->data, - MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); - p[0]++; - pB++; - } - - if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { - printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n", - dev->name, status); - goto err_out_unmap; - } -out_free: - res = p[0]; - kfree (p); -out: - return (res); /* return the number of posted buffers */ - -err_out_unmap: - for (; p[0] > 0; p[0]--) { - --pB; - skb = (struct sk_buff *) pB->context; - pci_unmap_single(pDpa->pci_dev, pB->addr, MAX_ETHER_SIZE, - PCI_DMA_FROMDEVICE); - dev_kfree_skb (skb); - } - goto out_free; -} diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 14dc145e0..83a53bc83 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -99,45 +99,45 @@ static char s2io_gstrings[][ETH_GSTRING_LEN] = { }; static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { - "tmac_frms", - "tmac_data_octets", - "tmac_drop_frms", - "tmac_mcst_frms", - "tmac_bcst_frms", - "tmac_pause_ctrl_frms", - "tmac_any_err_frms", - "tmac_vld_ip_octets", - "tmac_vld_ip", - "tmac_drop_ip", - "tmac_icmp", - "tmac_rst_tcp", - "tmac_tcp", - "tmac_udp", - "rmac_vld_frms", - "rmac_data_octets", - "rmac_fcs_err_frms", - "rmac_drop_frms", - "rmac_vld_mcst_frms", - "rmac_vld_bcst_frms", - "rmac_in_rng_len_err_frms", - "rmac_long_frms", - "rmac_pause_ctrl_frms", - "rmac_discarded_frms", - "rmac_usized_frms", - "rmac_osized_frms", - "rmac_frag_frms", - "rmac_jabber_frms", - "rmac_ip", - "rmac_ip_octets", - "rmac_hdr_err_ip", - "rmac_drop_ip", - "rmac_icmp", - "rmac_tcp", - "rmac_udp", - "rmac_err_drp_udp", - "rmac_pause_cnt", - "rmac_accepted_ip", - "rmac_err_tcp", + {"tmac_frms"}, + {"tmac_data_octets"}, + {"tmac_drop_frms"}, + {"tmac_mcst_frms"}, + {"tmac_bcst_frms"}, + {"tmac_pause_ctrl_frms"}, + {"tmac_any_err_frms"}, + {"tmac_vld_ip_octets"}, + {"tmac_vld_ip"}, + {"tmac_drop_ip"}, + {"tmac_icmp"}, + {"tmac_rst_tcp"}, + {"tmac_tcp"}, + {"tmac_udp"}, + {"rmac_vld_frms"}, + {"rmac_data_octets"}, + {"rmac_fcs_err_frms"}, + {"rmac_drop_frms"}, + {"rmac_vld_mcst_frms"}, + {"rmac_vld_bcst_frms"}, + {"rmac_in_rng_len_err_frms"}, + {"rmac_long_frms"}, + {"rmac_pause_ctrl_frms"}, + {"rmac_discarded_frms"}, + {"rmac_usized_frms"}, + {"rmac_osized_frms"}, + {"rmac_frag_frms"}, + {"rmac_jabber_frms"}, + {"rmac_ip"}, + {"rmac_ip_octets"}, + {"rmac_hdr_err_ip"}, + {"rmac_drop_ip"}, + {"rmac_icmp"}, + {"rmac_tcp"}, + {"rmac_udp"}, + {"rmac_err_drp_udp"}, + {"rmac_pause_cnt"}, + {"rmac_accepted_ip"}, + {"rmac_err_tcp"}, }; #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 8ac2d8109..ea2d89155 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -1031,14 +1031,14 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGCMFREQUENCY: /* get frequency */ if ((status = sb1000_get_frequency(ioaddr, name, &frequency))) return status; - if(put_user(frequency, (int __user *) ifr->ifr_data)) + if(put_user(frequency, (int*) ifr->ifr_data)) return -EFAULT; break; case SIOCSCMFREQUENCY: /* set frequency */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(get_user(frequency, (int __user *) ifr->ifr_data)) + if(get_user(frequency, (int*) ifr->ifr_data)) return -EFAULT; if ((status = sb1000_set_frequency(ioaddr, name, frequency))) return status; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index aa045b62c..05479dd80 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1893,7 +1893,7 @@ static struct ethtool_ops sis900_ethtool_ops = { static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { struct sis900_private *sis_priv = net_dev->priv; - struct mii_ioctl_data *data = if_mii(rq); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index e3e83ed0f..dba3d2dd2 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -58,7 +58,8 @@ /* 3Com (0x10b7) */ \ if (pdev->vendor == 0x10b7) { \ /* Gigabit Ethernet Adapter (0x1700) */ \ - if ((pdev->device == 0x1700)) { \ + if ((pdev->device == 0x1700) || \ + (pdev->device == 0x80eb)) { \ result = SK_TRUE; \ } \ /* SysKonnect (0x1148) */ \ diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 53da48163..327e7798e 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -788,7 +788,8 @@ static int __init skge_init_module(void) cards = skge_probe(); if (cards == 0) { printk("sk98lin: No adapter found.\n"); - } + } else + __unsafe(THIS_MODULE); return cards ? 0 : -ENODEV; } /* skge_init_module */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6b2a16825..20ba895dc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.6" -#define DRV_MODULE_RELDATE "June 12, 2004" +#define DRV_MODULE_VERSION "3.5" +#define DRV_MODULE_RELDATE "May 25, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -177,8 +177,6 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2, @@ -197,10 +195,6 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX, @@ -6684,7 +6678,7 @@ static void tg3_get_ethtool_stats (struct net_device *dev, static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mii_ioctl_data *data = if_mii(ifr); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; struct tg3 *tp = netdev_priv(dev); int err; @@ -7542,14 +7536,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) udelay(50); tg3_nvram_init(tp); - /* Always use host TXDs, it performs better in particular - * with multi-frag packets. The tests below are kept here - * as documentation should we change this decision again - * in the future. - */ - tp->tg3_flags |= TG3_FLAG_HOST_TXDS; - -#if 0 /* Determine if TX descriptors will reside in * main memory or in the chip SRAM. */ @@ -7557,7 +7543,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) tp->tg3_flags |= TG3_FLAG_HOST_TXDS; -#endif grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; @@ -7580,9 +7565,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901 || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 || - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) || - (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM && - tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F)) + tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F))) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); @@ -8463,8 +8446,6 @@ static int tg3_resume(struct pci_dev *pdev) if (!netif_running(dev)) return 0; - pci_restore_state(tp->pdev, tp->pci_cfg_state); - err = tg3_set_power_state(tp, 0); if (err) return err; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 4c57ab290..3c10d2a98 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -984,7 +984,7 @@ static int TLan_Open( struct net_device *dev ) static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { TLanPrivateInfo *priv = dev->priv; - struct mii_ioctl_data *data = if_mii(rq); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; u32 phy = priv->phy[priv->phyNum]; if (!priv->phyOnline) diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 10fa8e79d..61f50e0b1 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -848,6 +848,8 @@ static int tok_init_card(struct net_device *dev) struct tok_info *ti; short PIOaddr; unsigned long i; + wait_queue_t __wait; + init_waitqueue_entry(&__wait, current); PIOaddr = dev->base_addr; ti = (struct tok_info *) dev->priv; @@ -860,13 +862,18 @@ static int tok_init_card(struct net_device *dev) current->state=TASK_UNINTERRUPTIBLE; schedule_timeout(TR_RST_TIME); /* wait 50ms */ + add_wait_queue(&ti->wait_for_reset, &__wait); + set_current_state(TASK_UNINTERRUPTIBLE); outb(0, PIOaddr + ADAPTRESETREL); #ifdef ENABLE_PAGING if (ti->page_mask) writeb(SRPR_ENABLE_PAGING,ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); #endif writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ); + #warning pci posting bug + i = schedule_timeout(4 * HZ); + current->state = TASK_RUNNING; + remove_wait_queue(&ti->wait_for_reset, &__wait); return i? 0 : -EAGAIN; } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 498f612cf..0fc00edc8 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -830,7 +830,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev) } -static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct tulip_private *np = netdev_priv(dev); u32 ethcmd; @@ -859,14 +859,14 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = if_mii(rq); + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; const unsigned int phy_idx = 0; int phy = tp->phys[phy_idx] & 0x1f; unsigned int regnum = data->reg_num; switch (cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, rq->ifr_data); + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ if (tp->mii_cnt) diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index f5aeb3dda..74d42535c 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1526,8 +1526,8 @@ static struct ethtool_ops netdev_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct mii_ioctl_data *data = if_mii(rq); - struct netdev_private *np = netdev_priv(dev); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + struct netdev_private *np = dev->priv; switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 721e92f49..d399b347d 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1875,13 +1875,14 @@ static struct ethtool_ops netdev_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct rhine_private *rp = netdev_priv(dev); + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&rp->lock); - rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL); + rc = generic_mii_ioctl(&rp->mii_if, data, cmd, NULL); spin_unlock_irq(&rp->lock); return rc; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c new file mode 100644 index 000000000..3356fd8de --- /dev/null +++ b/drivers/net/via-velocity.c @@ -0,0 +1,3277 @@ +/* + * This code is derived from the VIA reference driver (copyright message + * below) provided to Red Hat by VIA Networking Technologies, Inc. for + * addition to the Linux kernel. + * + * The code has been merged into one source file, cleaned up to follow + * Linux coding style, ported to the Linux 2.6 kernel tree and cleaned + * for 64bit hardware platforms. + * + * TODO + * Big-endian support + * rx_copybreak/alignment + * Scatter gather + * More testing + * + * The changes are (c) Copyright 2004, Red Hat Inc. + * Additional fixes and clean up: Francois Romieu + * + * This source has not been verified for use in safety critical systems. + * + * Please direct queries about the revamped driver to the linux-kernel + * list not VIA. + * + * Original code: + * + * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. + * All rights reserved. + * + * This software may be redistributed and/or modified under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Author: Chuang Liang-Shing, AJ Jiang + * + * Date: Jan 24, 2003 + * + * MODULE_LICENSE("GPL"); + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "via-velocity.h" + + +static int velocity_nics = 0; +static int msglevel = MSG_LEVEL_INFO; + + +static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static struct ethtool_ops velocity_ethtool_ops; + +/* + Define module options +*/ + +MODULE_AUTHOR("VIA Networking Technologies, Inc."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"); + +#define VELOCITY_PARAM(N,D) \ + static const int N[MAX_UNITS]=OPTION_DEFAULT;\ + MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\ + MODULE_PARM_DESC(N, D); + +#define RX_DESC_MIN 64 +#define RX_DESC_MAX 255 +#define RX_DESC_DEF 64 +VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors"); + +#define TX_DESC_MIN 16 +#define TX_DESC_MAX 256 +#define TX_DESC_DEF 64 +VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors"); + +#define VLAN_ID_MIN 0 +#define VLAN_ID_MAX 4095 +#define VLAN_ID_DEF 0 +/* VID_setting[] is used for setting the VID of NIC. + 0: default VID. + 1-4094: other VIDs. +*/ +VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID"); + +#define RX_THRESH_MIN 0 +#define RX_THRESH_MAX 3 +#define RX_THRESH_DEF 0 +/* rx_thresh[] is used for controlling the receive fifo threshold. + 0: indicate the rxfifo threshold is 128 bytes. + 1: indicate the rxfifo threshold is 512 bytes. + 2: indicate the rxfifo threshold is 1024 bytes. + 3: indicate the rxfifo threshold is store & forward. +*/ +VELOCITY_PARAM(rx_thresh, "Receive fifo threshold"); + +#define DMA_LENGTH_MIN 0 +#define DMA_LENGTH_MAX 7 +#define DMA_LENGTH_DEF 0 + +/* DMA_length[] is used for controlling the DMA length + 0: 8 DWORDs + 1: 16 DWORDs + 2: 32 DWORDs + 3: 64 DWORDs + 4: 128 DWORDs + 5: 256 DWORDs + 6: SF(flush till emply) + 7: SF(flush till emply) +*/ +VELOCITY_PARAM(DMA_length, "DMA length"); + +#define TAGGING_DEF 0 +/* enable_tagging[] is used for enabling 802.1Q VID tagging. + 0: disable VID seeting(default). + 1: enable VID setting. +*/ +VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging"); + +#define IP_ALIG_DEF 0 +/* IP_byte_align[] is used for IP header DWORD byte aligned + 0: indicate the IP header won't be DWORD byte aligned.(Default) . + 1: indicate the IP header will be DWORD byte aligned. + In some enviroment, the IP header should be DWORD byte aligned, + or the packet will be droped when we receive it. (eg: IPVS) +*/ +VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned"); + +#define TX_CSUM_DEF 1 +/* txcsum_offload[] is used for setting the checksum offload ability of NIC. + (We only support RX checksum offload now) + 0: disable csum_offload[checksum offload + 1: enable checksum offload. (Default) +*/ +VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload"); + +#define FLOW_CNTL_DEF 1 +#define FLOW_CNTL_MIN 1 +#define FLOW_CNTL_MAX 5 + +/* flow_control[] is used for setting the flow control ability of NIC. + 1: hardware deafult - AUTO (default). Use Hardware default value in ANAR. + 2: enable TX flow control. + 3: enable RX flow control. + 4: enable RX/TX flow control. + 5: disable +*/ +VELOCITY_PARAM(flow_control, "Enable flow control ability"); + +#define MED_LNK_DEF 0 +#define MED_LNK_MIN 0 +#define MED_LNK_MAX 4 +/* speed_duplex[] is used for setting the speed and duplex mode of NIC. + 0: indicate autonegotiation for both speed and duplex mode + 1: indicate 100Mbps half duplex mode + 2: indicate 100Mbps full duplex mode + 3: indicate 10Mbps half duplex mode + 4: indicate 10Mbps full duplex mode + + Note: + if EEPROM have been set to the force mode, this option is ignored + by driver. +*/ +VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); + +#define VAL_PKT_LEN_DEF 0 +/* ValPktLen[] is used for setting the checksum offload ability of NIC. + 0: Receive frame with invalid layer 2 length (Default) + 1: Drop frame with invalid layer 2 length +*/ +VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame"); + +#define WOL_OPT_DEF 0 +#define WOL_OPT_MIN 0 +#define WOL_OPT_MAX 7 +/* wol_opts[] is used for controlling wake on lan behavior. + 0: Wake up if recevied a magic packet. (Default) + 1: Wake up if link status is on/off. + 2: Wake up if recevied an arp packet. + 4: Wake up if recevied any unicast packet. + Those value can be sumed up to support more than one option. +*/ +VELOCITY_PARAM(wol_opts, "Wake On Lan options"); + +#define INT_WORKS_DEF 20 +#define INT_WORKS_MIN 10 +#define INT_WORKS_MAX 64 + +VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); + +static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent); +static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info); +static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); +static void velocity_print_info(struct velocity_info *vptr); +static int velocity_open(struct net_device *dev); +static int velocity_change_mtu(struct net_device *dev, int mtu); +static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); +static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs); +static void velocity_set_multi(struct net_device *dev); +static struct net_device_stats *velocity_get_stats(struct net_device *dev); +static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int velocity_close(struct net_device *dev); +static int velocity_rx_srv(struct velocity_info *vptr, int status); +static int velocity_receive_frame(struct velocity_info *, int idx); +static int velocity_alloc_rx_buf(struct velocity_info *, int idx); +static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type); +static void velocity_free_rd_ring(struct velocity_info *vptr); +static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); +static int velocity_soft_reset(struct velocity_info *vptr); +static void mii_init(struct velocity_info *vptr, u32 mii_status); +static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); +static void velocity_print_link_status(struct velocity_info *vptr); +static void safe_disable_mii_autopoll(struct mac_regs * regs); +static void velocity_shutdown(struct velocity_info *vptr); +static void enable_flow_control_ability(struct velocity_info *vptr); +static void enable_mii_autopoll(struct mac_regs * regs); +static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); +static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); +static int velocity_set_wol(struct velocity_info *vptr); +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context); +static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context); +static u32 mii_check_media_mode(struct mac_regs * regs); +static u32 check_connection_type(struct mac_regs * regs); +static void velocity_init_cam_filter(struct velocity_info *vptr); +static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); + +#ifdef CONFIG_PM +static int velocity_suspend(struct pci_dev *pdev, u32 state); +static int velocity_resume(struct pci_dev *pdev); + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); + +static struct notifier_block velocity_inetaddr_notifier = { + notifier_call:velocity_netdev_event, +}; + +#endif /* CONFIG_PM */ + +/* + * Internal board variants. At the moment we have only one + */ + +static struct velocity_info_tbl chip_info_table[] = { + {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL}, + {0, NULL} +}; + +/* + * Describe the PCI device identifiers that we support in this + * device driver. Used for hotplug autoloading. + */ + +static struct pci_device_id velocity_id_table[] __devinitdata = { + {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, velocity_id_table); + +/** + * get_chip_name - identifier to name + * @id: chip identifier + * + * Given a chip identifier return a suitable description. Returns + * a pointer a static string valid while the driver is loaded. + */ + +static char __devinit *get_chip_name(enum chip_type chip_id) +{ + int i; + for (i = 0; chip_info_table[i].name != NULL; i++) + if (chip_info_table[i].chip_id == chip_id) + break; + return chip_info_table[i].name; +} + +/** + * velocity_remove1 - device unplug + * @pdev: PCI device being removed + * + * Device unload callback. Called on an unplug or on module + * unload for each active device that is present. Disconnects + * the device from the network layer and frees all the resources + */ + +static void __devexit velocity_remove1(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct velocity_info *vptr = dev->priv; + + unregister_netdev(dev); + iounmap(vptr->mac_regs); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(dev); +} + +/** + * velocity_set_int_opt - parser for integer options + * @opt: pointer to option value + * @val: value the user requested (or -1 for default) + * @min: lowest value allowed + * @max: highest value allowed + * @def: default value + * @name: property name + * @dev: device name + * + * Set an integer property in the module options. This function does + * all the verification and checking as well as reporting so that + * we don't duplicate code for each option. + */ + +static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, char *devname) +{ + if (val == -1) + *opt = def; + else if (val < min || val > max) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n", + devname, name, min, max); + *opt = def; + } else { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n", + devname, name, val); + *opt = val; + } +} + +/** + * velocity_set_bool_opt - parser for boolean options + * @opt: pointer to option value + * @val: value the user requested (or -1 for default) + * @def: default value (yes/no) + * @flag: numeric value to set for true. + * @name: property name + * @dev: device name + * + * Set a boolean property in the module options. This function does + * all the verification and checking as well as reporting so that + * we don't duplicate code for each option. + */ + +static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, char *devname) +{ + (*opt) &= (~flag); + if (val == -1) + *opt |= (def ? flag : 0); + else if (val < 0 || val > 1) { + printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n", + devname, name); + *opt |= (def ? flag : 0); + } else { + printk(KERN_INFO "%s: set parameter %s to %s\n", + devname, name, val ? "TRUE" : "FALSE"); + *opt |= (val ? flag : 0); + } +} + +/** + * velocity_get_options - set options on device + * @opts: option structure for the device + * @index: index of option to use in module options array + * @devname: device name + * + * Turn the module and command options into a single structure + * for the current device + */ + +static void __devinit velocity_get_options(struct velocity_opt *opts, int index, char *devname) +{ + + velocity_set_int_opt(&opts->rx_thresh, rx_thresh[index], RX_THRESH_MIN, RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", devname); + velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname); + velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname); + velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname); + velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname); + velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname); + velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname); + velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); + velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); + velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname); + velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname); + velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname); + velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname); + opts->numrx = (opts->numrx & ~3); +} + +/** + * velocity_init_cam_filter - initialise CAM + * @vptr: velocity to program + * + * Initialize the content addressable memory used for filters. Load + * appropriately according to the presence of VLAN + */ + +static void velocity_init_cam_filter(struct velocity_info *vptr) +{ + struct mac_regs * regs = vptr->mac_regs; + + /* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */ + WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); + WORD_REG_BITS_ON(MCFG_VIDFR, ®s->MCFG); + + /* Disable all CAMs */ + memset(vptr->vCAMmask, 0, sizeof(u8) * 8); + memset(vptr->mCAMmask, 0, sizeof(u8) * 8); + mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); + mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + + /* Enable first VCAM */ + if (vptr->flags & VELOCITY_FLAGS_TAGGING) { + /* If Tagging option is enabled and VLAN ID is not zero, then + turn on MCFG_RTGOPT also */ + if (vptr->options.vid != 0) + WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); + + mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM); + vptr->vCAMmask[0] |= 1; + mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); + } else { + u16 temp = 0; + mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + temp = 1; + mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + } +} + +/** + * velocity_rx_reset - handle a receive reset + * @vptr: velocity we are resetting + * + * Reset the ownership and status for the receive ring side. + * Hand all the receive queue to the NIC. + */ + +static void velocity_rx_reset(struct velocity_info *vptr) +{ + + struct mac_regs * regs = vptr->mac_regs; + int i; + + vptr->rd_used = vptr->rd_curr = 0; + + /* + * Init state, all RD entries belong to the NIC + */ + for (i = 0; i < vptr->options.numrx; ++i) + vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); + + writew(vptr->options.numrx, ®s->RBRDU); + writel(vptr->rd_pool_dma, ®s->RDBaseLo); + writew(0, ®s->RDIdx); + writew(vptr->options.numrx - 1, ®s->RDCSize); +} + +/** + * velocity_init_registers - initialise MAC registers + * @vptr: velocity to init + * @type: type of initialisation (hot or cold) + * + * Initialise the MAC on a reset or on first set up on the + * hardware. + */ + +static void velocity_init_registers(struct velocity_info *vptr, + enum velocity_init_type type) +{ + struct mac_regs * regs = vptr->mac_regs; + int i, mii_status; + + mac_wol_reset(regs); + + switch (type) { + case VELOCITY_INIT_RESET: + case VELOCITY_INIT_WOL: + + netif_stop_queue(vptr->dev); + + /* + * Reset RX to prevent RX pointer not on the 4X location + */ + velocity_rx_reset(vptr); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); + + mii_status = velocity_get_opt_media_mode(vptr); + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); + } + + enable_flow_control_ability(vptr); + + mac_clear_isr(regs); + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), + ®s->CR0Set); + + break; + + case VELOCITY_INIT_COLD: + default: + /* + * Do reset + */ + velocity_soft_reset(vptr); + mdelay(5); + + mac_eeprom_reload(regs); + for (i = 0; i < 6; i++) { + writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); + } + /* + * clear Pre_ACPI bit. + */ + BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); + mac_set_rx_thresh(regs, vptr->options.rx_thresh); + mac_set_dma_length(regs, vptr->options.DMA_length); + + writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); + /* + * Bback off algorithm use original IEEE standard + */ + BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); + + /* + * Set packet filter: Receive directed and broadcast address + */ + velocity_set_multi(vptr->dev); + + /* + * Enable MII auto-polling + */ + enable_mii_autopoll(regs); + + vptr->int_mask = INT_MASK_DEF; + + writel(cpu_to_le32(vptr->rd_pool_dma), ®s->RDBaseLo); + writew(vptr->options.numrx - 1, ®s->RDCSize); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); + + writew(vptr->options.numtx - 1, ®s->TDCSize); + + for (i = 0; i < vptr->num_txq; i++) { + writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i])); + mac_tx_queue_run(regs, i); + } + + velocity_init_cam_filter(vptr); + + init_flow_control_register(vptr); + + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); + + mii_status = velocity_get_opt_media_mode(vptr); + netif_stop_queue(vptr->dev); + mac_clear_isr(regs); + + mii_init(vptr, mii_status); + + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); + } + + enable_flow_control_ability(vptr); + mac_hw_mibs_init(regs); + mac_write_int_mask(vptr->int_mask, regs); + mac_clear_isr(regs); + + } +} + +/** + * velocity_soft_reset - soft reset + * @vptr: velocity to reset + * + * Kick off a soft reset of the velocity adapter and then poll + * until the reset sequence has completed before returning. + */ + +static int velocity_soft_reset(struct velocity_info *vptr) +{ + struct mac_regs * regs = vptr->mac_regs; + int i = 0; + + writel(CR0_SFRST, ®s->CR0Set); + + for (i = 0; i < W_MAX_TIMEOUT; i++) { + udelay(5); + if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) + break; + } + + if (i == W_MAX_TIMEOUT) { + writel(CR0_FORSRST, ®s->CR0Set); + /* FIXME: PCI POSTING */ + /* delay 2ms */ + mdelay(2); + } + return 0; +} + +/** + * velocity_found1 - set up discovered velocity card + * @pdev: PCI device + * @ent: PCI device table entry that matched + * + * Configure a discovered adapter from scratch. Return a negative + * errno error code on failure paths. + */ + +static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int first = 1; + struct net_device *dev; + int i; + struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data; + struct velocity_info *vptr; + struct mac_regs * regs; + int ret = -ENOMEM; + + if (velocity_nics++ >= MAX_UNITS) { + printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", + velocity_nics); + return -ENODEV; + } + + dev = alloc_etherdev(sizeof(struct velocity_info)); + + if (dev == NULL) { + printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n"); + goto out; + } + + /* Chain it all together */ + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + vptr = dev->priv; + + + if (first) { + printk(KERN_INFO "%s Ver. %s\n", + VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); + printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); + printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); + first = 0; + } + + velocity_init_info(pdev, vptr, info); + + vptr->dev = dev; + + dev->priv = vptr; + dev->irq = pdev->irq; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_free_dev; + + ret = velocity_get_pci_info(vptr, pdev); + if (ret < 0) { + printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n"); + goto err_disable; + } + + ret = pci_request_regions(pdev, VELOCITY_NAME); + if (ret < 0) { + printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n"); + goto err_disable; + } + + regs = ioremap(vptr->memaddr, vptr->io_size); + if (regs == NULL) { + ret = -EIO; + goto err_release_res; + } + + vptr->mac_regs = regs; + + mac_wol_reset(regs); + + dev->base_addr = vptr->ioaddr; + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(®s->PAR[i]); + + + velocity_get_options(&vptr->options, velocity_nics - 1, dev->name); + + /* + * Mask out the options cannot be set to the chip + */ + + vptr->options.flags &= info->flags; + + /* + * Enable the chip specified capbilities + */ + + vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); + + vptr->wol_opts = vptr->options.wol_opts; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + + vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); + + dev->irq = pdev->irq; + dev->open = velocity_open; + dev->hard_start_xmit = velocity_xmit; + dev->stop = velocity_close; + dev->get_stats = velocity_get_stats; + dev->set_multicast_list = velocity_set_multi; + dev->do_ioctl = velocity_ioctl; + dev->ethtool_ops = &velocity_ethtool_ops; + dev->change_mtu = velocity_change_mtu; +#ifdef VELOCITY_ZERO_COPY_SUPPORT + dev->features |= NETIF_F_SG; +#endif + + if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) { + dev->features |= NETIF_F_HW_CSUM; + } + + ret = register_netdev(dev); + if (ret < 0) + goto err_iounmap; + + velocity_print_info(vptr); + pci_set_drvdata(pdev, dev); + + /* and leave the chip powered down */ + + pci_set_power_state(pdev, 3); +out: + return ret; + +err_iounmap: + iounmap(regs); +err_release_res: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); +err_free_dev: + free_netdev(dev); + goto out; +} + +/** + * velocity_print_info - per driver data + * @vptr: velocity + * + * Print per driver data as the kernel driver finds Velocity + * hardware + */ + +static void __devinit velocity_print_info(struct velocity_info *vptr) +{ + struct net_device *dev = vptr->dev; + + printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); + printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); +} + +/** + * velocity_init_info - init private data + * @pdev: PCI device + * @vptr: Velocity info + * @info: Board type + * + * Set up the initial velocity_info struct for the device that has been + * discovered. + */ + +static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info) +{ + memset(vptr, 0, sizeof(struct velocity_info)); + + vptr->pdev = pdev; + vptr->chip_id = info->chip_id; + vptr->io_size = info->io_size; + vptr->num_txq = info->txqueue; + vptr->multicast_limit = MCAM_SIZE; + + spin_lock_init(&vptr->lock); + spin_lock_init(&vptr->xmit_lock); +} + +/** + * velocity_get_pci_info - retrieve PCI info for device + * @vptr: velocity device + * @pdev: PCI device it matches + * + * Retrieve the PCI configuration space data that interests us from + * the kernel PCI layer + */ + +static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) +{ + + if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) + return -EIO; + + pci_set_master(pdev); + + vptr->ioaddr = pci_resource_start(pdev, 0); + vptr->memaddr = pci_resource_start(pdev, 1); + + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) + { + printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n", + pci_name(pdev)); + return -EINVAL; + } + + if((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) + { + printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n", + pci_name(pdev)); + return -EINVAL; + } + + if(pci_resource_len(pdev, 1) < 256) + { + printk(KERN_ERR "%s: region #1 is too small.\n", + pci_name(pdev)); + return -EINVAL; + } + vptr->pdev = pdev; + + return 0; +} + +/** + * velocity_init_rings - set up DMA rings + * @vptr: Velocity to set up + * + * Allocate PCI mapped DMA rings for the receive and transmit layer + * to use. + */ + +static int velocity_init_rings(struct velocity_info *vptr) +{ + int i; + unsigned int psize; + unsigned int tsize; + dma_addr_t pool_dma; + u8 *pool; + + /* + * Allocate all RD/TD rings a single pool + */ + + psize = vptr->options.numrx * sizeof(struct rx_desc) + + vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; + + /* + * pci_alloc_consistent() fulfills the requirement for 64 bytes + * alignment + */ + pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma); + + if (pool == NULL) { + printk(KERN_ERR "%s : DMA memory allocation failed.\n", + vptr->dev->name); + return -ENOMEM; + } + + memset(pool, 0, psize); + + vptr->rd_ring = (struct rx_desc *) pool; + + vptr->rd_pool_dma = pool_dma; + + tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq; + vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize, + &vptr->tx_bufs_dma); + + if (vptr->tx_bufs == NULL) { + printk(KERN_ERR "%s: DMA memory allocation failed.\n", + vptr->dev->name); + pci_free_consistent(vptr->pdev, psize, pool, pool_dma); + return -ENOMEM; + } + + memset(vptr->tx_bufs, 0, vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq); + + i = vptr->options.numrx * sizeof(struct rx_desc); + pool += i; + pool_dma += i; + for (i = 0; i < vptr->num_txq; i++) { + int offset = vptr->options.numtx * sizeof(struct tx_desc); + + vptr->td_pool_dma[i] = pool_dma; + vptr->td_rings[i] = (struct tx_desc *) pool; + pool += offset; + pool_dma += offset; + } + return 0; +} + +/** + * velocity_free_rings - free PCI ring pointers + * @vptr: Velocity to free from + * + * Clean up the PCI ring buffers allocated to this velocity. + */ + +static void velocity_free_rings(struct velocity_info *vptr) +{ + int size; + + size = vptr->options.numrx * sizeof(struct rx_desc) + + vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; + + pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma); + + size = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq; + + pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); +} + +/** + * velocity_init_rd_ring - set up receive ring + * @vptr: velocity to configure + * + * Allocate and set up the receive buffers for each ring slot and + * assign them to the network adapter. + */ + +static int velocity_init_rd_ring(struct velocity_info *vptr) +{ + int i, ret = -ENOMEM; + struct rx_desc *rd; + struct velocity_rd_info *rd_info; + unsigned int rsize = sizeof(struct velocity_rd_info) * + vptr->options.numrx; + + vptr->rd_info = kmalloc(rsize, GFP_KERNEL); + if(vptr->rd_info == NULL) + goto out; + memset(vptr->rd_info, 0, rsize); + + /* Init the RD ring entries */ + for (i = 0; i < vptr->options.numrx; i++) { + rd = &(vptr->rd_ring[i]); + rd_info = &(vptr->rd_info[i]); + + ret = velocity_alloc_rx_buf(vptr, i); + if (ret < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", + vptr->dev->name); + velocity_free_rd_ring(vptr); + goto out; + } + rd->rdesc0.owner = OWNED_BY_NIC; + } + vptr->rd_used = vptr->rd_curr = 0; +out: + return ret; +} + +/** + * velocity_free_rd_ring - set up receive ring + * @vptr: velocity to clean up + * + * Free the receive buffers for each ring slot and any + * attached socket buffers that need to go away. + */ + +static void velocity_free_rd_ring(struct velocity_info *vptr) +{ + int i; + + if (vptr->rd_info == NULL) + return; + + for (i = 0; i < vptr->options.numrx; i++) { + struct velocity_rd_info *rd_info = &(vptr->rd_info[i]); + + if (!rd_info->skb_dma) + continue; + pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + rd_info->skb_dma = (dma_addr_t) NULL; + + dev_kfree_skb(rd_info->skb); + rd_info->skb = NULL; + } + + kfree(vptr->rd_info); + vptr->rd_info = NULL; +} + +/** + * velocity_init_td_ring - set up transmit ring + * @vptr: velocity + * + * Set up the transmit ring and chain the ring pointers together. + * Returns zero on success or a negative posix errno code for + * failure. + */ + +static int velocity_init_td_ring(struct velocity_info *vptr) +{ + int i, j; + dma_addr_t curr; + struct tx_desc *td; + struct velocity_td_info *td_info; + unsigned int tsize = sizeof(struct velocity_td_info) * + vptr->options.numtx; + + /* Init the TD ring entries */ + for (j = 0; j < vptr->num_txq; j++) { + curr = vptr->td_pool_dma[j]; + + vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL); + if(vptr->td_infos[j] == NULL) + { + while(--j >= 0) + kfree(vptr->td_infos[j]); + return -ENOMEM; + } + memset(vptr->td_infos[j], 0, tsize); + + for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { + td = &(vptr->td_rings[j][i]); + td_info = &(vptr->td_infos[j][i]); + td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ; + td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ; + } + vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0; + } + return 0; +} + +/* + * FIXME: could we merge this with velocity_free_tx_buf ? + */ + +static void velocity_free_td_ring_entry(struct velocity_info *vptr, + int q, int n) +{ + struct velocity_td_info * td_info = &(vptr->td_infos[q][n]); + int i; + + if (td_info == NULL) + return; + + if (td_info->skb) { + for (i = 0; i < td_info->nskb_dma; i++) + { + if (td_info->skb_dma[i]) { + pci_unmap_single(vptr->pdev, td_info->skb_dma[i], + td_info->skb->len, PCI_DMA_TODEVICE); + td_info->skb_dma[i] = (dma_addr_t) NULL; + } + } + dev_kfree_skb(td_info->skb); + td_info->skb = NULL; + } +} + +/** + * velocity_free_td_ring - free td ring + * @vptr: velocity + * + * Free up the transmit ring for this particular velocity adapter. + * We free the ring contents but not the ring itself. + */ + +static void velocity_free_td_ring(struct velocity_info *vptr) +{ + int i, j; + + for (j = 0; j < vptr->num_txq; j++) { + if (vptr->td_infos[j] == NULL) + continue; + for (i = 0; i < vptr->options.numtx; i++) { + velocity_free_td_ring_entry(vptr, j, i); + + } + if (vptr->td_infos[j]) { + kfree(vptr->td_infos[j]); + vptr->td_infos[j] = NULL; + } + } +} + +/** + * velocity_rx_srv - service RX interrupt + * @vptr: velocity + * @status: adapter status (unused) + * + * Walk the receive ring of the velocity adapter and remove + * any received packets from the receive queue. Hand the ring + * slots back to the adapter for reuse. + */ + +static int velocity_rx_srv(struct velocity_info *vptr, int status) +{ + struct rx_desc *rd; + struct net_device_stats *stats = &vptr->stats; + struct mac_regs * regs = vptr->mac_regs; + int rd_curr = vptr->rd_curr; + int works = 0; + + while (1) { + + rd = &(vptr->rd_ring[rd_curr]); + + if ((vptr->rd_info[rd_curr]).skb == NULL) { + if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) + break; + } + + if (works++ > 15) + break; + + if (rd->rdesc0.owner == OWNED_BY_NIC) + break; + + /* + * Don't drop CE or RL error frame although RXOK is off + * FIXME: need to handle copybreak + */ + if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { + if (velocity_receive_frame(vptr, rd_curr) == 0) { + if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name); + break; + } + } else { + stats->rx_dropped++; + } + } else { + if (rd->rdesc0.RSR & RSR_CRC) + stats->rx_crc_errors++; + if (rd->rdesc0.RSR & RSR_FAE) + stats->rx_frame_errors++; + + stats->rx_dropped++; + } + + rd->inten = 1; + + if (++vptr->rd_used >= 4) { + int i, rd_prev = rd_curr; + for (i = 0; i < 4; i++) { + if (--rd_prev < 0) + rd_prev = vptr->options.numrx - 1; + + rd = &(vptr->rd_ring[rd_prev]); + rd->rdesc0.owner = OWNED_BY_NIC; + } + writew(4, &(regs->RBRDU)); + vptr->rd_used -= 4; + } + + vptr->dev->last_rx = jiffies; + + rd_curr++; + if (rd_curr >= vptr->options.numrx) + rd_curr = 0; + } + vptr->rd_curr = rd_curr; + VAR_USED(stats); + return works; +} + +/** + * velocity_rx_csum - checksum process + * @rd: receive packet descriptor + * @skb: network layer packet buffer + * + * Process the status bits for the received packet and determine + * if the checksum was computed and verified by the hardware + */ + +static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + if (rd->rdesc1.CSM & CSM_IPKT) { + if (rd->rdesc1.CSM & CSM_IPOK) { + if ((rd->rdesc1.CSM & CSM_TCPKT) || + (rd->rdesc1.CSM & CSM_UDPKT)) { + if (!(rd->rdesc1.CSM & CSM_TUPOK)) { + return; + } + } + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + } +} + +/** + * velocity_receive_frame - received packet processor + * @vptr: velocity we are handling + * @idx: ring index + * + * A packet has arrived. We process the packet and if appropriate + * pass the frame up the network stack + */ + +static int velocity_receive_frame(struct velocity_info *vptr, int idx) +{ + struct net_device_stats *stats = &vptr->stats; + struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); + struct rx_desc *rd = &(vptr->rd_ring[idx]); + struct sk_buff *skb; + + if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { + VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name); + stats->rx_length_errors++; + return -EINVAL; + } + + if (rd->rdesc0.RSR & RSR_MAR) + vptr->stats.multicast++; + + skb = rd_info->skb; + skb->dev = vptr->dev; + + pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + rd_info->skb_dma = (dma_addr_t) NULL; + rd_info->skb = NULL; + + /* FIXME - memmove ? */ + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + int i; + for (i = rd->rdesc0.len + 4; i >= 0; i--) + *(skb->data + i + 2) = *(skb->data + i); + skb->data += 2; + skb->tail += 2; + } + + skb_put(skb, (rd->rdesc0.len - 4)); + skb->protocol = eth_type_trans(skb, skb->dev); + + /* + * Drop frame not meeting IEEE 802.3 + */ + + if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { + if (rd->rdesc0.RSR & RSR_RL) { + stats->rx_length_errors++; + return -EINVAL; + } + } + + velocity_rx_csum(rd, skb); + + /* + * FIXME: need rx_copybreak handling + */ + + stats->rx_bytes += skb->len; + netif_rx(skb); + + return 0; +} + +/** + * velocity_alloc_rx_buf - allocate aligned receive buffer + * @vptr: velocity + * @idx: ring index + * + * Allocate a new full sized buffer for the reception of a frame and + * map it into PCI space for the hardware to use. The hardware + * requires *64* byte alignment of the buffer which makes life + * less fun than would be ideal. + */ + +static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) +{ + struct rx_desc *rd = &(vptr->rd_ring[idx]); + struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); + + rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64); + if (rd_info->skb == NULL) + return -ENOMEM; + + /* + * Do the gymnastics to get the buffer head for data at + * 64byte alignment. + */ + skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63); + rd_info->skb->dev = vptr->dev; + rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); + + /* + * Fill in the descriptor to match + */ + + *((u32 *) & (rd->rdesc0)) = 0; + rd->len = cpu_to_le32(vptr->rx_buf_sz); + rd->inten = 1; + rd->pa_low = cpu_to_le32(rd_info->skb_dma); + rd->pa_high = 0; + return 0; +} + +/** + * tx_srv - transmit interrupt service + * @vptr; Velocity + * @status: + * + * Scan the queues looking for transmitted packets that + * we can complete and clean up. Update any statistics as + * neccessary/ + */ + +static int velocity_tx_srv(struct velocity_info *vptr, u32 status) +{ + struct tx_desc *td; + int qnum; + int full = 0; + int idx; + int works = 0; + struct velocity_td_info *tdinfo; + struct net_device_stats *stats = &vptr->stats; + + for (qnum = 0; qnum < vptr->num_txq; qnum++) { + for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0; + idx = (idx + 1) % vptr->options.numtx) { + + /* + * Get Tx Descriptor + */ + td = &(vptr->td_rings[qnum][idx]); + tdinfo = &(vptr->td_infos[qnum][idx]); + + if (td->tdesc0.owner == OWNED_BY_NIC) + break; + + if ((works++ > 15)) + break; + + if (td->tdesc0.TSR & TSR0_TERR) { + stats->tx_errors++; + stats->tx_dropped++; + if (td->tdesc0.TSR & TSR0_CDH) + stats->tx_heartbeat_errors++; + if (td->tdesc0.TSR & TSR0_CRS) + stats->tx_carrier_errors++; + if (td->tdesc0.TSR & TSR0_ABT) + stats->tx_aborted_errors++; + if (td->tdesc0.TSR & TSR0_OWC) + stats->tx_window_errors++; + } else { + stats->tx_packets++; + stats->tx_bytes += tdinfo->skb->len; + } + velocity_free_tx_buf(vptr, tdinfo); + vptr->td_used[qnum]--; + } + vptr->td_tail[qnum] = idx; + + if (AVAIL_TD(vptr, qnum) < 1) { + full = 1; + } + } + /* + * Look to see if we should kick the transmit network + * layer for more work. + */ + if (netif_queue_stopped(vptr->dev) && (full == 0) + && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { + netif_wake_queue(vptr->dev); + } + return works; +} + +/** + * velocity_print_link_status - link status reporting + * @vptr: velocity to report on + * + * Turn the link status of the velocity card into a kernel log + * description of the new link state, detailing speed and duplex + * status + */ + +static void velocity_print_link_status(struct velocity_info *vptr) +{ + + if (vptr->mii_status & VELOCITY_LINK_FAIL) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); + } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link autonegation", vptr->dev->name); + + if (vptr->mii_status & VELOCITY_SPEED_1000) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); + else if (vptr->mii_status & VELOCITY_SPEED_100) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); + + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); + } else { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); + switch (vptr->options.spd_dpx) { + case SPD_DPX_100_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); + break; + case SPD_DPX_100_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); + break; + case SPD_DPX_10_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); + break; + case SPD_DPX_10_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); + break; + default: + break; + } + } +} + +/** + * velocity_error - handle error from controller + * @vptr: velocity + * @status: card status + * + * Process an error report from the hardware and attempt to recover + * the card itself. At the moment we cannot recover from some + * theoretically impossible errors but this could be fixed using + * the pci_device_failed logic to bounce the hardware + * + */ + +static void velocity_error(struct velocity_info *vptr, int status) +{ + + if (status & ISR_TXSTLI) { + struct mac_regs * regs = vptr->mac_regs; + + printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(®s->TDIdx[0])); + BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); + writew(TRDCSR_RUN, ®s->TDCSRClr); + netif_stop_queue(vptr->dev); + + /* FIXME: port over the pci_device_failed code and use it + here */ + } + + if (status & ISR_SRCI) { + struct mac_regs * regs = vptr->mac_regs; + int linked; + + if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + vptr->mii_status = check_connection_type(regs); + + /* + * If it is a 3119, disable frame bursting in + * halfduplex mode and enable it in fullduplex + * mode + */ + if (vptr->rev_id < REV_ID_VT3216_A0) { + if (vptr->mii_status | VELOCITY_DUPLEX_FULL) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + else + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } + /* + * Only enable CD heart beat counter in 10HD mode + */ + if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) { + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + } else { + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + } + } + /* + * Get link status from PHYSR0 + */ + linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; + + if (linked) { + vptr->mii_status &= ~VELOCITY_LINK_FAIL; + } else { + vptr->mii_status |= VELOCITY_LINK_FAIL; + } + + velocity_print_link_status(vptr); + enable_flow_control_ability(vptr); + + /* + * Re-enable auto-polling because SRCI will disable + * auto-polling + */ + + enable_mii_autopoll(regs); + + if (vptr->mii_status & VELOCITY_LINK_FAIL) + netif_stop_queue(vptr->dev); + else + netif_wake_queue(vptr->dev); + + }; + if (status & ISR_MIBFI) + velocity_update_hw_mibs(vptr); + if (status & ISR_LSTEI) + mac_rx_queue_wake(vptr->mac_regs); +} + +/** + * velocity_free_tx_buf - free transmit buffer + * @vptr: velocity + * @tdinfo: buffer + * + * Release an transmit buffer. If the buffer was preallocated then + * recycle it, if not then unmap the buffer. + */ + +static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) +{ + struct sk_buff *skb = tdinfo->skb; + int i; + + /* + * Don't unmap the pre-allocated tx_bufs + */ + if (tdinfo->skb_dma && (tdinfo->skb_dma[0] != tdinfo->buf_dma)) { + + for (i = 0; i < tdinfo->nskb_dma; i++) { +#ifdef VELOCITY_ZERO_COPY_SUPPORT + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE); +#else + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE); +#endif + tdinfo->skb_dma[i] = 0; + } + } + dev_kfree_skb_irq(skb); + tdinfo->skb = NULL; +} + +/** + * velocity_open - interface activation callback + * @dev: network layer device to open + * + * Called when the network layer brings the interface up. Returns + * a negative posix error code on failure, or zero on success. + * + * All the ring allocation and set up is done on open for this + * adapter to minimise memory usage when inactive + */ + +static int velocity_open(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + int ret; + + vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32); + + ret = velocity_init_rings(vptr); + if (ret < 0) + goto out; + + ret = velocity_init_rd_ring(vptr); + if (ret < 0) + goto err_free_desc_rings; + + ret = velocity_init_td_ring(vptr); + if (ret < 0) + goto err_free_rd_ring; + + /* Ensure chip is running */ + pci_set_power_state(vptr->pdev, 0); + + velocity_init_registers(vptr, VELOCITY_INIT_COLD); + + ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ, + dev->name, dev); + if (ret < 0) { + /* Power down the chip */ + pci_set_power_state(vptr->pdev, 3); + goto err_free_td_ring; + } + + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); + vptr->flags |= VELOCITY_FLAGS_OPENED; +out: + return ret; + +err_free_td_ring: + velocity_free_td_ring(vptr); +err_free_rd_ring: + velocity_free_rd_ring(vptr); +err_free_desc_rings: + velocity_free_rings(vptr); + goto out; +} + +/** + * velocity_change_mtu - MTU change callback + * @dev: network device + * @new_mtu: desired MTU + * + * Handle requests from the networking layer for MTU change on + * this interface. It gets called on a change by the network layer. + * Return zero for success or negative posix error code. + */ + +static int velocity_change_mtu(struct net_device *dev, int new_mtu) +{ + struct velocity_info *vptr = dev->priv; + unsigned long flags; + int oldmtu = dev->mtu; + int ret = 0; + + if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", + vptr->dev->name); + return -EINVAL; + } + + if (new_mtu != oldmtu) { + spin_lock_irqsave(&vptr->lock, flags); + + netif_stop_queue(dev); + velocity_shutdown(vptr); + + velocity_free_td_ring(vptr); + velocity_free_rd_ring(vptr); + + dev->mtu = new_mtu; + if (new_mtu > 8192) + vptr->rx_buf_sz = 9 * 1024; + else if (new_mtu > 4096) + vptr->rx_buf_sz = 8192; + else + vptr->rx_buf_sz = 4 * 1024; + + ret = velocity_init_rd_ring(vptr); + if (ret < 0) + goto out_unlock; + + ret = velocity_init_td_ring(vptr); + if (ret < 0) + goto out_unlock; + + velocity_init_registers(vptr, VELOCITY_INIT_COLD); + + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); +out_unlock: + spin_unlock_irqrestore(&vptr->lock, flags); + } + + return ret; +} + +/** + * velocity_shutdown - shut down the chip + * @vptr: velocity to deactivate + * + * Shuts down the internal operations of the velocity and + * disables interrupts, autopolling, transmit and receive + */ + +static void velocity_shutdown(struct velocity_info *vptr) +{ + struct mac_regs * regs = vptr->mac_regs; + mac_disable_int(regs); + writel(CR0_STOP, ®s->CR0Set); + writew(0xFFFF, ®s->TDCSRClr); + writeb(0xFF, ®s->RDCSRClr); + safe_disable_mii_autopoll(regs); + mac_clear_isr(regs); +} + +/** + * velocity_close - close adapter callback + * @dev: network device + * + * Callback from the network layer when the velocity is being + * deactivated by the network layer + */ + +static int velocity_close(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + + netif_stop_queue(dev); + velocity_shutdown(vptr); + + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) + velocity_get_ip(vptr); + if (dev->irq != 0) + free_irq(dev->irq, dev); + + /* Power down the chip */ + pci_set_power_state(vptr->pdev, 3); + + /* Free the resources */ + velocity_free_td_ring(vptr); + velocity_free_rd_ring(vptr); + velocity_free_rings(vptr); + + vptr->flags &= (~VELOCITY_FLAGS_OPENED); + return 0; +} + +/** + * velocity_xmit - transmit packet callback + * @skb: buffer to transmit + * @dev: network device + * + * Called by the networ layer to request a packet is queued to + * the velocity. Returns zero on success. + */ + +static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + int qnum = 0; + struct tx_desc *td_ptr; + struct velocity_td_info *tdinfo; + unsigned long flags; + int index; + + int pktlen = skb->len; + + spin_lock_irqsave(&vptr->lock, flags); + + index = vptr->td_curr[qnum]; + td_ptr = &(vptr->td_rings[qnum][index]); + tdinfo = &(vptr->td_infos[qnum][index]); + + td_ptr->tdesc1.TCPLS = TCPLS_NORMAL; + td_ptr->tdesc1.TCR = TCR0_TIC; + td_ptr->td_buf[0].queue = 0; + + /* + * Pad short frames. + */ + if (pktlen < ETH_ZLEN) { + /* Cannot occur until ZC support */ + if(skb_linearize(skb, GFP_ATOMIC)) + return 0; + pktlen = ETH_ZLEN; + memcpy(tdinfo->buf, skb->data, skb->len); + memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); + tdinfo->skb = skb; + tdinfo->skb_dma[0] = tdinfo->buf_dma; + td_ptr->tdesc0.pktsize = pktlen; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; + tdinfo->nskb_dma = 1; + td_ptr->tdesc1.CMDZ = 2; + } else +#ifdef VELOCITY_ZERO_COPY_SUPPORT + if (skb_shinfo(skb)->nr_frags > 0) { + int nfrags = skb_shinfo(skb)->nr_frags; + tdinfo->skb = skb; + if (nfrags > 6) { + skb_linearize(skb, GFP_ATOMIC); + memcpy(tdinfo->buf, skb->data, skb->len); + tdinfo->skb_dma[0] = tdinfo->buf_dma; + td_ptr->tdesc0.pktsize = + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; + tdinfo->nskb_dma = 1; + td_ptr->tdesc1.CMDZ = 2; + } else { + int i = 0; + tdinfo->nskb_dma = 0; + tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE); + + td_ptr->tdesc0.pktsize = pktlen; + + /* FIXME: support 48bit DMA later */ + td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma); + td_ptr->td_buf[i].pa_high = 0; + td_ptr->td_buf[i].bufsize = skb->len->skb->data_len; + + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + void *addr = ((void *) page_address(frag->page + frag->page_offset)); + + tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE); + + td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]); + td_ptr->td_buf[i + 1].pa_high = 0; + td_ptr->td_buf[i + 1].bufsize = frag->size; + } + tdinfo->nskb_dma = i - 1; + td_ptr->tdesc1.CMDZ = i; + } + + } else +#endif + { + /* + * Map the linear network buffer into PCI space and + * add it to the transmit ring. + */ + tdinfo->skb = skb; + tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); + td_ptr->tdesc0.pktsize = pktlen; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; + tdinfo->nskb_dma = 1; + td_ptr->tdesc1.CMDZ = 2; + } + + if (vptr->flags & VELOCITY_FLAGS_TAGGING) { + td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff); + td_ptr->tdesc1.pqinf.priority = 0; + td_ptr->tdesc1.pqinf.CFI = 0; + td_ptr->tdesc1.TCR |= TCR0_VETAG; + } + + /* + * Handle hardware checksum + */ + if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) + && (skb->ip_summed == CHECKSUM_HW)) { + struct iphdr *ip = skb->nh.iph; + if (ip->protocol == IPPROTO_TCP) + td_ptr->tdesc1.TCR |= TCR0_TCPCK; + else if (ip->protocol == IPPROTO_UDP) + td_ptr->tdesc1.TCR |= (TCR0_UDPCK); + td_ptr->tdesc1.TCR |= TCR0_IPCK; + } + { + + int prev = index - 1; + + if (prev < 0) + prev = vptr->options.numtx - 1; + td_ptr->tdesc0.owner = OWNED_BY_NIC; + vptr->td_used[qnum]++; + vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx; + + if (AVAIL_TD(vptr, qnum) < 1) + netif_stop_queue(dev); + + td_ptr = &(vptr->td_rings[qnum][prev]); + td_ptr->td_buf[0].queue = 1; + mac_tx_queue_wake(vptr->mac_regs, qnum); + } + dev->trans_start = jiffies; + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +/** + * velocity_intr - interrupt callback + * @irq: interrupt number + * @dev_instance: interrupting device + * @pt_regs: CPU register state at interrupt + * + * Called whenever an interrupt is generated by the velocity + * adapter IRQ line. We may not be the source of the interrupt + * and need to identify initially if we are, and if not exit as + * efficiently as possible. + */ + +static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = dev_instance; + struct velocity_info *vptr = dev->priv; + u32 isr_status; + int max_count = 0; + + + spin_lock(&vptr->lock); + isr_status = mac_read_isr(vptr->mac_regs); + + /* Not us ? */ + if (isr_status == 0) { + spin_unlock(&vptr->lock); + return IRQ_NONE; + } + + mac_disable_int(vptr->mac_regs); + + /* + * Keep processing the ISR until we have completed + * processing and the isr_status becomes zero + */ + + while (isr_status != 0) { + mac_write_isr(vptr->mac_regs, isr_status); + if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) + velocity_error(vptr, isr_status); + if (isr_status & (ISR_PRXI | ISR_PPRXI)) + max_count += velocity_rx_srv(vptr, isr_status); + if (isr_status & (ISR_PTXI | ISR_PPTXI)) + max_count += velocity_tx_srv(vptr, isr_status); + isr_status = mac_read_isr(vptr->mac_regs); + if (max_count > vptr->options.int_works) + { + printk(KERN_WARNING "%s: excessive work at interrupt.\n", + dev->name); + max_count = 0; + } + } + spin_unlock(&vptr->lock); + mac_enable_int(vptr->mac_regs); + return IRQ_HANDLED; + +} + + +/** + * ether_crc - ethernet CRC function + * + * Compute an ethernet CRC hash of the data block provided. This + * is not performance optimised but is not needed in performance + * critical code paths. + * + * FIXME: could we use shared code here ? + */ + +static inline u32 ether_crc(int length, unsigned char *data) +{ + static unsigned const ethernet_polynomial = 0x04c11db7U; + + int crc = -1; + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) { + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + } + return crc; +} + +/** + * velocity_set_multi - filter list change callback + * @dev: network device + * + * Called by the network layer when the filter lists need to change + * for a velocity adapter. Reload the CAMs with the new address + * filter ruleset. + */ + +static void velocity_set_multi(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + struct mac_regs * regs = vptr->mac_regs; + u8 rx_mode; + int i; + struct dev_mc_list *mclist; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB | RCR_PROM); + } else if ((dev->mc_count > vptr->multicast_limit) + || (dev->flags & IFF_ALLMULTI)) { + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB); + } else { + int offset = MCAM_SIZE - vptr->multicast_limit; + mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM); + vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); + } + + mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + rx_mode = (RCR_AM | RCR_AB); + } + if (dev->mtu > 1500) + rx_mode |= RCR_AL; + + BYTE_REG_BITS_ON(rx_mode, ®s->RCR); + +} + +/** + * velocity_get_status - statistics callback + * @dev: network device + * + * Callback from the network layer to allow driver statistics + * to be resynchronized with hardware collected state. In the + * case of the velocity we need to pull the MIB counters from + * the hardware into the counters before letting the network + * layer display them. + */ + +static struct net_device_stats *velocity_get_stats(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + + /* If the hardware is down, don't touch MII */ + if(!netif_running(dev)) + return &vptr->stats; + + spin_lock_irq(&vptr->lock); + velocity_update_hw_mibs(vptr); + spin_unlock_irq(&vptr->lock); + + vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + +// unsigned long rx_dropped; /* no space in linux buffers */ + vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + /* detailed rx_errors: */ +// unsigned long rx_length_errors; +// unsigned long rx_over_errors; /* receiver ring buff overflow */ + vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; +// unsigned long rx_frame_errors; /* recv'd frame alignment error */ +// unsigned long rx_fifo_errors; /* recv'r fifo overrun */ +// unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ +// unsigned long tx_fifo_errors; + + return &vptr->stats; +} + + +/** + * velocity_ioctl - ioctl entry point + * @dev: network device + * @rq: interface request ioctl + * @cmd: command code + * + * Called when the user issues an ioctl request to the network + * device in question. The velocity interface supports MII. + */ + +static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct velocity_info *vptr = dev->priv; + int ret; + + /* If we are asked for information and the device is power + saving then we need to bring the device back up to talk to it */ + + if(!netif_running(dev)) + pci_set_power_state(vptr->pdev, 0); + + switch (cmd) { + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCSMIIREG: /* Write to MII PHY register. */ + ret = velocity_mii_ioctl(dev, rq, cmd); + break; + + default: + ret = -EOPNOTSUPP; + } + if(!netif_running(dev)) + pci_set_power_state(vptr->pdev, 3); + + + return ret; +} + +/* + * Definition for our device driver. The PCI layer interface + * uses this to handle all our card discover and plugging + */ + +static struct pci_driver velocity_driver = { + name:VELOCITY_NAME, + id_table:velocity_id_table, + probe:velocity_found1, + remove:velocity_remove1, +#ifdef CONFIG_PM + suspend:velocity_suspend, + resume:velocity_resume, +#endif +}; + +/** + * velocity_init_module - load time function + * + * Called when the velocity module is loaded. The PCI driver + * is registered with the PCI layer, and in turn will call + * the probe functions for each velocity adapter installed + * in the system. + */ + +static int __init velocity_init_module(void) +{ + int ret; + ret = pci_module_init(&velocity_driver); + +#ifdef CONFIG_PM + register_inetaddr_notifier(&velocity_inetaddr_notifier); +#endif + return ret; +} + +/** + * velocity_cleanup - module unload + * + * When the velocity hardware is unloaded this function is called. + * It will clean up the notifiers and the unregister the PCI + * driver interface for this hardware. This in turn cleans up + * all discovered interfaces before returning from the function + */ + +static void __exit velocity_cleanup_module(void) +{ +#ifdef CONFIG_PM + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); +#endif + pci_unregister_driver(&velocity_driver); +} + +module_init(velocity_init_module); +module_exit(velocity_cleanup_module); + + +/* + * MII access , media link mode setting functions + */ + + +/** + * mii_init - set up MII + * @vptr: velocity adapter + * @mii_status: links tatus + * + * Set up the PHY for the current link state. + */ + +static void mii_init(struct velocity_info *vptr, u32 mii_status) +{ + u16 BMCR; + + switch (PHYID_GET_PHY_ID(vptr->phy_id)) { + case PHYID_CICADA_CS8201: + /* + * Reset to hardware default + */ + MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue. + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + /* + * Turn on Link/Activity LED enable bit for CIS8201 + */ + MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); + break; + case PHYID_VT3216_32BIT: + case PHYID_VT3216_64BIT: + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + break; + + case PHYID_MARVELL_1000: + case PHYID_MARVELL_1000S: + /* + * Assert CRS on Transmit + */ + MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + break; + default: + ; + } + velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); + if (BMCR & BMCR_ISO) { + BMCR &= ~BMCR_ISO; + velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); + } +} + +/** + * safe_disable_mii_autopoll - autopoll off + * @regs: velocity registers + * + * Turn off the autopoll and wait for it to disable on the chip + */ + +static void safe_disable_mii_autopoll(struct mac_regs * regs) +{ + u16 ww; + + /* turn off MAUTO */ + writeb(0, ®s->MIICR); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } +} + +/** + * enable_mii_autopoll - turn on autopolling + * @regs: velocity registers + * + * Enable the MII link status autopoll feature on the Velocity + * hardware. Wait for it to enable. + */ + +static void enable_mii_autopoll(struct mac_regs * regs) +{ + int ii; + + writeb(0, &(regs->MIICR)); + writeb(MIIADR_SWMPL, ®s->MIIADR); + + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } + + writeb(MIICR_MAUTO, ®s->MIICR); + + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } + +} + +/** + * velocity_mii_read - read MII data + * @regs: velocity registers + * @index: MII register index + * @data: buffer for received data + * + * Perform a single read of an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. + */ + +static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data) +{ + u16 ww; + + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally + */ + safe_disable_mii_autopoll(regs); + + writeb(index, ®s->MIIADR); + + BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); + + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + if (!(readb(®s->MIICR) & MIICR_RCMD)) + break; + } + + *data = readw(®s->MIIDATA); + + enable_mii_autopoll(regs); + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; +} + +/** + * velocity_mii_write - write MII data + * @regs: velocity registers + * @index: MII register index + * @data: 16bit data for the MII register + * + * Perform a single write to an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. + */ + +static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data) +{ + u16 ww; + + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally + */ + safe_disable_mii_autopoll(regs); + + /* MII reg offset */ + writeb(mii_addr, ®s->MIIADR); + /* set MII data */ + writew(data, ®s->MIIDATA); + + /* turn on MIICR_WCMD */ + BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); + + /* W_MAX_TIMEOUT is the timeout period */ + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(5); + if (!(readb(®s->MIICR) & MIICR_WCMD)) + break; + } + enable_mii_autopoll(regs); + + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; +} + +/** + * velocity_get_opt_media_mode - get media selection + * @vptr: velocity adapter + * + * Get the media mode stored in EEPROM or module options and load + * mii_status accordingly. The requested link state information + * is also returned. + */ + +static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) +{ + u32 status = 0; + + switch (vptr->options.spd_dpx) { + case SPD_DPX_AUTO: + status = VELOCITY_AUTONEG_ENABLE; + break; + case SPD_DPX_100_FULL: + status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_10_FULL: + status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_100_HALF: + status = VELOCITY_SPEED_100; + break; + case SPD_DPX_10_HALF: + status = VELOCITY_SPEED_10; + break; + } + vptr->mii_status = status; + return status; +} + +/** + * mii_set_auto_on - autonegotiate on + * @vptr: velocity + * + * Enable autonegotation on this interface + */ + +static void mii_set_auto_on(struct velocity_info *vptr) +{ + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) + MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); + else + MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +} + + +/* +static void mii_set_auto_off(struct velocity_info * vptr) +{ + MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +} +*/ + +/** + * set_mii_flow_control - flow control setup + * @vptr: velocity interface + * + * Set up the flow control on this interface according to + * the supplied user/eeprom options. + */ + +static void set_mii_flow_control(struct velocity_info *vptr) +{ + /*Enable or Disable PAUSE in ANAR */ + switch (vptr->options.flow_cntl) { + case FLOW_CNTL_TX: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + + case FLOW_CNTL_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + + case FLOW_CNTL_TX_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + + case FLOW_CNTL_DISABLE: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + default: + break; + } +} + +/** + * velocity_set_media_mode - set media mode + * @mii_status: old MII link state + * + * Check the media link state and configure the flow control + * PHY and also velocity hardware setup accordingly. In particular + * we need to set up CD polling and frame bursting. + */ + +static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) +{ + u32 curr_status; + struct mac_regs * regs = vptr->mac_regs; + + vptr->mii_status = mii_check_media_mode(vptr->mac_regs); + curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); + + /* Set mii link status */ + set_mii_flow_control(vptr); + + /* + Check if new status is consisent with current status + if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) + || (mii_status==curr_status)) { + vptr->mii_status=mii_check_media_mode(vptr->mac_regs); + vptr->mii_status=check_connection_type(vptr->mac_regs); + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); + return 0; + } + */ + + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) { + MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); + } + + /* + * If connection type is AUTO + */ + if (mii_status & VELOCITY_AUTONEG_ENABLE) { + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n"); + /* clear force MAC mode bit */ + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* set duplex mode of MAC according to duplex mode of MII */ + MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); + + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + } else { + u16 ANAR; + u8 CHIPGCR; + + /* + * 1. if it's 3119, disable frame bursting in halfduplex mode + * and enable it in fullduplex mode + * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR + * 3. only enable CD heart beat counter in 10HD mode + */ + + /* set force MAC mode bit */ + BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); + + CHIPGCR = readb(®s->CHIPGCR); + CHIPGCR &= ~CHIPGCR_FCGMII; + + if (mii_status & VELOCITY_DUPLEX_FULL) { + CHIPGCR |= CHIPGCR_FCFDX; + writeb(CHIPGCR, ®s->CHIPGCR); + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n"); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } else { + CHIPGCR &= ~CHIPGCR_FCFDX; + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n"); + writeb(CHIPGCR, ®s->CHIPGCR); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + } + + MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + + if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) { + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + } else { + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + } + /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ + velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); + ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); + if (mii_status & VELOCITY_SPEED_100) { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_TXFD; + else + ANAR |= ANAR_TX; + } else { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_10FD; + else + ANAR |= ANAR_10; + } + velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ + } + /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ + /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ + return VELOCITY_LINK_CHANGE; +} + +/** + * mii_check_media_mode - check media state + * @regs: velocity registers + * + * Check the current MII status and determine the link status + * accordingly + */ + +static u32 mii_check_media_mode(struct mac_regs * regs) +{ + u32 status = 0; + u16 ANAR; + + if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) + status |= VELOCITY_LINK_FAIL; + + if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; + else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) + status |= (VELOCITY_SPEED_1000); + else { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if (ANAR & ANAR_TXFD) + status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); + else if (ANAR & ANAR_TX) + status |= VELOCITY_SPEED_100; + else if (ANAR & ANAR_10FD) + status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); + else + status |= (VELOCITY_SPEED_10); + } + + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } + } + + return status; +} + +static u32 check_connection_type(struct mac_regs * regs) +{ + u32 status = 0; + u8 PHYSR0; + u16 ANAR; + PHYSR0 = readb(®s->PHYSR0); + + /* + if (!(PHYSR0 & PHYSR0_LINKGD)) + status|=VELOCITY_LINK_FAIL; + */ + + if (PHYSR0 & PHYSR0_FDPX) + status |= VELOCITY_DUPLEX_FULL; + + if (PHYSR0 & PHYSR0_SPDG) + status |= VELOCITY_SPEED_1000; + if (PHYSR0 & PHYSR0_SPD10) + status |= VELOCITY_SPEED_10; + else + status |= VELOCITY_SPEED_100; + + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } + } + + return status; +} + +/** + * enable_flow_control_ability - flow control + * @vptr: veloity to configure + * + * Set up flow control according to the flow control options + * determined by the eeprom/configuration. + */ + +static void enable_flow_control_ability(struct velocity_info *vptr) +{ + + struct mac_regs * regs = vptr->mac_regs; + + switch (vptr->options.flow_cntl) { + + case FLOW_CNTL_DEFAULT: + if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) + writel(CR0_FDXRFCEN, ®s->CR0Set); + else + writel(CR0_FDXRFCEN, ®s->CR0Clr); + + if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) + writel(CR0_FDXTFCEN, ®s->CR0Set); + else + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_RX: + writel(CR0_FDXRFCEN, ®s->CR0Set); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX_RX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Set); + break; + + case FLOW_CNTL_DISABLE: + writel(CR0_FDXRFCEN, ®s->CR0Clr); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + default: + break; + } + +} + + +/** + * velocity_ethtool_up - pre hook for ethtool + * @dev: network device + * + * Called before an ethtool operation. We need to make sure the + * chip is out of D3 state before we poke at it. + */ + +static int velocity_ethtool_up(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + if(!netif_running(dev)) + pci_set_power_state(vptr->pdev, 0); + return 0; +} + +/** + * velocity_ethtool_down - post hook for ethtool + * @dev: network device + * + * Called after an ethtool operation. Restore the chip back to D3 + * state if it isn't running. + */ + +static void velocity_ethtool_down(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + if(!netif_running(dev)) + pci_set_power_state(vptr->pdev, 3); +} + +static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = dev->priv; + struct mac_regs * regs = vptr->mac_regs; + u32 status; + status = check_connection_type(vptr->mac_regs); + + cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + if (status & VELOCITY_SPEED_100) + cmd->speed = SPEED_100; + else + cmd->speed = SPEED_10; + cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->port = PORT_TP; + cmd->transceiver = XCVR_INTERNAL; + cmd->phy_address = readb(®s->MIIADR) & 0x1F; + + if (status & VELOCITY_DUPLEX_FULL) + cmd->duplex = DUPLEX_FULL; + else + cmd->duplex = DUPLEX_HALF; + + return 0; +} + +static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = dev->priv; + u32 curr_status; + u32 new_status = 0; + int ret = 0; + + curr_status = check_connection_type(vptr->mac_regs); + curr_status &= (~VELOCITY_LINK_FAIL); + + new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); + new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); + new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); + new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); + + if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) + ret = -EINVAL; + else + velocity_set_media_mode(vptr, new_status); + + return ret; +} + +static u32 velocity_get_link(struct net_device *dev) +{ + struct velocity_info *vptr = dev->priv; + struct mac_regs * regs = vptr->mac_regs; + return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 0 : 1; +} + +static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct velocity_info *vptr = dev->priv; + strcpy(info->driver, VELOCITY_NAME); + strcpy(info->version, VELOCITY_VERSION); + strcpy(info->bus_info, vptr->pdev->slot_name); +} + +static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = dev->priv; + wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; + wol->wolopts |= WAKE_MAGIC; + /* + if (vptr->wol_opts & VELOCITY_WOL_PHY) + wol.wolopts|=WAKE_PHY; + */ + if (vptr->wol_opts & VELOCITY_WOL_UCAST) + wol->wolopts |= WAKE_UCAST; + if (vptr->wol_opts & VELOCITY_WOL_ARP) + wol->wolopts |= WAKE_ARP; + memcpy(&wol->sopass, vptr->wol_passwd, 6); +} + +static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = dev->priv; + + if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) + return -EFAULT; + vptr->wol_opts = VELOCITY_WOL_MAGIC; + + /* + if (wol.wolopts & WAKE_PHY) { + vptr->wol_opts|=VELOCITY_WOL_PHY; + vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED; + } + */ + + if (wol->wolopts & WAKE_MAGIC) { + vptr->wol_opts |= VELOCITY_WOL_MAGIC; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_UCAST) { + vptr->wol_opts |= VELOCITY_WOL_UCAST; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_ARP) { + vptr->wol_opts |= VELOCITY_WOL_ARP; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + memcpy(vptr->wol_passwd, wol->sopass, 6); + return 0; +} + +static u32 velocity_get_msglevel(struct net_device *dev) +{ + return msglevel; +} + +static void velocity_set_msglevel(struct net_device *dev, u32 value) +{ + msglevel = value; +} + +static struct ethtool_ops velocity_ethtool_ops = { + .get_settings = velocity_get_settings, + .set_settings = velocity_set_settings, + .get_drvinfo = velocity_get_drvinfo, + .get_wol = velocity_ethtool_get_wol, + .set_wol = velocity_ethtool_set_wol, + .get_msglevel = velocity_get_msglevel, + .set_msglevel = velocity_set_msglevel, + .get_link = velocity_get_link, + .begin = velocity_ethtool_up, + .complete = velocity_ethtool_down +}; + +/** + * velocity_mii_ioctl - MII ioctl handler + * @dev: network device + * @ifr: the ifreq block for the ioctl + * @cmd: the command + * + * Process MII requests made via ioctl from the network layer. These + * are used by tools like kudzu to interrogate the link state of the + * hardware + */ + +static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct velocity_info *vptr = dev->priv; + struct mac_regs * regs = vptr->mac_regs; + unsigned long flags; + struct mii_ioctl_data *miidata = (struct mii_ioctl_data *) &(ifr->ifr_data); + int err; + + switch (cmd) { + case SIOCGMIIPHY: + miidata->phy_id = readb(®s->MIIADR) & 0x1f; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) + return -ETIMEDOUT; + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&vptr->lock, flags); + err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); + spin_unlock_irqrestore(&vptr->lock, flags); + check_connection_type(vptr->mac_regs); + if(err) + return err; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +#ifdef CONFIG_PM + +/** + * velocity_save_context - save registers + * @vptr: velocity + * @context: buffer for stored context + * + * Retrieve the current configuration from the velocity hardware + * and stash it in the context structure, for use by the context + * restore functions. This allows us to save things we need across + * power down states + */ + +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context) +{ + struct mac_regs * regs = vptr->mac_regs; + u16 i; + u8 *ptr = (u8 *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + +} + +/** + * velocity_restore_context - restore registers + * @vptr: velocity + * @context: buffer for stored context + * + * Reload the register configuration from the velocity context + * created by velocity_save_context. + */ + +static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) +{ + struct mac_regs * regs = vptr->mac_regs; + int i; + u8 *ptr = (u8 *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) { + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + } + + /* Just skip cr0 */ + for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { + /* Clear */ + writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4); + /* Set */ + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + } + + for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) { + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + } + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) { + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + } + + for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) { + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + } + +} + +static int velocity_suspend(struct pci_dev *pdev, u32 state) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + + if(!netif_running(vptr->dev)) + return 0; + + netif_device_detach(vptr->dev); + + spin_lock_irqsave(&vptr->lock, flags); + pci_save_state(pdev, vptr->pci_state); +#ifdef ETHTOOL_GWOL + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { + velocity_get_ip(vptr); + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + velocity_set_wol(vptr); + pci_enable_wake(pdev, 3, 1); + pci_set_power_state(pdev, 3); + } else { + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + } +#else + pci_set_power_state(pdev, state); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +static int velocity_resume(struct pci_dev *pdev) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + int i; + + if(!netif_running(vptr->dev)) + return 0; + + pci_set_power_state(pdev, 0); + pci_enable_wake(pdev, 0, 0); + pci_restore_state(pdev, vptr->pci_state); + + mac_wol_reset(vptr->mac_regs); + + spin_lock_irqsave(&vptr->lock, flags); + velocity_restore_context(vptr, &vptr->context); + velocity_init_registers(vptr, VELOCITY_INIT_WOL); + mac_disable_int(vptr->mac_regs); + + velocity_tx_srv(vptr, 0); + + for (i = 0; i < vptr->num_txq; i++) { + if (vptr->td_used[i]) { + mac_tx_queue_wake(vptr->mac_regs, i); + } + } + + mac_enable_int(vptr->mac_regs); + spin_unlock_irqrestore(&vptr->lock, flags); + netif_device_attach(vptr->dev); + + return 0; +} + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + struct net_device *dev; + struct velocity_info *vptr; + + if (ifa) { + dev = ifa->ifa_dev->dev; + vptr = dev->priv; + velocity_get_ip(vptr); + } + return NOTIFY_DONE; +} +#endif + +/* + * Purpose: Functions to set WOL. + */ + +const static unsigned short crc16_tab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + + +static u32 mask_pattern[2][4] = { + {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ + {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ +}; + +/** + * ether_crc16 - compute ethernet CRC + * @len: buffer length + * @cp: buffer + * @crc16: initial CRC + * + * Compute a CRC value for a block of data. + * FIXME: can we use generic functions ? + */ + +static u16 ether_crc16(int len, u8 * cp, u16 crc16) +{ + while (len--) + crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff]; + return (crc16); +} + +/** + * bit_reverse - 16bit reverse + * @data: 16bit data t reverse + * + * Reverse the order of a 16bit value and return the reversed bits + */ + +static u16 bit_reverse(u16 data) +{ + u32 new = 0x00000000; + int ii; + + + for (ii = 0; ii < 16; ii++) { + new |= ((u32) (data & 1) << (31 - ii)); + data >>= 1; + } + + return (u16) (new >> 16); +} + +/** + * wol_calc_crc - WOL CRC + * @pattern: data pattern + * @mask_pattern: mask + * + * Compute the wake on lan crc hashes for the packet header + * we are interested in. + */ + +u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) +{ + u16 crc = 0xFFFF; + u8 mask; + int i, j; + + for (i = 0; i < size; i++) { + mask = mask_pattern[i]; + + /* Skip this loop if the mask equals to zero */ + if (mask == 0x00) + continue; + + for (j = 0; j < 8; j++) { + if ((mask & 0x01) == 0) { + mask >>= 1; + continue; + } + mask >>= 1; + crc = ether_crc16(1, &(pattern[i * 8 + j]), crc); + } + } + /* Finally, invert the result once to get the correct data */ + crc = ~crc; + return bit_reverse(crc); +} + +/** + * velocity_set_wol - set up for wake on lan + * @vptr: velocity to set WOL status on + * + * Set a card up for wake on lan either by unicast or by + * ARP packet. + * + * FIXME: check static buffer is safe here + */ + +static int velocity_set_wol(struct velocity_info *vptr) +{ + struct mac_regs * regs = vptr->mac_regs; + static u8 buf[256]; + int i; + + writew(0xFFFF, ®s->WOLCRClr); + writeb(WOLCFG_SAB | WOLCFG_SAM, ®s->WOLCFGSet); + writew(WOLCR_MAGIC_EN, ®s->WOLCRSet); + + /* + if (vptr->wol_opts & VELOCITY_WOL_PHY) + writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), ®s->WOLCRSet); + */ + + if (vptr->wol_opts & VELOCITY_WOL_UCAST) { + writew(WOLCR_UNICAST_EN, ®s->WOLCRSet); + } + + if (vptr->wol_opts & VELOCITY_WOL_ARP) { + struct arp_packet *arp = (struct arp_packet *) buf; + u16 crc; + memset(buf, 0, sizeof(struct arp_packet) + 7); + + for (i = 0; i < 4; i++) + writel(mask_pattern[0][i], ®s->ByteMask[0][i]); + + arp->type = htons(ETH_P_ARP); + arp->ar_op = htons(1); + + memcpy(arp->ar_tip, vptr->ip_addr, 4); + + crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]); + + writew(crc, ®s->PatternCRC[0]); + writew(WOLCR_ARP_EN, ®s->WOLCRSet); + } + + BYTE_REG_BITS_ON(PWCFG_WOLTYPE, ®s->PWCFGSet); + BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, ®s->PWCFGSet); + + writew(0x0FFF, ®s->WOLSRClr); + + if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) { + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) + MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); + + MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + } + + if (vptr->mii_status & VELOCITY_SPEED_1000) + MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); + + BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); + + { + u8 GCR; + GCR = readb(®s->CHIPGCR); + GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX; + writeb(GCR, ®s->CHIPGCR); + } + + BYTE_REG_BITS_OFF(ISR_PWEI, ®s->ISR); + /* Turn on SWPTAG just before entering power mode */ + BYTE_REG_BITS_ON(STICKHW_SWPTAG, ®s->STICKHW); + /* Go to bed ..... */ + BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); + + return 0; +} + diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h new file mode 100644 index 000000000..2175b8696 --- /dev/null +++ b/drivers/net/via-velocity.h @@ -0,0 +1,1885 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. + * All rights reserved. + * + * This software may be redistributed and/or modified under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * File: via-velocity.h + * + * Purpose: Header file to define driver's private structures. + * + * Author: Chuang Liang-Shing, AJ Jiang + * + * Date: Jan 24, 2003 + */ + + +#ifndef VELOCITY_H +#define VELOCITY_H + +#define VELOCITY_TX_CSUM_SUPPORT + +#define VELOCITY_NAME "via-velocity" +#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver" +#define VELOCITY_VERSION "1.13" + +#define PKT_BUF_SZ 1540 + +#define MAX_UNITS 8 +#define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1} + +#define REV_ID_VT6110 (0) +#define DEVICE_ID (0x3119) + +#define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0) +#define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0) +#define DWORD_REG_BITS_ON(x,p) do { writel(readl((p))|(x),(p));} while (0) + +#define BYTE_REG_BITS_IS_ON(x,p) (readb((p)) & (x)) +#define WORD_REG_BITS_IS_ON(x,p) (readw((p)) & (x)) +#define DWORD_REG_BITS_IS_ON(x,p) (readl((p)) & (x)) + +#define BYTE_REG_BITS_OFF(x,p) do { writeb(readb((p)) & (~(x)),(p));} while (0) +#define WORD_REG_BITS_OFF(x,p) do { writew(readw((p)) & (~(x)),(p));} while (0) +#define DWORD_REG_BITS_OFF(x,p) do { writel(readl((p)) & (~(x)),(p));} while (0) + +#define BYTE_REG_BITS_SET(x,m,p) do { writeb( (readb((p)) & (~(m))) |(x),(p));} while (0) +#define WORD_REG_BITS_SET(x,m,p) do { writew( (readw((p)) & (~(m))) |(x),(p));} while (0) +#define DWORD_REG_BITS_SET(x,m,p) do { writel( (readl((p)) & (~(m)))|(x),(p));} while (0) + +#define VAR_USED(p) do {(p)=(p);} while (0) + +/* + * Purpose: Structures for MAX RX/TX descriptors. + */ + + +#define B_OWNED_BY_CHIP 1 +#define B_OWNED_BY_HOST 0 + +/* + * Bits in the RSR0 register + */ + +#define RSR_DETAG 0x0080 +#define RSR_SNTAG 0x0040 +#define RSR_RXER 0x0020 +#define RSR_RL 0x0010 +#define RSR_CE 0x0008 +#define RSR_FAE 0x0004 +#define RSR_CRC 0x0002 +#define RSR_VIDM 0x0001 + +/* + * Bits in the RSR1 register + */ + +#define RSR_RXOK 0x8000 // rx OK +#define RSR_PFT 0x4000 // Perfect filtering address match +#define RSR_MAR 0x2000 // MAC accept multicast address packet +#define RSR_BAR 0x1000 // MAC accept broadcast address packet +#define RSR_PHY 0x0800 // MAC accept physical address packet +#define RSR_VTAG 0x0400 // 802.1p/1q tagging packet indicator +#define RSR_STP 0x0200 // start of packet +#define RSR_EDP 0x0100 // end of packet + +/* + * Bits in the RSR1 register + */ + +#define RSR1_RXOK 0x80 // rx OK +#define RSR1_PFT 0x40 // Perfect filtering address match +#define RSR1_MAR 0x20 // MAC accept multicast address packet +#define RSR1_BAR 0x10 // MAC accept broadcast address packet +#define RSR1_PHY 0x08 // MAC accept physical address packet +#define RSR1_VTAG 0x04 // 802.1p/1q tagging packet indicator +#define RSR1_STP 0x02 // start of packet +#define RSR1_EDP 0x01 // end of packet + +/* + * Bits in the CSM register + */ + +#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok +#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok +#define CSM_FRAG 0x10 //Fragment IP datagram +#define CSM_IPKT 0x04 //Received an IP packet +#define CSM_TCPKT 0x02 //Received a TCP packet +#define CSM_UDPKT 0x01 //Received a UDP packet + +/* + * Bits in the TSR0 register + */ + +#define TSR0_ABT 0x0080 // Tx abort because of excessive collision +#define TSR0_OWT 0x0040 // Jumbo frame Tx abort +#define TSR0_OWC 0x0020 // Out of window collision +#define TSR0_COLS 0x0010 // experience collision in this transmit event +#define TSR0_NCR3 0x0008 // collision retry counter[3] +#define TSR0_NCR2 0x0004 // collision retry counter[2] +#define TSR0_NCR1 0x0002 // collision retry counter[1] +#define TSR0_NCR0 0x0001 // collision retry counter[0] +#define TSR0_TERR 0x8000 // +#define TSR0_FDX 0x4000 // current transaction is serviced by full duplex mode +#define TSR0_GMII 0x2000 // current transaction is serviced by GMII mode +#define TSR0_LNKFL 0x1000 // packet serviced during link down +#define TSR0_SHDN 0x0400 // shutdown case +#define TSR0_CRS 0x0200 // carrier sense lost +#define TSR0_CDH 0x0100 // AQE test fail (CD heartbeat) + +/* + * Bits in the TSR1 register + */ + +#define TSR1_TERR 0x80 // +#define TSR1_FDX 0x40 // current transaction is serviced by full duplex mode +#define TSR1_GMII 0x20 // current transaction is serviced by GMII mode +#define TSR1_LNKFL 0x10 // packet serviced during link down +#define TSR1_SHDN 0x04 // shutdown case +#define TSR1_CRS 0x02 // carrier sense lost +#define TSR1_CDH 0x01 // AQE test fail (CD heartbeat) + +// +// Bits in the TCR0 register +// +#define TCR0_TIC 0x80 // assert interrupt immediately while descriptor has been send complete +#define TCR0_PIC 0x40 // priority interrupt request, INA# is issued over adaptive interrupt scheme +#define TCR0_VETAG 0x20 // enable VLAN tag +#define TCR0_IPCK 0x10 // request IP checksum calculation. +#define TCR0_UDPCK 0x08 // request UDP checksum calculation. +#define TCR0_TCPCK 0x04 // request TCP checksum calculation. +#define TCR0_JMBO 0x02 // indicate a jumbo packet in GMAC side +#define TCR0_CRC 0x01 // disable CRC generation + +#define TCPLS_NORMAL 3 +#define TCPLS_START 2 +#define TCPLS_END 1 +#define TCPLS_MED 0 + + +// max transmit or receive buffer size +#define CB_RX_BUF_SIZE 2048UL // max buffer size + // NOTE: must be multiple of 4 + +#define CB_MAX_RD_NUM 512 // MAX # of RD +#define CB_MAX_TD_NUM 256 // MAX # of TD + +#define CB_INIT_RD_NUM_3119 128 // init # of RD, for setup VT3119 +#define CB_INIT_TD_NUM_3119 64 // init # of TD, for setup VT3119 + +#define CB_INIT_RD_NUM 128 // init # of RD, for setup default +#define CB_INIT_TD_NUM 64 // init # of TD, for setup default + +// for 3119 +#define CB_TD_RING_NUM 4 // # of TD rings. +#define CB_MAX_SEG_PER_PKT 7 // max data seg per packet (Tx) + + +/* + * If collisions excess 15 times , tx will abort, and + * if tx fifo underflow, tx will fail + * we should try to resend it + */ + +#define CB_MAX_TX_ABORT_RETRY 3 + +/* + * Receive descriptor + */ + +struct rdesc0 { + u16 RSR; /* Receive status */ + u16 len:14; /* Received packet length */ + u16 reserved:1; + u16 owner:1; /* Who owns this buffer ? */ +}; + +struct rdesc1 { + u16 PQTAG; + u8 CSM; + u8 IPKT; +}; + +struct rx_desc { + struct rdesc0 rdesc0; + struct rdesc1 rdesc1; + u32 pa_low; /* Low 32 bit PCI address */ + u16 pa_high; /* Next 16 bit PCI address (48 total) */ + u16 len:15; /* Frame size */ + u16 inten:1; /* Enable interrupt */ +} __attribute__ ((__packed__)); + +/* + * Transmit descriptor + */ + +struct tdesc0 { + u16 TSR; /* Transmit status register */ + u16 pktsize:14; /* Size of frame */ + u16 reserved:1; + u16 owner:1; /* Who owns the buffer */ +}; + +struct pqinf { /* Priority queue info */ + u16 VID:12; + u16 CFI:1; + u16 priority:3; +} __attribute__ ((__packed__)); + +struct tdesc1 { + struct pqinf pqinf; + u8 TCR; + u8 TCPLS:2; + u8 reserved:2; + u8 CMDZ:4; +} __attribute__ ((__packed__)); + +struct td_buf { + u32 pa_low; + u16 pa_high; + u16 bufsize:14; + u16 reserved:1; + u16 queue:1; +} __attribute__ ((__packed__)); + +struct tx_desc { + struct tdesc0 tdesc0; + struct tdesc1 tdesc1; + struct td_buf td_buf[7]; +}; + +struct velocity_rd_info { + struct sk_buff *skb; + dma_addr_t skb_dma; +}; + +/** + * alloc_rd_info - allocate an rd info block + * + * Alocate and initialize a receive info structure used for keeping + * track of kernel side information related to each receive + * descriptor we are using + */ + +static inline struct velocity_rd_info *alloc_rd_info(void) +{ + struct velocity_rd_info *ptr; + if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL) + return NULL; + else { + memset(ptr, 0, sizeof(struct velocity_rd_info)); + return ptr; + } +} + +/* + * Used to track transmit side buffers. + */ + +struct velocity_td_info { + struct sk_buff *skb; + u8 *buf; + int nskb_dma; + dma_addr_t skb_dma[7]; + dma_addr_t buf_dma; +}; + +enum { + OWNED_BY_HOST = 0, + OWNED_BY_NIC = 1 +} velocity_owner; + + +/* + * MAC registers and macros. + */ + + +#define MCAM_SIZE 64 +#define VCAM_SIZE 64 +#define TX_QUEUE_NO 4 + +#define MAX_HW_MIB_COUNTER 32 +#define VELOCITY_MIN_MTU (1514-14) +#define VELOCITY_MAX_MTU (9000) + +/* + * Registers in the MAC + */ + +#define MAC_REG_PAR 0x00 // physical address +#define MAC_REG_RCR 0x06 +#define MAC_REG_TCR 0x07 +#define MAC_REG_CR0_SET 0x08 +#define MAC_REG_CR1_SET 0x09 +#define MAC_REG_CR2_SET 0x0A +#define MAC_REG_CR3_SET 0x0B +#define MAC_REG_CR0_CLR 0x0C +#define MAC_REG_CR1_CLR 0x0D +#define MAC_REG_CR2_CLR 0x0E +#define MAC_REG_CR3_CLR 0x0F +#define MAC_REG_MAR 0x10 +#define MAC_REG_CAM 0x10 +#define MAC_REG_DEC_BASE_HI 0x18 +#define MAC_REG_DBF_BASE_HI 0x1C +#define MAC_REG_ISR_CTL 0x20 +#define MAC_REG_ISR_HOTMR 0x20 +#define MAC_REG_ISR_TSUPTHR 0x20 +#define MAC_REG_ISR_RSUPTHR 0x20 +#define MAC_REG_ISR_CTL1 0x21 +#define MAC_REG_TXE_SR 0x22 +#define MAC_REG_RXE_SR 0x23 +#define MAC_REG_ISR 0x24 +#define MAC_REG_ISR0 0x24 +#define MAC_REG_ISR1 0x25 +#define MAC_REG_ISR2 0x26 +#define MAC_REG_ISR3 0x27 +#define MAC_REG_IMR 0x28 +#define MAC_REG_IMR0 0x28 +#define MAC_REG_IMR1 0x29 +#define MAC_REG_IMR2 0x2A +#define MAC_REG_IMR3 0x2B +#define MAC_REG_TDCSR_SET 0x30 +#define MAC_REG_RDCSR_SET 0x32 +#define MAC_REG_TDCSR_CLR 0x34 +#define MAC_REG_RDCSR_CLR 0x36 +#define MAC_REG_RDBASE_LO 0x38 +#define MAC_REG_RDINDX 0x3C +#define MAC_REG_TDBASE_LO 0x40 +#define MAC_REG_RDCSIZE 0x50 +#define MAC_REG_TDCSIZE 0x52 +#define MAC_REG_TDINDX 0x54 +#define MAC_REG_TDIDX0 0x54 +#define MAC_REG_TDIDX1 0x56 +#define MAC_REG_TDIDX2 0x58 +#define MAC_REG_TDIDX3 0x5A +#define MAC_REG_PAUSE_TIMER 0x5C +#define MAC_REG_RBRDU 0x5E +#define MAC_REG_FIFO_TEST0 0x60 +#define MAC_REG_FIFO_TEST1 0x64 +#define MAC_REG_CAMADDR 0x68 +#define MAC_REG_CAMCR 0x69 +#define MAC_REG_GFTEST 0x6A +#define MAC_REG_FTSTCMD 0x6B +#define MAC_REG_MIICFG 0x6C +#define MAC_REG_MIISR 0x6D +#define MAC_REG_PHYSR0 0x6E +#define MAC_REG_PHYSR1 0x6F +#define MAC_REG_MIICR 0x70 +#define MAC_REG_MIIADR 0x71 +#define MAC_REG_MIIDATA 0x72 +#define MAC_REG_SOFT_TIMER0 0x74 +#define MAC_REG_SOFT_TIMER1 0x76 +#define MAC_REG_CFGA 0x78 +#define MAC_REG_CFGB 0x79 +#define MAC_REG_CFGC 0x7A +#define MAC_REG_CFGD 0x7B +#define MAC_REG_DCFG0 0x7C +#define MAC_REG_DCFG1 0x7D +#define MAC_REG_MCFG0 0x7E +#define MAC_REG_MCFG1 0x7F + +#define MAC_REG_TBIST 0x80 +#define MAC_REG_RBIST 0x81 +#define MAC_REG_PMCC 0x82 +#define MAC_REG_STICKHW 0x83 +#define MAC_REG_MIBCR 0x84 +#define MAC_REG_EERSV 0x85 +#define MAC_REG_REVID 0x86 +#define MAC_REG_MIBREAD 0x88 +#define MAC_REG_BPMA 0x8C +#define MAC_REG_EEWR_DATA 0x8C +#define MAC_REG_BPMD_WR 0x8F +#define MAC_REG_BPCMD 0x90 +#define MAC_REG_BPMD_RD 0x91 +#define MAC_REG_EECHKSUM 0x92 +#define MAC_REG_EECSR 0x93 +#define MAC_REG_EERD_DATA 0x94 +#define MAC_REG_EADDR 0x96 +#define MAC_REG_EMBCMD 0x97 +#define MAC_REG_JMPSR0 0x98 +#define MAC_REG_JMPSR1 0x99 +#define MAC_REG_JMPSR2 0x9A +#define MAC_REG_JMPSR3 0x9B +#define MAC_REG_CHIPGSR 0x9C +#define MAC_REG_TESTCFG 0x9D +#define MAC_REG_DEBUG 0x9E +#define MAC_REG_CHIPGCR 0x9F +#define MAC_REG_WOLCR0_SET 0xA0 +#define MAC_REG_WOLCR1_SET 0xA1 +#define MAC_REG_PWCFG_SET 0xA2 +#define MAC_REG_WOLCFG_SET 0xA3 +#define MAC_REG_WOLCR0_CLR 0xA4 +#define MAC_REG_WOLCR1_CLR 0xA5 +#define MAC_REG_PWCFG_CLR 0xA6 +#define MAC_REG_WOLCFG_CLR 0xA7 +#define MAC_REG_WOLSR0_SET 0xA8 +#define MAC_REG_WOLSR1_SET 0xA9 +#define MAC_REG_WOLSR0_CLR 0xAC +#define MAC_REG_WOLSR1_CLR 0xAD +#define MAC_REG_PATRN_CRC0 0xB0 +#define MAC_REG_PATRN_CRC1 0xB2 +#define MAC_REG_PATRN_CRC2 0xB4 +#define MAC_REG_PATRN_CRC3 0xB6 +#define MAC_REG_PATRN_CRC4 0xB8 +#define MAC_REG_PATRN_CRC5 0xBA +#define MAC_REG_PATRN_CRC6 0xBC +#define MAC_REG_PATRN_CRC7 0xBE +#define MAC_REG_BYTEMSK0_0 0xC0 +#define MAC_REG_BYTEMSK0_1 0xC4 +#define MAC_REG_BYTEMSK0_2 0xC8 +#define MAC_REG_BYTEMSK0_3 0xCC +#define MAC_REG_BYTEMSK1_0 0xD0 +#define MAC_REG_BYTEMSK1_1 0xD4 +#define MAC_REG_BYTEMSK1_2 0xD8 +#define MAC_REG_BYTEMSK1_3 0xDC +#define MAC_REG_BYTEMSK2_0 0xE0 +#define MAC_REG_BYTEMSK2_1 0xE4 +#define MAC_REG_BYTEMSK2_2 0xE8 +#define MAC_REG_BYTEMSK2_3 0xEC +#define MAC_REG_BYTEMSK3_0 0xF0 +#define MAC_REG_BYTEMSK3_1 0xF4 +#define MAC_REG_BYTEMSK3_2 0xF8 +#define MAC_REG_BYTEMSK3_3 0xFC + +/* + * Bits in the RCR register + */ + +#define RCR_AS 0x80 +#define RCR_AP 0x40 +#define RCR_AL 0x20 +#define RCR_PROM 0x10 +#define RCR_AB 0x08 +#define RCR_AM 0x04 +#define RCR_AR 0x02 +#define RCR_SEP 0x01 + +/* + * Bits in the TCR register + */ + +#define TCR_TB2BDIS 0x80 +#define TCR_COLTMC1 0x08 +#define TCR_COLTMC0 0x04 +#define TCR_LB1 0x02 /* loopback[1] */ +#define TCR_LB0 0x01 /* loopback[0] */ + +/* + * Bits in the CR0 register + */ + +#define CR0_TXON 0x00000008UL +#define CR0_RXON 0x00000004UL +#define CR0_STOP 0x00000002UL /* stop MAC, default = 1 */ +#define CR0_STRT 0x00000001UL /* start MAC */ +#define CR0_SFRST 0x00008000UL /* software reset */ +#define CR0_TM1EN 0x00004000UL +#define CR0_TM0EN 0x00002000UL +#define CR0_DPOLL 0x00000800UL /* disable rx/tx auto polling */ +#define CR0_DISAU 0x00000100UL +#define CR0_XONEN 0x00800000UL +#define CR0_FDXTFCEN 0x00400000UL /* full-duplex TX flow control enable */ +#define CR0_FDXRFCEN 0x00200000UL /* full-duplex RX flow control enable */ +#define CR0_HDXFCEN 0x00100000UL /* half-duplex flow control enable */ +#define CR0_XHITH1 0x00080000UL /* TX XON high threshold 1 */ +#define CR0_XHITH0 0x00040000UL /* TX XON high threshold 0 */ +#define CR0_XLTH1 0x00020000UL /* TX pause frame low threshold 1 */ +#define CR0_XLTH0 0x00010000UL /* TX pause frame low threshold 0 */ +#define CR0_GSPRST 0x80000000UL +#define CR0_FORSRST 0x40000000UL +#define CR0_FPHYRST 0x20000000UL +#define CR0_DIAG 0x10000000UL +#define CR0_INTPCTL 0x04000000UL +#define CR0_GINTMSK1 0x02000000UL +#define CR0_GINTMSK0 0x01000000UL + +/* + * Bits in the CR1 register + */ + +#define CR1_SFRST 0x80 /* software reset */ +#define CR1_TM1EN 0x40 +#define CR1_TM0EN 0x20 +#define CR1_DPOLL 0x08 /* disable rx/tx auto polling */ +#define CR1_DISAU 0x01 + +/* + * Bits in the CR2 register + */ + +#define CR2_XONEN 0x80 +#define CR2_FDXTFCEN 0x40 /* full-duplex TX flow control enable */ +#define CR2_FDXRFCEN 0x20 /* full-duplex RX flow control enable */ +#define CR2_HDXFCEN 0x10 /* half-duplex flow control enable */ +#define CR2_XHITH1 0x08 /* TX XON high threshold 1 */ +#define CR2_XHITH0 0x04 /* TX XON high threshold 0 */ +#define CR2_XLTH1 0x02 /* TX pause frame low threshold 1 */ +#define CR2_XLTH0 0x01 /* TX pause frame low threshold 0 */ + +/* + * Bits in the CR3 register + */ + +#define CR3_GSPRST 0x80 +#define CR3_FORSRST 0x40 +#define CR3_FPHYRST 0x20 +#define CR3_DIAG 0x10 +#define CR3_INTPCTL 0x04 +#define CR3_GINTMSK1 0x02 +#define CR3_GINTMSK0 0x01 + +#define ISRCTL_UDPINT 0x8000 +#define ISRCTL_TSUPDIS 0x4000 +#define ISRCTL_RSUPDIS 0x2000 +#define ISRCTL_PMSK1 0x1000 +#define ISRCTL_PMSK0 0x0800 +#define ISRCTL_INTPD 0x0400 +#define ISRCTL_HCRLD 0x0200 +#define ISRCTL_SCRLD 0x0100 + +/* + * Bits in the ISR_CTL1 register + */ + +#define ISRCTL1_UDPINT 0x80 +#define ISRCTL1_TSUPDIS 0x40 +#define ISRCTL1_RSUPDIS 0x20 +#define ISRCTL1_PMSK1 0x10 +#define ISRCTL1_PMSK0 0x08 +#define ISRCTL1_INTPD 0x04 +#define ISRCTL1_HCRLD 0x02 +#define ISRCTL1_SCRLD 0x01 + +/* + * Bits in the TXE_SR register + */ + +#define TXESR_TFDBS 0x08 +#define TXESR_TDWBS 0x04 +#define TXESR_TDRBS 0x02 +#define TXESR_TDSTR 0x01 + +/* + * Bits in the RXE_SR register + */ + +#define RXESR_RFDBS 0x08 +#define RXESR_RDWBS 0x04 +#define RXESR_RDRBS 0x02 +#define RXESR_RDSTR 0x01 + +/* + * Bits in the ISR register + */ + +#define ISR_ISR3 0x80000000UL +#define ISR_ISR2 0x40000000UL +#define ISR_ISR1 0x20000000UL +#define ISR_ISR0 0x10000000UL +#define ISR_TXSTLI 0x02000000UL +#define ISR_RXSTLI 0x01000000UL +#define ISR_HFLD 0x00800000UL +#define ISR_UDPI 0x00400000UL +#define ISR_MIBFI 0x00200000UL +#define ISR_SHDNI 0x00100000UL +#define ISR_PHYI 0x00080000UL +#define ISR_PWEI 0x00040000UL +#define ISR_TMR1I 0x00020000UL +#define ISR_TMR0I 0x00010000UL +#define ISR_SRCI 0x00008000UL +#define ISR_LSTPEI 0x00004000UL +#define ISR_LSTEI 0x00002000UL +#define ISR_OVFI 0x00001000UL +#define ISR_FLONI 0x00000800UL +#define ISR_RACEI 0x00000400UL +#define ISR_TXWB1I 0x00000200UL +#define ISR_TXWB0I 0x00000100UL +#define ISR_PTX3I 0x00000080UL +#define ISR_PTX2I 0x00000040UL +#define ISR_PTX1I 0x00000020UL +#define ISR_PTX0I 0x00000010UL +#define ISR_PTXI 0x00000008UL +#define ISR_PRXI 0x00000004UL +#define ISR_PPTXI 0x00000002UL +#define ISR_PPRXI 0x00000001UL + +/* + * Bits in the IMR register + */ + +#define IMR_TXSTLM 0x02000000UL +#define IMR_UDPIM 0x00400000UL +#define IMR_MIBFIM 0x00200000UL +#define IMR_SHDNIM 0x00100000UL +#define IMR_PHYIM 0x00080000UL +#define IMR_PWEIM 0x00040000UL +#define IMR_TMR1IM 0x00020000UL +#define IMR_TMR0IM 0x00010000UL + +#define IMR_SRCIM 0x00008000UL +#define IMR_LSTPEIM 0x00004000UL +#define IMR_LSTEIM 0x00002000UL +#define IMR_OVFIM 0x00001000UL +#define IMR_FLONIM 0x00000800UL +#define IMR_RACEIM 0x00000400UL +#define IMR_TXWB1IM 0x00000200UL +#define IMR_TXWB0IM 0x00000100UL + +#define IMR_PTX3IM 0x00000080UL +#define IMR_PTX2IM 0x00000040UL +#define IMR_PTX1IM 0x00000020UL +#define IMR_PTX0IM 0x00000010UL +#define IMR_PTXIM 0x00000008UL +#define IMR_PRXIM 0x00000004UL +#define IMR_PPTXIM 0x00000002UL +#define IMR_PPRXIM 0x00000001UL + +/* 0x0013FB0FUL = initial value of IMR */ + +#define INT_MASK_DEF (IMR_PPTXIM|IMR_PPRXIM|IMR_PTXIM|IMR_PRXIM|\ + IMR_PWEIM|IMR_TXWB0IM|IMR_TXWB1IM|IMR_FLONIM|\ + IMR_OVFIM|IMR_LSTEIM|IMR_LSTPEIM|IMR_SRCIM|IMR_MIBFIM|\ + IMR_SHDNIM|IMR_TMR1IM|IMR_TMR0IM|IMR_TXSTLM) + +/* + * Bits in the TDCSR0/1, RDCSR0 register + */ + +#define TRDCSR_DEAD 0x0008 +#define TRDCSR_WAK 0x0004 +#define TRDCSR_ACT 0x0002 +#define TRDCSR_RUN 0x0001 + +/* + * Bits in the CAMADDR register + */ + +#define CAMADDR_CAMEN 0x80 +#define CAMADDR_VCAMSL 0x40 + +/* + * Bits in the CAMCR register + */ + +#define CAMCR_PS1 0x80 +#define CAMCR_PS0 0x40 +#define CAMCR_AITRPKT 0x20 +#define CAMCR_AITR16 0x10 +#define CAMCR_CAMRD 0x08 +#define CAMCR_CAMWR 0x04 +#define CAMCR_PS_CAM_MASK 0x40 +#define CAMCR_PS_CAM_DATA 0x80 +#define CAMCR_PS_MAR 0x00 + +/* + * Bits in the MIICFG register + */ + +#define MIICFG_MPO1 0x80 +#define MIICFG_MPO0 0x40 +#define MIICFG_MFDC 0x20 + +/* + * Bits in the MIISR register + */ + +#define MIISR_MIDLE 0x80 + +/* + * Bits in the PHYSR0 register + */ + +#define PHYSR0_PHYRST 0x80 +#define PHYSR0_LINKGD 0x40 +#define PHYSR0_FDPX 0x10 +#define PHYSR0_SPDG 0x08 +#define PHYSR0_SPD10 0x04 +#define PHYSR0_RXFLC 0x02 +#define PHYSR0_TXFLC 0x01 + +/* + * Bits in the PHYSR1 register + */ + +#define PHYSR1_PHYTBI 0x01 + +/* + * Bits in the MIICR register + */ + +#define MIICR_MAUTO 0x80 +#define MIICR_RCMD 0x40 +#define MIICR_WCMD 0x20 +#define MIICR_MDPM 0x10 +#define MIICR_MOUT 0x08 +#define MIICR_MDO 0x04 +#define MIICR_MDI 0x02 +#define MIICR_MDC 0x01 + +/* + * Bits in the MIIADR register + */ + +#define MIIADR_SWMPL 0x80 + +/* + * Bits in the CFGA register + */ + +#define CFGA_PMHCTG 0x08 +#define CFGA_GPIO1PD 0x04 +#define CFGA_ABSHDN 0x02 +#define CFGA_PACPI 0x01 + +/* + * Bits in the CFGB register + */ + +#define CFGB_GTCKOPT 0x80 +#define CFGB_MIIOPT 0x40 +#define CFGB_CRSEOPT 0x20 +#define CFGB_OFSET 0x10 +#define CFGB_CRANDOM 0x08 +#define CFGB_CAP 0x04 +#define CFGB_MBA 0x02 +#define CFGB_BAKOPT 0x01 + +/* + * Bits in the CFGC register + */ + +#define CFGC_EELOAD 0x80 +#define CFGC_BROPT 0x40 +#define CFGC_DLYEN 0x20 +#define CFGC_DTSEL 0x10 +#define CFGC_BTSEL 0x08 +#define CFGC_BPS2 0x04 /* bootrom select[2] */ +#define CFGC_BPS1 0x02 /* bootrom select[1] */ +#define CFGC_BPS0 0x01 /* bootrom select[0] */ + +/* + * Bits in the CFGD register + */ + +#define CFGD_IODIS 0x80 +#define CFGD_MSLVDACEN 0x40 +#define CFGD_CFGDACEN 0x20 +#define CFGD_PCI64EN 0x10 +#define CFGD_HTMRL4 0x08 + +/* + * Bits in the DCFG1 register + */ + +#define DCFG_XMWI 0x8000 +#define DCFG_XMRM 0x4000 +#define DCFG_XMRL 0x2000 +#define DCFG_PERDIS 0x1000 +#define DCFG_MRWAIT 0x0400 +#define DCFG_MWWAIT 0x0200 +#define DCFG_LATMEN 0x0100 + +/* + * Bits in the MCFG0 register + */ + +#define MCFG_RXARB 0x0080 +#define MCFG_RFT1 0x0020 +#define MCFG_RFT0 0x0010 +#define MCFG_LOWTHOPT 0x0008 +#define MCFG_PQEN 0x0004 +#define MCFG_RTGOPT 0x0002 +#define MCFG_VIDFR 0x0001 + +/* + * Bits in the MCFG1 register + */ + +#define MCFG_TXARB 0x8000 +#define MCFG_TXQBK1 0x0800 +#define MCFG_TXQBK0 0x0400 +#define MCFG_TXQNOBK 0x0200 +#define MCFG_SNAPOPT 0x0100 + +/* + * Bits in the PMCC register + */ + +#define PMCC_DSI 0x80 +#define PMCC_D2_DIS 0x40 +#define PMCC_D1_DIS 0x20 +#define PMCC_D3C_EN 0x10 +#define PMCC_D3H_EN 0x08 +#define PMCC_D2_EN 0x04 +#define PMCC_D1_EN 0x02 +#define PMCC_D0_EN 0x01 + +/* + * Bits in STICKHW + */ + +#define STICKHW_SWPTAG 0x10 +#define STICKHW_WOLSR 0x08 +#define STICKHW_WOLEN 0x04 +#define STICKHW_DS1 0x02 /* R/W by software/cfg cycle */ +#define STICKHW_DS0 0x01 /* suspend well DS write port */ + +/* + * Bits in the MIBCR register + */ + +#define MIBCR_MIBISTOK 0x80 +#define MIBCR_MIBISTGO 0x40 +#define MIBCR_MIBINC 0x20 +#define MIBCR_MIBHI 0x10 +#define MIBCR_MIBFRZ 0x08 +#define MIBCR_MIBFLSH 0x04 +#define MIBCR_MPTRINI 0x02 +#define MIBCR_MIBCLR 0x01 + +/* + * Bits in the EERSV register + */ + +#define EERSV_BOOT_RPL ((u8) 0x01) /* Boot method selection for VT6110 */ + +#define EERSV_BOOT_MASK ((u8) 0x06) +#define EERSV_BOOT_INT19 ((u8) 0x00) +#define EERSV_BOOT_INT18 ((u8) 0x02) +#define EERSV_BOOT_LOCAL ((u8) 0x04) +#define EERSV_BOOT_BEV ((u8) 0x06) + + +/* + * Bits in BPCMD + */ + +#define BPCMD_BPDNE 0x80 +#define BPCMD_EBPWR 0x02 +#define BPCMD_EBPRD 0x01 + +/* + * Bits in the EECSR register + */ + +#define EECSR_EMBP 0x40 /* eeprom embeded programming */ +#define EECSR_RELOAD 0x20 /* eeprom content reload */ +#define EECSR_DPM 0x10 /* eeprom direct programming */ +#define EECSR_ECS 0x08 /* eeprom CS pin */ +#define EECSR_ECK 0x04 /* eeprom CK pin */ +#define EECSR_EDI 0x02 /* eeprom DI pin */ +#define EECSR_EDO 0x01 /* eeprom DO pin */ + +/* + * Bits in the EMBCMD register + */ + +#define EMBCMD_EDONE 0x80 +#define EMBCMD_EWDIS 0x08 +#define EMBCMD_EWEN 0x04 +#define EMBCMD_EWR 0x02 +#define EMBCMD_ERD 0x01 + +/* + * Bits in TESTCFG register + */ + +#define TESTCFG_HBDIS 0x80 + +/* + * Bits in CHIPGCR register + */ + +#define CHIPGCR_FCGMII 0x80 +#define CHIPGCR_FCFDX 0x40 +#define CHIPGCR_FCRESV 0x20 +#define CHIPGCR_FCMODE 0x10 +#define CHIPGCR_LPSOPT 0x08 +#define CHIPGCR_TM1US 0x04 +#define CHIPGCR_TM0US 0x02 +#define CHIPGCR_PHYINTEN 0x01 + +/* + * Bits in WOLCR0 + */ + +#define WOLCR_MSWOLEN7 0x0080 /* enable pattern match filtering */ +#define WOLCR_MSWOLEN6 0x0040 +#define WOLCR_MSWOLEN5 0x0020 +#define WOLCR_MSWOLEN4 0x0010 +#define WOLCR_MSWOLEN3 0x0008 +#define WOLCR_MSWOLEN2 0x0004 +#define WOLCR_MSWOLEN1 0x0002 +#define WOLCR_MSWOLEN0 0x0001 +#define WOLCR_ARP_EN 0x0001 + +/* + * Bits in WOLCR1 + */ + +#define WOLCR_LINKOFF_EN 0x0800 /* link off detected enable */ +#define WOLCR_LINKON_EN 0x0400 /* link on detected enable */ +#define WOLCR_MAGIC_EN 0x0200 /* magic packet filter enable */ +#define WOLCR_UNICAST_EN 0x0100 /* unicast filter enable */ + + +/* + * Bits in PWCFG + */ + +#define PWCFG_PHYPWOPT 0x80 /* internal MII I/F timing */ +#define PWCFG_PCISTICK 0x40 /* PCI sticky R/W enable */ +#define PWCFG_WOLTYPE 0x20 /* pulse(1) or button (0) */ +#define PWCFG_LEGCY_WOL 0x10 +#define PWCFG_PMCSR_PME_SR 0x08 +#define PWCFG_PMCSR_PME_EN 0x04 /* control by PCISTICK */ +#define PWCFG_LEGACY_WOLSR 0x02 /* Legacy WOL_SR shadow */ +#define PWCFG_LEGACY_WOLEN 0x01 /* Legacy WOL_EN shadow */ + +/* + * Bits in WOLCFG + */ + +#define WOLCFG_PMEOVR 0x80 /* for legacy use, force PMEEN always */ +#define WOLCFG_SAM 0x20 /* accept multicast case reset, default=0 */ +#define WOLCFG_SAB 0x10 /* accept broadcast case reset, default=0 */ +#define WOLCFG_SMIIACC 0x08 /* ?? */ +#define WOLCFG_SGENWH 0x02 +#define WOLCFG_PHYINTEN 0x01 /* 0:PHYINT trigger enable, 1:use internal MII + to report status change */ +/* + * Bits in WOLSR1 + */ + +#define WOLSR_LINKOFF_INT 0x0800 +#define WOLSR_LINKON_INT 0x0400 +#define WOLSR_MAGIC_INT 0x0200 +#define WOLSR_UNICAST_INT 0x0100 + +/* + * Ethernet address filter type + */ + +#define PKT_TYPE_NONE 0x0000 /* Turn off receiver */ +#define PKT_TYPE_DIRECTED 0x0001 /* obselete, directed address is always accepted */ +#define PKT_TYPE_MULTICAST 0x0002 +#define PKT_TYPE_ALL_MULTICAST 0x0004 +#define PKT_TYPE_BROADCAST 0x0008 +#define PKT_TYPE_PROMISCUOUS 0x0020 +#define PKT_TYPE_LONG 0x2000 /* NOTE.... the definition of LONG is >2048 bytes in our chip */ +#define PKT_TYPE_RUNT 0x4000 +#define PKT_TYPE_ERROR 0x8000 /* Accept error packets, e.g. CRC error */ + +/* + * Loopback mode + */ + +#define MAC_LB_NONE 0x00 +#define MAC_LB_INTERNAL 0x01 +#define MAC_LB_EXTERNAL 0x02 + +/* + * Enabled mask value of irq + */ + +#if defined(_SIM) +#define IMR_MASK_VALUE 0x0033FF0FUL /* initial value of IMR + set IMR0 to 0x0F according to spec */ + +#else +#define IMR_MASK_VALUE 0x0013FB0FUL /* initial value of IMR + ignore MIBFI,RACEI to + reduce intr. frequency + NOTE.... do not enable NoBuf int mask at driver driver + when (1) NoBuf -> RxThreshold = SF + (2) OK -> RxThreshold = original value + */ +#endif + +/* + * Revision id + */ + +#define REV_ID_VT3119_A0 0x00 +#define REV_ID_VT3119_A1 0x01 +#define REV_ID_VT3216_A0 0x10 + +/* + * Max time out delay time + */ + +#define W_MAX_TIMEOUT 0x0FFFU + + +/* + * MAC registers as a structure. Cannot be directly accessed this + * way but generates offsets for readl/writel() calls + */ + +struct mac_regs { + volatile u8 PAR[6]; /* 0x00 */ + volatile u8 RCR; + volatile u8 TCR; + + volatile u32 CR0Set; /* 0x08 */ + volatile u32 CR0Clr; /* 0x0C */ + + volatile u8 MARCAM[8]; /* 0x10 */ + + volatile u32 DecBaseHi; /* 0x18 */ + volatile u16 DbfBaseHi; /* 0x1C */ + volatile u16 reserved_1E; + + volatile u16 ISRCTL; /* 0x20 */ + volatile u8 TXESR; + volatile u8 RXESR; + + volatile u32 ISR; /* 0x24 */ + volatile u32 IMR; + + volatile u32 TDStatusPort; /* 0x2C */ + + volatile u16 TDCSRSet; /* 0x30 */ + volatile u8 RDCSRSet; + volatile u8 reserved_33; + volatile u16 TDCSRClr; + volatile u8 RDCSRClr; + volatile u8 reserved_37; + + volatile u32 RDBaseLo; /* 0x38 */ + volatile u16 RDIdx; /* 0x3C */ + volatile u16 reserved_3E; + + volatile u32 TDBaseLo[4]; /* 0x40 */ + + volatile u16 RDCSize; /* 0x50 */ + volatile u16 TDCSize; /* 0x52 */ + volatile u16 TDIdx[4]; /* 0x54 */ + volatile u16 tx_pause_timer; /* 0x5C */ + volatile u16 RBRDU; /* 0x5E */ + + volatile u32 FIFOTest0; /* 0x60 */ + volatile u32 FIFOTest1; /* 0x64 */ + + volatile u8 CAMADDR; /* 0x68 */ + volatile u8 CAMCR; /* 0x69 */ + volatile u8 GFTEST; /* 0x6A */ + volatile u8 FTSTCMD; /* 0x6B */ + + volatile u8 MIICFG; /* 0x6C */ + volatile u8 MIISR; + volatile u8 PHYSR0; + volatile u8 PHYSR1; + volatile u8 MIICR; + volatile u8 MIIADR; + volatile u16 MIIDATA; + + volatile u16 SoftTimer0; /* 0x74 */ + volatile u16 SoftTimer1; + + volatile u8 CFGA; /* 0x78 */ + volatile u8 CFGB; + volatile u8 CFGC; + volatile u8 CFGD; + + volatile u16 DCFG; /* 0x7C */ + volatile u16 MCFG; + + volatile u8 TBIST; /* 0x80 */ + volatile u8 RBIST; + volatile u8 PMCPORT; + volatile u8 STICKHW; + + volatile u8 MIBCR; /* 0x84 */ + volatile u8 reserved_85; + volatile u8 rev_id; + volatile u8 PORSTS; + + volatile u32 MIBData; /* 0x88 */ + + volatile u16 EEWrData; + + volatile u8 reserved_8E; + volatile u8 BPMDWr; + volatile u8 BPCMD; + volatile u8 BPMDRd; + + volatile u8 EECHKSUM; /* 0x92 */ + volatile u8 EECSR; + + volatile u16 EERdData; /* 0x94 */ + volatile u8 EADDR; + volatile u8 EMBCMD; + + + volatile u8 JMPSR0; /* 0x98 */ + volatile u8 JMPSR1; + volatile u8 JMPSR2; + volatile u8 JMPSR3; + volatile u8 CHIPGSR; /* 0x9C */ + volatile u8 TESTCFG; + volatile u8 DEBUG; + volatile u8 CHIPGCR; + + volatile u16 WOLCRSet; /* 0xA0 */ + volatile u8 PWCFGSet; + volatile u8 WOLCFGSet; + + volatile u16 WOLCRClr; /* 0xA4 */ + volatile u8 PWCFGCLR; + volatile u8 WOLCFGClr; + + volatile u16 WOLSRSet; /* 0xA8 */ + volatile u16 reserved_AA; + + volatile u16 WOLSRClr; /* 0xAC */ + volatile u16 reserved_AE; + + volatile u16 PatternCRC[8]; /* 0xB0 */ + volatile u32 ByteMask[4][4]; /* 0xC0 */ +} __attribute__ ((__packed__)); + + +enum hw_mib { + HW_MIB_ifRxAllPkts = 0, + HW_MIB_ifRxOkPkts, + HW_MIB_ifTxOkPkts, + HW_MIB_ifRxErrorPkts, + HW_MIB_ifRxRuntOkPkt, + HW_MIB_ifRxRuntErrPkt, + HW_MIB_ifRx64Pkts, + HW_MIB_ifTx64Pkts, + HW_MIB_ifRx65To127Pkts, + HW_MIB_ifTx65To127Pkts, + HW_MIB_ifRx128To255Pkts, + HW_MIB_ifTx128To255Pkts, + HW_MIB_ifRx256To511Pkts, + HW_MIB_ifTx256To511Pkts, + HW_MIB_ifRx512To1023Pkts, + HW_MIB_ifTx512To1023Pkts, + HW_MIB_ifRx1024To1518Pkts, + HW_MIB_ifTx1024To1518Pkts, + HW_MIB_ifTxEtherCollisions, + HW_MIB_ifRxPktCRCE, + HW_MIB_ifRxJumboPkts, + HW_MIB_ifTxJumboPkts, + HW_MIB_ifRxMacControlFrames, + HW_MIB_ifTxMacControlFrames, + HW_MIB_ifRxPktFAE, + HW_MIB_ifRxLongOkPkt, + HW_MIB_ifRxLongPktErrPkt, + HW_MIB_ifTXSQEErrors, + HW_MIB_ifRxNobuf, + HW_MIB_ifRxSymbolErrors, + HW_MIB_ifInRangeLengthErrors, + HW_MIB_ifLateCollisions, + HW_MIB_SIZE +}; + +enum chip_type { + CHIP_TYPE_VT6110 = 1, +}; + +struct velocity_info_tbl { + enum chip_type chip_id; + char *name; + int io_size; + int txqueue; + u32 flags; +}; + +#define mac_hw_mibs_init(regs) {\ + BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\ + BYTE_REG_BITS_ON(MIBCR_MIBCLR,&((regs)->MIBCR));\ + do {}\ + while (BYTE_REG_BITS_IS_ON(MIBCR_MIBCLR,&((regs)->MIBCR)));\ + BYTE_REG_BITS_OFF(MIBCR_MIBFRZ,&((regs)->MIBCR));\ +} + +#define mac_read_isr(regs) readl(&((regs)->ISR)) +#define mac_write_isr(regs, x) writel((x),&((regs)->ISR)) +#define mac_clear_isr(regs) writel(0xffffffffL,&((regs)->ISR)) + +#define mac_write_int_mask(mask, regs) writel((mask),&((regs)->IMR)); +#define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr)) +#define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set)) + +#define mac_hw_mibs_read(regs, MIBs) {\ + int i;\ + BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\ + for (i=0;iMIBData));\ + }\ +} + +#define mac_set_dma_length(regs, n) {\ + BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\ +} + +#define mac_set_rx_thresh(regs, n) {\ + BYTE_REG_BITS_SET((n),(MCFG_RFT0|MCFG_RFT1),&((regs)->MCFG));\ +} + +#define mac_rx_queue_run(regs) {\ + writeb(TRDCSR_RUN, &((regs)->RDCSRSet));\ +} + +#define mac_rx_queue_wake(regs) {\ + writeb(TRDCSR_WAK, &((regs)->RDCSRSet));\ +} + +#define mac_tx_queue_run(regs, n) {\ + writew(TRDCSR_RUN<<((n)*4),&((regs)->TDCSRSet));\ +} + +#define mac_tx_queue_wake(regs, n) {\ + writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\ +} + +#define mac_eeprom_reload(regs) {\ + int i=0;\ + BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\ + do {\ + udelay(10);\ + if (i++>0x1000) {\ + break;\ + }\ + }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\ +} + +enum velocity_cam_type { + VELOCITY_VLAN_ID_CAM = 0, + VELOCITY_MULTICAST_CAM +}; + +/** + * mac_get_cam_mask - Read a CAM mask + * @regs: register block for this velocity + * @mask: buffer to store mask + * @cam_type: CAM to fetch + * + * Fetch the mask bits of the selected CAM and store them into the + * provided mask buffer. + */ + +static inline void mac_get_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + writeb(CAMADDR_VCAMSL, ®s->CAMADDR); + else + writeb(0, ®s->CAMADDR); + + /* read mask */ + for (i = 0; i < 8; i++) + *mask++ = readb(&(regs->MARCAM[i])); + + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + +} + +/** + * mac_set_cam_mask - Set a CAM mask + * @regs: register block for this velocity + * @mask: CAM mask to load + * @cam_type: CAM to store + * + * Store a new mask into a CAM + */ + +static inline void mac_set_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); + else + writeb(CAMADDR_CAMEN, ®s->CAMADDR); + + for (i = 0; i < 8; i++) { + writeb(*mask++, &(regs->MARCAM[i])); + } + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +/** + * mac_set_cam - set CAM data + * @regs: register block of this velocity + * @idx: Cam index + * @addr: 2 or 6 bytes of CAM data + * @cam_type: CAM to load + * + * Load an address or vlan tag into a CAM + */ + +static inline void mac_set_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) +{ + int i; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); + else + writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + writew(*((u16 *) addr), ®s->MARCAM[0]); + else { + for (i = 0; i < 6; i++) { + writeb(*addr++, &(regs->MARCAM[i])); + } + } + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); + + udelay(10); + + writeb(0, ®s->CAMADDR); + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +/** + * mac_get_cam - fetch CAM data + * @regs: register block of this velocity + * @idx: Cam index + * @addr: buffer to hold up to 6 bytes of CAM data + * @cam_type: CAM to load + * + * Load an address or vlan tag from a CAM into the buffer provided by + * the caller. VLAN tags are 2 bytes the address cam entries are 6. + */ + +static inline void mac_get_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) +{ + int i; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); + else + writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); + + BYTE_REG_BITS_ON(CAMCR_CAMRD, ®s->CAMCR); + + udelay(10); + + if (cam_type == VELOCITY_VLAN_ID_CAM) + *((u16 *) addr) = readw(&(regs->MARCAM[0])); + else + for (i = 0; i < 6; i++, addr++) + *((u8 *) addr) = readb(&(regs->MARCAM[i])); + + writeb(0, ®s->CAMADDR); + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +/** + * mac_wol_reset - reset WOL after exiting low power + * @regs: register block of this velocity + * + * Called after we drop out of wake on lan mode in order to + * reset the Wake on lan features. This function doesn't restore + * the rest of the logic from the result of sleep/wakeup + */ + +inline static void mac_wol_reset(struct mac_regs * regs) +{ + + /* Turn off SWPTAG right after leaving power mode */ + BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); + /* clear sticky bits */ + BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); + + BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* disable force PME-enable */ + writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); + /* disable power-event config bit */ + writew(0xFFFF, ®s->WOLCRClr); + /* clear power status */ + writew(0xFFFF, ®s->WOLSRClr); +} + + +/* + * Header for WOL definitions. Used to compute hashes + */ + +typedef u8 MCAM_ADDR[ETH_ALEN]; + +struct arp_packet { + u8 dest_mac[ETH_ALEN]; + u8 src_mac[ETH_ALEN]; + u16 type; + u16 ar_hrd; + u16 ar_pro; + u8 ar_hln; + u8 ar_pln; + u16 ar_op; + u8 ar_sha[ETH_ALEN]; + u8 ar_sip[4]; + u8 ar_tha[ETH_ALEN]; + u8 ar_tip[4]; +} __attribute__ ((__packed__)); + +struct _magic_packet { + u8 dest_mac[6]; + u8 src_mac[6]; + u16 type; + u8 MAC[16][6]; + u8 password[6]; +} __attribute__ ((__packed__)); + +/* + * Store for chip context when saving and restoring status. Not + * all fields are saved/restored currently. + */ + +struct velocity_context { + u8 mac_reg[256]; + MCAM_ADDR cam_addr[MCAM_SIZE]; + u16 vcam[VCAM_SIZE]; + u32 cammask[2]; + u32 patcrc[2]; + u32 pattern[8]; +}; + + +/* + * MII registers. + */ + + +/* + * Registers in the MII (offset unit is WORD) + */ + +#define MII_REG_BMCR 0x00 // physical address +#define MII_REG_BMSR 0x01 // +#define MII_REG_PHYID1 0x02 // OUI +#define MII_REG_PHYID2 0x03 // OUI + Module ID + REV ID +#define MII_REG_ANAR 0x04 // +#define MII_REG_ANLPAR 0x05 // +#define MII_REG_G1000CR 0x09 // +#define MII_REG_G1000SR 0x0A // +#define MII_REG_MODCFG 0x10 // +#define MII_REG_TCSR 0x16 // +#define MII_REG_PLED 0x1B // +// NS, MYSON only +#define MII_REG_PCR 0x17 // +// ESI only +#define MII_REG_PCSR 0x17 // +#define MII_REG_AUXCR 0x1C // + +// Marvell 88E1000/88E1000S +#define MII_REG_PSCR 0x10 // PHY specific control register + +// +// Bits in the BMCR register +// +#define BMCR_RESET 0x8000 // +#define BMCR_LBK 0x4000 // +#define BMCR_SPEED100 0x2000 // +#define BMCR_AUTO 0x1000 // +#define BMCR_PD 0x0800 // +#define BMCR_ISO 0x0400 // +#define BMCR_REAUTO 0x0200 // +#define BMCR_FDX 0x0100 // +#define BMCR_SPEED1G 0x0040 // +// +// Bits in the BMSR register +// +#define BMSR_AUTOCM 0x0020 // +#define BMSR_LNK 0x0004 // + +// +// Bits in the ANAR register +// +#define ANAR_ASMDIR 0x0800 // Asymmetric PAUSE support +#define ANAR_PAUSE 0x0400 // Symmetric PAUSE Support +#define ANAR_T4 0x0200 // +#define ANAR_TXFD 0x0100 // +#define ANAR_TX 0x0080 // +#define ANAR_10FD 0x0040 // +#define ANAR_10 0x0020 // +// +// Bits in the ANLPAR register +// +#define ANLPAR_ASMDIR 0x0800 // Asymmetric PAUSE support +#define ANLPAR_PAUSE 0x0400 // Symmetric PAUSE Support +#define ANLPAR_T4 0x0200 // +#define ANLPAR_TXFD 0x0100 // +#define ANLPAR_TX 0x0080 // +#define ANLPAR_10FD 0x0040 // +#define ANLPAR_10 0x0020 // + +// +// Bits in the G1000CR register +// +#define G1000CR_1000FD 0x0200 // PHY is 1000-T Full-duplex capable +#define G1000CR_1000 0x0100 // PHY is 1000-T Half-duplex capable + +// +// Bits in the G1000SR register +// +#define G1000SR_1000FD 0x0800 // LP PHY is 1000-T Full-duplex capable +#define G1000SR_1000 0x0400 // LP PHY is 1000-T Half-duplex capable + +#define TCSR_ECHODIS 0x2000 // +#define AUXCR_MDPPS 0x0004 // + +// Bits in the PLED register +#define PLED_LALBE 0x0004 // + +// Marvell 88E1000/88E1000S Bits in the PHY specific control register (10h) +#define PSCR_ACRSTX 0x0800 // Assert CRS on Transmit + +#define PHYID_CICADA_CS8201 0x000FC410UL +#define PHYID_VT3216_32BIT 0x000FC610UL +#define PHYID_VT3216_64BIT 0x000FC600UL +#define PHYID_MARVELL_1000 0x01410C50UL +#define PHYID_MARVELL_1000S 0x01410C40UL + +#define PHYID_REV_ID_MASK 0x0000000FUL + +#define PHYID_GET_PHY_REV_ID(i) ((i) & PHYID_REV_ID_MASK) +#define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK) + +#define MII_REG_BITS_ON(x,i,p) do {\ + u16 w;\ + velocity_mii_read((p),(i),&(w));\ + (w)|=(x);\ + velocity_mii_write((p),(i),(w));\ +} while (0) + +#define MII_REG_BITS_OFF(x,i,p) do {\ + u16 w;\ + velocity_mii_read((p),(i),&(w));\ + (w)&=(~(x));\ + velocity_mii_write((p),(i),(w));\ +} while (0) + +#define MII_REG_BITS_IS_ON(x,i,p) ({\ + u16 w;\ + velocity_mii_read((p),(i),&(w));\ + ((int) ((w) & (x)));}) + +#define MII_GET_PHY_ID(p) ({\ + u32 id;\ + velocity_mii_read((p),MII_REG_PHYID2,(u16 *) &id);\ + velocity_mii_read((p),MII_REG_PHYID1,((u16 *) &id)+1);\ + (id);}) + +/* + * Inline debug routine + */ + + +enum velocity_msg_level { + MSG_LEVEL_ERR = 0, //Errors that will cause abnormal operation. + MSG_LEVEL_NOTICE = 1, //Some errors need users to be notified. + MSG_LEVEL_INFO = 2, //Normal message. + MSG_LEVEL_VERBOSE = 3, //Will report all trival errors. + MSG_LEVEL_DEBUG = 4 //Only for debug purpose. +}; + +#ifdef VELOCITY_DEBUG +#define ASSERT(x) { \ + if (!(x)) { \ + printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\ + __FUNCTION__, __LINE__);\ + BUG(); \ + }\ +} +#define VELOCITY_DBG(p,args...) printk(p, ##args) +#else +#define ASSERT(x) +#define VELOCITY_DBG(x) +#endif + +#define VELOCITY_PRT(l, p, args...) do {if (l<=msglevel) printk( p ,##args);} while (0) + +#define VELOCITY_PRT_CAMMASK(p,t) {\ + int i;\ + if ((t)==VELOCITY_MULTICAST_CAM) {\ + for (i=0;i<(MCAM_SIZE/8);i++)\ + printk("%02X",(p)->mCAMmask[i]);\ + }\ + else {\ + for (i=0;i<(VCAM_SIZE/8);i++)\ + printk("%02X",(p)->vCAMmask[i]);\ + }\ + printk("\n");\ +} + + + +#define VELOCITY_WOL_MAGIC 0x00000000UL +#define VELOCITY_WOL_PHY 0x00000001UL +#define VELOCITY_WOL_ARP 0x00000002UL +#define VELOCITY_WOL_UCAST 0x00000004UL +#define VELOCITY_WOL_BCAST 0x00000010UL +#define VELOCITY_WOL_MCAST 0x00000020UL +#define VELOCITY_WOL_MAGIC_SEC 0x00000040UL + +/* + * Flags for options + */ + +#define VELOCITY_FLAGS_TAGGING 0x00000001UL +#define VELOCITY_FLAGS_TX_CSUM 0x00000002UL +#define VELOCITY_FLAGS_RX_CSUM 0x00000004UL +#define VELOCITY_FLAGS_IP_ALIGN 0x00000008UL +#define VELOCITY_FLAGS_VAL_PKT_LEN 0x00000010UL + +#define VELOCITY_FLAGS_FLOW_CTRL 0x01000000UL + +/* + * Flags for driver status + */ + +#define VELOCITY_FLAGS_OPENED 0x00010000UL +#define VELOCITY_FLAGS_VMNS_CONNECTED 0x00020000UL +#define VELOCITY_FLAGS_VMNS_COMMITTED 0x00040000UL +#define VELOCITY_FLAGS_WOL_ENABLED 0x00080000UL + +/* + * Flags for MII status + */ + +#define VELOCITY_LINK_FAIL 0x00000001UL +#define VELOCITY_SPEED_10 0x00000002UL +#define VELOCITY_SPEED_100 0x00000004UL +#define VELOCITY_SPEED_1000 0x00000008UL +#define VELOCITY_DUPLEX_FULL 0x00000010UL +#define VELOCITY_AUTONEG_ENABLE 0x00000020UL +#define VELOCITY_FORCED_BY_EEPROM 0x00000040UL + +/* + * For velocity_set_media_duplex + */ + +#define VELOCITY_LINK_CHANGE 0x00000001UL + +enum speed_opt { + SPD_DPX_AUTO = 0, + SPD_DPX_100_HALF = 1, + SPD_DPX_100_FULL = 2, + SPD_DPX_10_HALF = 3, + SPD_DPX_10_FULL = 4 +}; + +enum velocity_init_type { + VELOCITY_INIT_COLD = 0, + VELOCITY_INIT_RESET, + VELOCITY_INIT_WOL +}; + +enum velocity_flow_cntl_type { + FLOW_CNTL_DEFAULT = 1, + FLOW_CNTL_TX, + FLOW_CNTL_RX, + FLOW_CNTL_TX_RX, + FLOW_CNTL_DISABLE, +}; + +struct velocity_opt { + int numrx; /* Number of RX descriptors */ + int numtx; /* Number of TX descriptors */ + enum speed_opt spd_dpx; /* Media link mode */ + int vid; /* vlan id */ + int DMA_length; /* DMA length */ + int rx_thresh; /* RX_THRESH */ + int flow_cntl; + int wol_opts; /* Wake on lan options */ + int td_int_count; + int int_works; + int rx_bandwidth_hi; + int rx_bandwidth_lo; + int rx_bandwidth_en; + u32 flags; +}; + +struct velocity_info { + struct velocity_info *next; + struct velocity_info *prev; + + struct pci_dev *pdev; + struct net_device *dev; + struct net_device_stats stats; + +#if CONFIG_PM + u32 pci_state[16]; +#endif + + dma_addr_t rd_pool_dma; + dma_addr_t td_pool_dma[TX_QUEUE_NO]; + + dma_addr_t tx_bufs_dma; + u8 *tx_bufs; + + u8 ip_addr[4]; + enum chip_type chip_id; + + struct mac_regs * mac_regs; + unsigned long memaddr; + unsigned long ioaddr; + u32 io_size; + + u8 rev_id; + +#define AVAIL_TD(p,q) ((p)->options.numtx-((p)->td_used[(q)])) + + int num_txq; + + volatile int td_used[TX_QUEUE_NO]; + int td_curr[TX_QUEUE_NO]; + int td_tail[TX_QUEUE_NO]; + struct tx_desc *td_rings[TX_QUEUE_NO]; + struct velocity_td_info *td_infos[TX_QUEUE_NO]; + + int rd_curr; + int rd_used; + struct rx_desc *rd_ring; + struct velocity_rd_info *rd_info; /* It's an array */ + +#define GET_RD_BY_IDX(vptr, idx) (vptr->rd_ring[idx]) + u32 mib_counter[MAX_HW_MIB_COUNTER]; + struct velocity_opt options; + + u32 int_mask; + + u32 flags; + + int rx_buf_sz; + u32 mii_status; + u32 phy_id; + int multicast_limit; + + u8 vCAMmask[(VCAM_SIZE / 8)]; + u8 mCAMmask[(MCAM_SIZE / 8)]; + + spinlock_t lock; + spinlock_t xmit_lock; + + int wol_opts; + u8 wol_passwd[6]; + + struct velocity_context context; + + u32 ticks; + u32 rx_bytes; + +}; + +/** + * velocity_get_ip - find an IP address for the device + * @vptr: Velocity to query + * + * Dig out an IP address for this interface so that we can + * configure wakeup with WOL for ARP. If there are multiple IP + * addresses on this chain then we use the first - multi-IP WOL is not + * supported. + * + * CHECK ME: locking + */ + +inline static int velocity_get_ip(struct velocity_info *vptr) +{ + struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr; + struct in_ifaddr *ifa; + + if (in_dev != NULL) { + ifa = (struct in_ifaddr *) in_dev->ifa_list; + if (ifa != NULL) { + memcpy(vptr->ip_addr, &ifa->ifa_address, 4); + return 0; + } + } + return -ENOENT; +} + +/** + * velocity_update_hw_mibs - fetch MIB counters from chip + * @vptr: velocity to update + * + * The velocity hardware keeps certain counters in the hardware + * side. We need to read these when the user asks for statistics + * or when they overflow (causing an interrupt). The read of the + * statistic clears it, so we keep running master counters in user + * space. + */ + +static inline void velocity_update_hw_mibs(struct velocity_info *vptr) +{ + u32 tmp; + int i; + BYTE_REG_BITS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR)); + + while (BYTE_REG_BITS_IS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR))); + + BYTE_REG_BITS_ON(MIBCR_MPTRINI, &(vptr->mac_regs->MIBCR)); + for (i = 0; i < HW_MIB_SIZE; i++) { + tmp = readl(&(vptr->mac_regs->MIBData)) & 0x00FFFFFFUL; + vptr->mib_counter[i] += tmp; + } +} + +/** + * init_flow_control_register - set up flow control + * @vptr: velocity to configure + * + * Configure the flow control registers for this velocity device. + */ + +static inline void init_flow_control_register(struct velocity_info *vptr) +{ + struct mac_regs * regs = vptr->mac_regs; + + /* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1} + depend on RD=64, and Turn on XNOEN in FlowCR1 */ + writel((CR0_XONEN | CR0_XHITH1 | CR0_XLTH1 | CR0_XLTH0), ®s->CR0Set); + writel((CR0_FDXTFCEN | CR0_FDXRFCEN | CR0_HDXFCEN | CR0_XHITH0), ®s->CR0Clr); + + /* Set TxPauseTimer to 0xFFFF */ + writew(0xFFFF, ®s->tx_pause_timer); + + /* Initialize RBRDU to Rx buffer count. */ + writew(vptr->options.numrx, ®s->RBRDU); +} + + +#endif diff --git a/drivers/net/wan/comx-hw-comx.c b/drivers/net/wan/comx-hw-comx.c deleted file mode 100644 index a62fe5514..000000000 --- a/drivers/net/wan/comx-hw-comx.c +++ /dev/null @@ -1,1450 +0,0 @@ -/* - * Hardware-level driver for the COMX and HICOMX cards - * for Linux kernel 2.2.X - * - * Original authors: Arpad Bakay , - * Peter Bajan , - * Rewritten by: Tivadar Szemethy - * Currently maintained by: Gergely Madarasz - * - * Copyright (C) 1995-2000 ITConsult-Pro Co. - * - * Contributors: - * Arnaldo Carvalho de Melo - 0.86 - * Daniele Bellucci - 0.87 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.80 (99/06/11): - * - port back to kernel, add support builtin driver - * - cleaned up the source code a bit - * - * Version 0.81 (99/06/22): - * - cleaned up the board load functions, no more long reset - * timeouts - * - lower modem lines on close - * - some interrupt handling fixes - * - * Version 0.82 (99/08/24): - * - fix multiple board support - * - * Version 0.83 (99/11/30): - * - interrupt handling and locking fixes during initalization - * - really fix multiple board support - * - * Version 0.84 (99/12/02): - * - some workarounds for problematic hardware/firmware - * - * Version 0.85 (00/01/14): - * - some additional workarounds :/ - * - printk cleanups - * Version 0.86 (00/08/15): - * - resource release on failure at COMX_init - * - * Version 0.87 (03/07/09) - * - audit copy_from_user in comxhw_write_proc - */ - -#define VERSION "0.87" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "comx.h" -#include "comxhw.h" - -MODULE_AUTHOR("Gergely Madarasz , Tivadar Szemethy , Arpad Bakay"); -MODULE_DESCRIPTION("Hardware-level driver for the COMX and HICOMX adapters\n"); -MODULE_LICENSE("GPL"); - -#define COMX_readw(dev, offset) (readw(dev->mem_start + offset + \ - (unsigned int)(((struct comx_privdata *)\ - ((struct comx_channel *)dev->priv)->HW_privdata)->channel) \ - * COMX_CHANNEL_OFFSET)) - -#define COMX_WRITE(dev, offset, value) (writew(value, dev->mem_start + offset \ - + (unsigned int)(((struct comx_privdata *) \ - ((struct comx_channel *)dev->priv)->HW_privdata)->channel) \ - * COMX_CHANNEL_OFFSET)) - -#define COMX_CMD(dev, cmd) (COMX_WRITE(dev, OFF_A_L2_CMD, cmd)) - -struct comx_firmware { - int len; - unsigned char *data; -}; - -struct comx_privdata { - struct comx_firmware *firmware; - u16 clock; - char channel; // channel no. - int memory_size; - short io_extent; - u_long histogram[5]; -}; - -static struct net_device *memory_used[(COMX_MEM_MAX - COMX_MEM_MIN) / 0x10000]; -extern struct comx_hardware hicomx_hw; -extern struct comx_hardware comx_hw; -extern struct comx_hardware cmx_hw; - -static irqreturn_t COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static void COMX_board_on(struct net_device *dev) -{ - outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | - COMX_ENABLE_BOARD_IT | COMX_ENABLE_BOARD_MEM), dev->base_addr); -} - -static void COMX_board_off(struct net_device *dev) -{ - outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | - COMX_ENABLE_BOARD_IT), dev->base_addr); -} - -static void HICOMX_board_on(struct net_device *dev) -{ - outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | - HICOMX_ENABLE_BOARD_MEM), dev->base_addr); -} - -static void HICOMX_board_off(struct net_device *dev) -{ - outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | - HICOMX_DISABLE_BOARD_MEM), dev->base_addr); -} - -static void COMX_set_clock(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - - COMX_WRITE(dev, OFF_A_L1_CLKINI, hw->clock); -} - -static struct net_device *COMX_access_board(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct net_device *ret; - int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16; - unsigned long flags; - - - save_flags(flags); cli(); - - ret = memory_used[mempos]; - - if(ret == dev) { - goto out; - } - - memory_used[mempos] = dev; - - if (!ch->twin || ret != ch->twin) { - if (ret) ((struct comx_channel *)ret->priv)->HW_board_off(ret); - ch->HW_board_on(dev); - } -out: - restore_flags(flags); - return ret; -} - -static void COMX_release_board(struct net_device *dev, struct net_device *savep) -{ - unsigned long flags; - int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16; - struct comx_channel *ch = dev->priv; - - save_flags(flags); cli(); - - if (memory_used[mempos] == savep) { - goto out; - } - - memory_used[mempos] = savep; - if (!ch->twin || ch->twin != savep) { - ch->HW_board_off(dev); - if (savep) ((struct comx_channel*)savep->priv)->HW_board_on(savep); - } -out: - restore_flags(flags); -} - -static int COMX_txe(struct net_device *dev) -{ - struct net_device *savep; - struct comx_channel *ch = dev->priv; - int rc = 0; - - savep = ch->HW_access_board(dev); - if (COMX_readw(dev,OFF_A_L2_LINKUP) == LINKUP_READY) { - rc = COMX_readw(dev,OFF_A_L2_TxEMPTY); - } - ch->HW_release_board(dev,savep); - if(rc==0xffff) { - printk(KERN_ERR "%s, OFF_A_L2_TxEMPTY is %d\n",dev->name, rc); - } - return rc; -} - -static int COMX_send_packet(struct net_device *dev, struct sk_buff *skb) -{ - struct net_device *savep; - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - int ret = FRAME_DROPPED; - word tmp; - - savep = ch->HW_access_board(dev); - - if (ch->debug_flags & DEBUG_HW_TX) { - comx_debug_bytes(dev, skb->data, skb->len,"COMX_send packet"); - } - - if (skb->len > COMX_MAX_TX_SIZE) { - ret=FRAME_DROPPED; - goto out; - } - - tmp=COMX_readw(dev, OFF_A_L2_TxEMPTY); - if ((ch->line_status & LINE_UP) && tmp==1) { - int lensave = skb->len; - int dest = COMX_readw(dev, OFF_A_L2_TxBUFP); - word *data = (word *)skb->data; - - if(dest==0xffff) { - printk(KERN_ERR "%s: OFF_A_L2_TxBUFP is %d\n", dev->name, dest); - ret=FRAME_DROPPED; - goto out; - } - - writew((unsigned short)skb->len, dev->mem_start + dest); - dest += 2; - while (skb->len > 1) { - writew(*data++, dev->mem_start + dest); - dest += 2; skb->len -= 2; - } - if (skb->len == 1) { - writew(*((byte *)data), dev->mem_start + dest); - } - writew(0, dev->mem_start + (int)hw->channel * - COMX_CHANNEL_OFFSET + OFF_A_L2_TxEMPTY); - ch->stats.tx_packets++; - ch->stats.tx_bytes += lensave; - ret = FRAME_ACCEPTED; - } else { - ch->stats.tx_dropped++; - printk(KERN_INFO "%s: frame dropped\n",dev->name); - if(tmp) { - printk(KERN_ERR "%s: OFF_A_L2_TxEMPTY is %d\n",dev->name,tmp); - } - } - -out: - ch->HW_release_board(dev, savep); - dev_kfree_skb(skb); - return ret; -} - -static inline int comx_read_buffer(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - word rbuf_offs; - struct sk_buff *skb; - word len; - int i=0; - word *writeptr; - - i = 0; - rbuf_offs = COMX_readw(dev, OFF_A_L2_RxBUFP); - if(rbuf_offs == 0xffff) { - printk(KERN_ERR "%s: OFF_A_L2_RxBUFP is %d\n",dev->name,rbuf_offs); - return 0; - } - len = readw(dev->mem_start + rbuf_offs); - if(len > COMX_MAX_RX_SIZE) { - printk(KERN_ERR "%s: packet length is %d\n",dev->name,len); - return 0; - } - if ((skb = dev_alloc_skb(len + 16)) == NULL) { - ch->stats.rx_dropped++; - COMX_WRITE(dev, OFF_A_L2_DAV, 0); - return 0; - } - rbuf_offs += 2; - skb_reserve(skb, 16); - skb_put(skb, len); - skb->dev = dev; - writeptr = (word *)skb->data; - while (i < len) { - *writeptr++ = readw(dev->mem_start + rbuf_offs); - rbuf_offs += 2; - i += 2; - } - COMX_WRITE(dev, OFF_A_L2_DAV, 0); - ch->stats.rx_packets++; - ch->stats.rx_bytes += len; - if (ch->debug_flags & DEBUG_HW_RX) { - comx_debug_skb(dev, skb, "COMX_interrupt receiving"); - } - ch->LINE_rx(dev, skb); - return 1; -} - -static inline char comx_line_change(struct net_device *dev, char linestat) -{ - struct comx_channel *ch=dev->priv; - char idle=1; - - - if (linestat & LINE_UP) { /* Vonal fol */ - if (ch->lineup_delay) { - if (!test_and_set_bit(0, &ch->lineup_pending)) { - ch->lineup_timer.function = comx_lineup_func; - ch->lineup_timer.data = (unsigned long)dev; - ch->lineup_timer.expires = jiffies + - HZ*ch->lineup_delay; - add_timer(&ch->lineup_timer); - idle=0; - } - } else { - idle=0; - ch->LINE_status(dev, ch->line_status |= LINE_UP); - } - } else { /* Vonal le */ - idle=0; - if (test_and_clear_bit(0, &ch->lineup_pending)) { - del_timer(&ch->lineup_timer); - } else { - ch->line_status &= ~LINE_UP; - if (ch->LINE_status) { - ch->LINE_status(dev, ch->line_status); - } - } - } - return idle; -} - - - -static irqreturn_t COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct net_device *interrupted; - unsigned long jiffs; - char idle = 0; - int count = 0; - word tmp; - - if (dev == NULL) { - printk(KERN_ERR "COMX_interrupt: irq %d for unknown device\n", irq); - return IRQ_NONE; - } - - jiffs = jiffies; - - interrupted = ch->HW_access_board(dev); - - while (!idle && count < 5000) { - char channel = 0; - idle = 1; - - while (channel < 2) { - char linestat = 0; - char buffers_emptied = 0; - - if (channel == 1) { - if (ch->twin) { - dev = ch->twin; - ch = dev->priv; - hw = ch->HW_privdata; - } else { - break; - } - } else { - COMX_WRITE(dev, OFF_A_L1_REPENA, - COMX_readw(dev, OFF_A_L1_REPENA) & 0xFF00); - } - channel++; - - if ((ch->init_status & (HW_OPEN | LINE_OPEN)) != - (HW_OPEN | LINE_OPEN)) { - continue; - } - - /* Collect stats */ - tmp = COMX_readw(dev, OFF_A_L1_ABOREC); - COMX_WRITE(dev, OFF_A_L1_ABOREC, 0); - if(tmp==0xffff) { - printk(KERN_ERR "%s: OFF_A_L1_ABOREC is %d\n",dev->name,tmp); - break; - } else { - ch->stats.rx_missed_errors += (tmp >> 8) & 0xff; - ch->stats.rx_over_errors += tmp & 0xff; - } - tmp = COMX_readw(dev, OFF_A_L1_CRCREC); - COMX_WRITE(dev, OFF_A_L1_CRCREC, 0); - if(tmp==0xffff) { - printk(KERN_ERR "%s: OFF_A_L1_CRCREC is %d\n",dev->name,tmp); - break; - } else { - ch->stats.rx_crc_errors += (tmp >> 8) & 0xff; - ch->stats.rx_missed_errors += tmp & 0xff; - } - - if ((ch->line_status & LINE_UP) && ch->LINE_rx) { - tmp=COMX_readw(dev, OFF_A_L2_DAV); - while (tmp==1) { - idle=0; - buffers_emptied+=comx_read_buffer(dev); - tmp=COMX_readw(dev, OFF_A_L2_DAV); - } - if(tmp) { - printk(KERN_ERR "%s: OFF_A_L2_DAV is %d\n", dev->name, tmp); - break; - } - } - - tmp=COMX_readw(dev, OFF_A_L2_TxEMPTY); - if (tmp==1 && ch->LINE_tx) { - ch->LINE_tx(dev); - } - if(tmp==0xffff) { - printk(KERN_ERR "%s: OFF_A_L2_TxEMPTY is %d\n", dev->name, tmp); - break; - } - - if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) { - linestat &= ~LINE_UP; - } else { - linestat |= LINE_UP; - } - - if ((linestat & LINE_UP) != (ch->line_status & LINE_UP)) { - ch->stats.tx_carrier_errors++; - idle &= comx_line_change(dev,linestat); - } - - hw->histogram[(int)buffers_emptied]++; - } - count++; - } - - if(count==5000) { - printk(KERN_WARNING "%s: interrupt stuck\n",dev->name); - } - - ch->HW_release_board(dev, interrupted); - return IRQ_HANDLED; -} - -static int COMX_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - unsigned long jiffs; - int twin_open=0; - int retval; - struct net_device *savep; - - if (!dev->base_addr || !dev->irq || !dev->mem_start) { - return -ENODEV; - } - - if (ch->twin && (((struct comx_channel *)(ch->twin->priv))->init_status & HW_OPEN)) { - twin_open=1; - } - - if (!twin_open) { - if (!request_region(dev->base_addr, hw->io_extent, dev->name)) { - return -EAGAIN; - } - if (request_irq(dev->irq, COMX_interrupt, 0, dev->name, - (void *)dev)) { - printk(KERN_ERR "comx-hw-comx: unable to obtain irq %d\n", dev->irq); - release_region(dev->base_addr, hw->io_extent); - return -EAGAIN; - } - ch->init_status |= IRQ_ALLOCATED; - if (!ch->HW_load_board || ch->HW_load_board(dev)) { - ch->init_status &= ~IRQ_ALLOCATED; - retval=-ENODEV; - goto error; - } - } - - savep = ch->HW_access_board(dev); - COMX_WRITE(dev, OFF_A_L2_LINKUP, 0); - - if (ch->HW_set_clock) { - ch->HW_set_clock(dev); - } - - COMX_CMD(dev, COMX_CMD_INIT); - jiffs = jiffies; - while (COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && time_before(jiffies, jiffs + HZ)) { - schedule_timeout(1); - } - - if (time_after_eq(jiffies, jiffs + HZ)) { - printk(KERN_ERR "%s: board timeout on INIT command\n", dev->name); - ch->HW_release_board(dev, savep); - retval=-EIO; - goto error; - } - udelay(1000); - - COMX_CMD(dev, COMX_CMD_OPEN); - - jiffs = jiffies; - while (COMX_readw(dev, OFF_A_L2_LINKUP) != 3 && time_before(jiffies, jiffs + HZ)) { - schedule_timeout(1); - } - - if (time_after_eq(jiffies, jiffs + HZ)) { - printk(KERN_ERR "%s: board timeout on OPEN command\n", dev->name); - ch->HW_release_board(dev, savep); - retval=-EIO; - goto error; - } - - ch->init_status |= HW_OPEN; - - /* Ez eleg ciki, de ilyen a rendszer */ - if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) { - ch->line_status &= ~LINE_UP; - } else { - ch->line_status |= LINE_UP; - } - - if (ch->LINE_status) { - ch->LINE_status(dev, ch->line_status); - } - - ch->HW_release_board(dev, savep); - - for ( ; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IRQ) == 0 - || strcmp(procfile->name, FILENAME_IO) == 0 - || strcmp(procfile->name, FILENAME_MEMADDR) == 0 - || strcmp(procfile->name, FILENAME_CHANNEL) == 0 - || strcmp(procfile->name, FILENAME_FIRMWARE) == 0 - || strcmp(procfile->name, FILENAME_CLOCK) == 0) { - procfile->mode = S_IFREG | 0444; - - } - } - - return 0; - -error: - if(!twin_open) { - release_region(dev->base_addr, hw->io_extent); - free_irq(dev->irq, (void *)dev); - } - return retval; - -} - -static int COMX_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *procfile = ch->procdir->subdir; - struct comx_privdata *hw = ch->HW_privdata; - struct comx_channel *twin_ch; - struct net_device *savep; - - savep = ch->HW_access_board(dev); - - COMX_CMD(dev, COMX_CMD_CLOSE); - udelay(1000); - COMX_CMD(dev, COMX_CMD_EXIT); - - ch->HW_release_board(dev, savep); - - if (ch->init_status & IRQ_ALLOCATED) { - free_irq(dev->irq, (void *)dev); - ch->init_status &= ~IRQ_ALLOCATED; - } - release_region(dev->base_addr, hw->io_extent); - - if (ch->twin && (twin_ch = ch->twin->priv) && - (twin_ch->init_status & HW_OPEN)) { - /* Pass the irq to the twin */ - if (request_irq(dev->irq, COMX_interrupt, 0, ch->twin->name, - (void *)ch->twin) == 0) { - twin_ch->init_status |= IRQ_ALLOCATED; - } - } - - for ( ; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IRQ) == 0 - || strcmp(procfile->name, FILENAME_IO) == 0 - || strcmp(procfile->name, FILENAME_MEMADDR) == 0 - || strcmp(procfile->name, FILENAME_CHANNEL) == 0 - || strcmp(procfile->name, FILENAME_FIRMWARE) == 0 - || strcmp(procfile->name, FILENAME_CLOCK) == 0) { - procfile->mode = S_IFREG | 0644; - } - } - - ch->init_status &= ~HW_OPEN; - return 0; -} - -static int COMX_statistics(struct net_device *dev, char *page) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct net_device *savep; - int len = 0; - - savep = ch->HW_access_board(dev); - - len += sprintf(page + len, "Board data: %s %s %s %s\nPBUFOVR: %02x, " - "MODSTAT: %02x, LINKUP: %02x, DAV: %02x\nRxBUFP: %02x, " - "TxEMPTY: %02x, TxBUFP: %02x\n", - (ch->init_status & HW_OPEN) ? "HW_OPEN" : "", - (ch->init_status & LINE_OPEN) ? "LINE_OPEN" : "", - (ch->init_status & FW_LOADED) ? "FW_LOADED" : "", - (ch->init_status & IRQ_ALLOCATED) ? "IRQ_ALLOCATED" : "", - COMX_readw(dev, OFF_A_L1_PBUFOVR) & 0xff, - (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) & 0xff, - COMX_readw(dev, OFF_A_L2_LINKUP) & 0xff, - COMX_readw(dev, OFF_A_L2_DAV) & 0xff, - COMX_readw(dev, OFF_A_L2_RxBUFP) & 0xff, - COMX_readw(dev, OFF_A_L2_TxEMPTY) & 0xff, - COMX_readw(dev, OFF_A_L2_TxBUFP) & 0xff); - - len += sprintf(page + len, "hist[0]: %8lu hist[1]: %8lu hist[2]: %8lu\n" - "hist[3]: %8lu hist[4]: %8lu\n",hw->histogram[0],hw->histogram[1], - hw->histogram[2],hw->histogram[3],hw->histogram[4]); - - ch->HW_release_board(dev, savep); - - return len; -} - -static int COMX_load_board(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct comx_firmware *fw = hw->firmware; - word board_segment = dev->mem_start >> 16; - int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16; - unsigned long flags; - unsigned char id1, id2; - struct net_device *saved; - int retval; - int loopcount; - int len; - byte *COMX_address; - - if (!fw || !fw->len) { - struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL; - struct comx_privdata *twin_hw; - - if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) { - return -EAGAIN; - } - - if (!(fw = twin_hw->firmware) || !fw->len) { - return -EAGAIN; - } - } - - id1 = fw->data[OFF_FW_L1_ID]; - id2 = fw->data[OFF_FW_L1_ID + 1]; - - if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_COMX) { - printk(KERN_ERR "%s: incorrect firmware, load aborted\n", - dev->name); - return -EAGAIN; - } - - printk(KERN_INFO "%s: Loading COMX Layer 1 firmware %s\n", dev->name, - (char *)(fw->data + OFF_FW_L1_ID + 2)); - - id1 = fw->data[OFF_FW_L2_ID]; - id2 = fw->data[OFF_FW_L2_ID + 1]; - if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) { - printk(KERN_INFO "with Layer 2 code %s\n", - (char *)(fw->data + OFF_FW_L2_ID + 2)); - } - - outb_p(board_segment | COMX_BOARD_RESET, dev->base_addr); - /* 10 usec should be enough here */ - udelay(100); - - save_flags(flags); cli(); - saved=memory_used[mempos]; - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_off(saved); - } - memory_used[mempos]=dev; - - outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr); - - writeb(0, dev->mem_start + COMX_JAIL_OFFSET); - - loopcount=0; - while(loopcount++ < 10000 && - readb(dev->mem_start + COMX_JAIL_OFFSET) != COMX_JAIL_VALUE) { - udelay(100); - } - - if (readb(dev->mem_start + COMX_JAIL_OFFSET) != COMX_JAIL_VALUE) { - printk(KERN_ERR "%s: Can't reset board, JAIL value is %02x\n", - dev->name, readb(dev->mem_start + COMX_JAIL_OFFSET)); - retval=-ENODEV; - goto out; - } - - writeb(0x55, dev->mem_start + 0x18ff); - - loopcount=0; - while(loopcount++ < 10000 && readb(dev->mem_start + 0x18ff) != 0) { - udelay(100); - } - - if(readb(dev->mem_start + 0x18ff) != 0) { - printk(KERN_ERR "%s: Can't reset board, reset timeout\n", - dev->name); - retval=-ENODEV; - goto out; - } - - len = 0; - COMX_address = (byte *)dev->mem_start; - while (fw->len > len) { - writeb(fw->data[len++], COMX_address++); - } - - len = 0; - COMX_address = (byte *)dev->mem_start; - while (len != fw->len && readb(COMX_address++) == fw->data[len]) { - len++; - } - - if (len != fw->len) { - printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x " - "instead of 0x%02x\n", dev->name, len, - readb(COMX_address - 1), fw->data[len]); - retval=-EAGAIN; - goto out; - } - - writeb(0, dev->mem_start + COMX_JAIL_OFFSET); - - loopcount = 0; - while ( loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) { - udelay(100); - } - - if (COMX_readw(dev, OFF_A_L2_LINKUP) != 1) { - printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n", - dev->name, COMX_readw(dev, OFF_A_L2_LINKUP)); - retval=-EAGAIN; - goto out; - } - - - ch->init_status |= FW_LOADED; - retval=0; - -out: - outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr); - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_on(saved); - } - memory_used[mempos]=saved; - restore_flags(flags); - return retval; -} - -static int CMX_load_board(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct comx_firmware *fw = hw->firmware; - word board_segment = dev->mem_start >> 16; - int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16; - #if 0 - unsigned char id1, id2; - #endif - struct net_device *saved; - unsigned long flags; - int retval; - int loopcount; - int len; - byte *COMX_address; - - if (!fw || !fw->len) { - struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL; - struct comx_privdata *twin_hw; - - if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) { - return -EAGAIN; - } - - if (!(fw = twin_hw->firmware) || !fw->len) { - return -EAGAIN; - } - } - - /* Ide kell olyat tenni, hogy ellenorizze az ID-t */ - - if (inb_p(dev->base_addr) != CMX_ID_BYTE) { - printk(KERN_ERR "%s: CMX id byte is invalid(%02x)\n", dev->name, - inb_p(dev->base_addr)); - return -ENODEV; - } - - printk(KERN_INFO "%s: Loading CMX Layer 1 firmware %s\n", dev->name, - (char *)(fw->data + OFF_FW_L1_ID + 2)); - - save_flags(flags); cli(); - saved=memory_used[mempos]; - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_off(saved); - } - memory_used[mempos]=dev; - - outb_p(board_segment | COMX_ENABLE_BOARD_MEM | COMX_BOARD_RESET, - dev->base_addr); - - len = 0; - COMX_address = (byte *)dev->mem_start; - while (fw->len > len) { - writeb(fw->data[len++], COMX_address++); - } - - len = 0; - COMX_address = (byte *)dev->mem_start; - while (len != fw->len && readb(COMX_address++) == fw->data[len]) { - len++; - } - - outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr); - - if (len != fw->len) { - printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x " - "instead of 0x%02x\n", dev->name, len, - readb(COMX_address - 1), fw->data[len]); - retval=-EAGAIN; - goto out; - } - - loopcount=0; - while( loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) { - udelay(100); - } - - if (COMX_readw(dev, OFF_A_L2_LINKUP) != 1) { - printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n", - dev->name, COMX_readw(dev, OFF_A_L2_LINKUP)); - retval=-EAGAIN; - goto out; - } - - ch->init_status |= FW_LOADED; - retval=0; - -out: - outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr); - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_on(saved); - } - memory_used[mempos]=saved; - restore_flags(flags); - return retval; -} - -static int HICOMX_load_board(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - struct comx_firmware *fw = hw->firmware; - word board_segment = dev->mem_start >> 12; - int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16; - struct net_device *saved; - unsigned char id1, id2; - unsigned long flags; - int retval; - int loopcount; - int len; - word *HICOMX_address; - char id = 1; - - if (!fw || !fw->len) { - struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL; - struct comx_privdata *twin_hw; - - if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) { - return -EAGAIN; - } - - if (!(fw = twin_hw->firmware) || !fw->len) { - return -EAGAIN; - } - } - - while (id != 4) { - if (inb_p(dev->base_addr + id++) != HICOMX_ID_BYTE) { - break; - } - } - - if (id != 4) { - printk(KERN_ERR "%s: can't find HICOMX at 0x%04x, id[%d] = %02x\n", - dev->name, (unsigned int)dev->base_addr, id - 1, - inb_p(dev->base_addr + id - 1)); - return -1; - } - - id1 = fw->data[OFF_FW_L1_ID]; - id2 = fw->data[OFF_FW_L1_ID + 1]; - if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_HICOMX) { - printk(KERN_ERR "%s: incorrect firmware, load aborted\n", dev->name); - return -EAGAIN; - } - - printk(KERN_INFO "%s: Loading HICOMX Layer 1 firmware %s\n", dev->name, - (char *)(fw->data + OFF_FW_L1_ID + 2)); - - id1 = fw->data[OFF_FW_L2_ID]; - id2 = fw->data[OFF_FW_L2_ID + 1]; - if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) { - printk(KERN_INFO "with Layer 2 code %s\n", - (char *)(fw->data + OFF_FW_L2_ID + 2)); - } - - outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr); - udelay(10); - - save_flags(flags); cli(); - saved=memory_used[mempos]; - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_off(saved); - } - memory_used[mempos]=dev; - - outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr); - outb_p(HICOMX_PRG_MEM, dev->base_addr + 1); - - len = 0; - HICOMX_address = (word *)dev->mem_start; - while (fw->len > len) { - writeb(fw->data[len++], HICOMX_address++); - } - - len = 0; - HICOMX_address = (word *)dev->mem_start; - while (len != fw->len && (readw(HICOMX_address++) & 0xff) == fw->data[len]) { - len++; - } - - if (len != fw->len) { - printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x " - "instead of 0x%02x\n", dev->name, len, - readw(HICOMX_address - 1) & 0xff, fw->data[len]); - retval=-EAGAIN; - goto out; - } - - outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr); - outb_p(HICOMX_DATA_MEM, dev->base_addr + 1); - - outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr); - - loopcount=0; - while(loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1) { - udelay(100); - } - - if ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) { - printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n", - dev->name, COMX_readw(dev, OFF_A_L2_LINKUP)); - retval=-EAGAIN; - goto out; - } - - ch->init_status |= FW_LOADED; - retval=0; - -out: - outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr); - outb_p(HICOMX_DATA_MEM, dev->base_addr + 1); - - if(saved) { - ((struct comx_channel *)saved->priv)->HW_board_on(saved); - } - memory_used[mempos]=saved; - restore_flags(flags); - return retval; -} - -static struct net_device *comx_twin_check(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *procfile = ch->procdir->parent->subdir; - struct comx_privdata *hw = ch->HW_privdata; - - struct net_device *twin; - struct comx_channel *ch_twin; - struct comx_privdata *hw_twin; - - - for ( ; procfile ; procfile = procfile->next) { - - if(!S_ISDIR(procfile->mode)) { - continue; - } - - twin=procfile->data; - ch_twin=twin->priv; - hw_twin=ch_twin->HW_privdata; - - - if (twin != dev && dev->irq && dev->base_addr && dev->mem_start && - dev->irq == twin->irq && dev->base_addr == twin->base_addr && - dev->mem_start == twin->mem_start && - hw->channel == (1 - hw_twin->channel) && - ch->hardware == ch_twin->hardware) { - return twin; - } - } - return NULL; -} - -static int comxhw_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = entry->parent->data; - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - char *page; - - - if(ch->init_status & HW_OPEN) { - return -EAGAIN; - } - - if (strcmp(FILENAME_FIRMWARE, entry->name) != 0) { - if (!(page = (char *)__get_free_page(GFP_KERNEL))) { - return -ENOMEM; - } - if(copy_from_user(page, buffer, count = (min_t(int, count, PAGE_SIZE)))) - { - count = -EFAULT; - goto out; - } - if (page[count-1] == '\n') - page[count-1] = '\0'; - else if (count < PAGE_SIZE) - page[count] = '\0'; - else if (page[count]) { - count = -EINVAL; - goto out; - } - page[count]=0; /* Null terminate */ - } else { - byte *tmp; - - if (!hw->firmware) { - if ((hw->firmware = kmalloc(sizeof(struct comx_firmware), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - hw->firmware->len = 0; - hw->firmware->data = NULL; - } - - if ((tmp = kmalloc(count + file->f_pos, GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - /* Ha nem 0 a fpos, akkor meglevo file-t irunk. Gyenge trukk. */ - if (hw->firmware && hw->firmware->len && file->f_pos - && hw->firmware->len < count + file->f_pos) { - memcpy(tmp, hw->firmware->data, hw->firmware->len); - } - if (hw->firmware->data) { - kfree(hw->firmware->data); - } - if (copy_from_user(tmp + file->f_pos, buffer, count)) - return -EFAULT; - hw->firmware->len = entry->size = file->f_pos + count; - hw->firmware->data = tmp; - file->f_pos += count; - return count; - } - - if (strcmp(entry->name, FILENAME_CHANNEL) == 0) { - hw->channel = simple_strtoul(page, NULL, 0); - if (hw->channel >= MAX_CHANNELNO) { - printk(KERN_ERR "Invalid channel number\n"); - hw->channel = 0; - } - if ((ch->twin = comx_twin_check(dev)) != NULL) { - struct comx_channel *twin_ch = ch->twin->priv; - twin_ch->twin = dev; - } - } else if (strcmp(entry->name, FILENAME_IRQ) == 0) { - dev->irq = simple_strtoul(page, NULL, 0); - if (dev->irq == 2) { - dev->irq = 9; - } - if (dev->irq < 3 || dev->irq > 15) { - printk(KERN_ERR "comxhw: Invalid irq number\n"); - dev->irq = 0; - } - if ((ch->twin = comx_twin_check(dev)) != NULL) { - struct comx_channel *twin_ch = ch->twin->priv; - twin_ch->twin = dev; - } - } else if (strcmp(entry->name, FILENAME_IO) == 0) { - dev->base_addr = simple_strtoul(page, NULL, 0); - if ((dev->base_addr & 3) != 0 || dev->base_addr < 0x300 - || dev->base_addr > 0x3fc) { - printk(KERN_ERR "Invalid io value\n"); - dev->base_addr = 0; - } - if ((ch->twin = comx_twin_check(dev)) != NULL) { - struct comx_channel *twin_ch = ch->twin->priv; - - twin_ch->twin = dev; - } - } else if (strcmp(entry->name, FILENAME_MEMADDR) == 0) { - dev->mem_start = simple_strtoul(page, NULL, 0); - if (dev->mem_start <= 0xf000 && dev->mem_start >= 0xa000) { - dev->mem_start *= 16; - } - if ((dev->mem_start & 0xfff) != 0 || dev->mem_start < COMX_MEM_MIN - || dev->mem_start + hw->memory_size > COMX_MEM_MAX) { - printk(KERN_ERR "Invalid memory page\n"); - dev->mem_start = 0; - } - dev->mem_end = dev->mem_start + hw->memory_size; - if ((ch->twin = comx_twin_check(dev)) != NULL) { - struct comx_channel *twin_ch = ch->twin->priv; - - twin_ch->twin = dev; - } - } else if (strcmp(entry->name, FILENAME_CLOCK) == 0) { - if (strncmp("ext", page, 3) == 0) { - hw->clock = 0; - } else { - int kbps; - - kbps = simple_strtoul(page, NULL, 0); - hw->clock = kbps ? COMX_CLOCK_CONST/kbps : 0; - } - } -out: - free_page((unsigned long)page); - return count; -} - -static int comxhw_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - int len = 0; - - - if (strcmp(file->name, FILENAME_IO) == 0) { - len = sprintf(page, "0x%03x\n", (unsigned int)dev->base_addr); - } else if (strcmp(file->name, FILENAME_IRQ) == 0) { - len = sprintf(page, "0x%02x\n", dev->irq == 9 ? 2 : dev->irq); - } else if (strcmp(file->name, FILENAME_CHANNEL) == 0) { - len = sprintf(page, "%01d\n", hw->channel); - } else if (strcmp(file->name, FILENAME_MEMADDR) == 0) { - len = sprintf(page, "0x%05x\n", (unsigned int)dev->mem_start); - } else if (strcmp(file->name, FILENAME_TWIN) == 0) { - len = sprintf(page, "%s\n", ch->twin ? ch->twin->name : "none"); - } else if (strcmp(file->name, FILENAME_CLOCK) == 0) { - if (hw->clock) { - len = sprintf(page, "%-8d\n", COMX_CLOCK_CONST/hw->clock); - } else { - len = sprintf(page, "external\n"); - } - } else if (strcmp(file->name, FILENAME_FIRMWARE) == 0) { - len = min_t(int, FILE_PAGESIZE, - min_t(int, count, - hw->firmware ? - (hw->firmware->len - off) : 0)); - if (len < 0) { - len = 0; - } - *start = hw->firmware ? (hw->firmware->data + off) : NULL; - if (off + len >= (hw->firmware ? hw->firmware->len : 0) || len == 0) { - *eof = 1; - } - return len; - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) { - *eof = 1; - } - return min_t(int, count, len - off); -} - -/* Called on echo comx >boardtype */ -static int COMX_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw; - struct proc_dir_entry *new_file; - - if ((ch->HW_privdata = kmalloc(sizeof(struct comx_privdata), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(hw = ch->HW_privdata, 0, sizeof(struct comx_privdata)); - - if (ch->hardware == &comx_hw || ch->hardware == &cmx_hw) { - hw->memory_size = COMX_MEMORY_SIZE; - hw->io_extent = COMX_IO_EXTENT; - dev->base_addr = COMX_DEFAULT_IO; - dev->irq = COMX_DEFAULT_IRQ; - dev->mem_start = COMX_DEFAULT_MEMADDR; - dev->mem_end = COMX_DEFAULT_MEMADDR + COMX_MEMORY_SIZE; - } else if (ch->hardware == &hicomx_hw) { - hw->memory_size = HICOMX_MEMORY_SIZE; - hw->io_extent = HICOMX_IO_EXTENT; - dev->base_addr = HICOMX_DEFAULT_IO; - dev->irq = HICOMX_DEFAULT_IRQ; - dev->mem_start = HICOMX_DEFAULT_MEMADDR; - dev->mem_end = HICOMX_DEFAULT_MEMADDR + HICOMX_MEMORY_SIZE; - } else { - printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__); - } - - if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir)) - == NULL) { - goto cleanup_HW_privdata; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->size = 6; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir)) - == NULL) { - goto cleanup_filename_io; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->size = 5; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_irq; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->size = 2; // Ezt tudjuk - new_file->nlink = 1; - - if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) { - if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_channel; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->size = 9; - new_file->nlink = 1; - } - - if ((new_file = create_proc_entry(FILENAME_MEMADDR, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_clock; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->size = 8; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, - ch->procdir)) == NULL) { - goto cleanup_filename_memaddr; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = NULL; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_FIRMWARE, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_twin; - } - new_file->data = (void *)new_file; - new_file->read_proc = &comxhw_read_proc; - new_file->write_proc = &comxhw_write_proc; - new_file->nlink = 1; - - if (ch->hardware == &comx_hw) { - ch->HW_board_on = COMX_board_on; - ch->HW_board_off = COMX_board_off; - ch->HW_load_board = COMX_load_board; - } else if (ch->hardware == &cmx_hw) { - ch->HW_board_on = COMX_board_on; - ch->HW_board_off = COMX_board_off; - ch->HW_load_board = CMX_load_board; - ch->HW_set_clock = COMX_set_clock; - } else if (ch->hardware == &hicomx_hw) { - ch->HW_board_on = HICOMX_board_on; - ch->HW_board_off = HICOMX_board_off; - ch->HW_load_board = HICOMX_load_board; - ch->HW_set_clock = COMX_set_clock; - } else { - printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__); - } - - ch->HW_access_board = COMX_access_board; - ch->HW_release_board = COMX_release_board; - ch->HW_txe = COMX_txe; - ch->HW_open = COMX_open; - ch->HW_close = COMX_close; - ch->HW_send_packet = COMX_send_packet; - ch->HW_statistics = COMX_statistics; - - if ((ch->twin = comx_twin_check(dev)) != NULL) { - struct comx_channel *twin_ch = ch->twin->priv; - - twin_ch->twin = dev; - } - - MOD_INC_USE_COUNT; - return 0; - -cleanup_filename_twin: - remove_proc_entry(FILENAME_TWIN, ch->procdir); -cleanup_filename_memaddr: - remove_proc_entry(FILENAME_MEMADDR, ch->procdir); -cleanup_filename_clock: - if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) - remove_proc_entry(FILENAME_CLOCK, ch->procdir); -cleanup_filename_channel: - remove_proc_entry(FILENAME_CHANNEL, ch->procdir); -cleanup_filename_irq: - remove_proc_entry(FILENAME_IRQ, ch->procdir); -cleanup_filename_io: - remove_proc_entry(FILENAME_IO, ch->procdir); -cleanup_HW_privdata: - kfree(ch->HW_privdata); - return -EIO; -} - -/* Called on echo valami >boardtype */ -static int COMX_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_privdata *hw = ch->HW_privdata; - - if (hw->firmware) { - if (hw->firmware->data) kfree(hw->firmware->data); - kfree(hw->firmware); - } if (ch->twin) { - struct comx_channel *twin_ch = ch->twin->priv; - - twin_ch->twin = NULL; - } - - kfree(ch->HW_privdata); - remove_proc_entry(FILENAME_IO, ch->procdir); - remove_proc_entry(FILENAME_IRQ, ch->procdir); - remove_proc_entry(FILENAME_CHANNEL, ch->procdir); - remove_proc_entry(FILENAME_MEMADDR, ch->procdir); - remove_proc_entry(FILENAME_FIRMWARE, ch->procdir); - remove_proc_entry(FILENAME_TWIN, ch->procdir); - if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) { - remove_proc_entry(FILENAME_CLOCK, ch->procdir); - } - - MOD_DEC_USE_COUNT; - return 0; -} - -static int COMX_dump(struct net_device *dev) -{ - printk(KERN_INFO "%s: COMX_dump called, why ?\n", dev->name); - return 0; -} - -static struct comx_hardware comx_hw = { - "comx", - VERSION, - COMX_init, - COMX_exit, - COMX_dump, - NULL -}; - -static struct comx_hardware cmx_hw = { - "cmx", - VERSION, - COMX_init, - COMX_exit, - COMX_dump, - NULL -}; - -static struct comx_hardware hicomx_hw = { - "hicomx", - VERSION, - COMX_init, - COMX_exit, - COMX_dump, - NULL -}; - -static int __init comx_hw_comx_init(void) -{ - comx_register_hardware(&comx_hw); - comx_register_hardware(&cmx_hw); - comx_register_hardware(&hicomx_hw); - return 0; -} - -static void __exit comx_hw_comx_exit(void) -{ - comx_unregister_hardware("comx"); - comx_unregister_hardware("cmx"); - comx_unregister_hardware("hicomx"); -} - -module_init(comx_hw_comx_init); -module_exit(comx_hw_comx_exit); diff --git a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c deleted file mode 100644 index 52460164a..000000000 --- a/drivers/net/wan/comx-hw-locomx.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Hardware driver for the LoCOMX card, using the generic z85230 - * functions - * - * Author: Gergely Madarasz - * - * Based on skeleton code and old LoCOMX driver by Tivadar Szemethy - * and the hostess_sv11 driver - * - * Contributors: - * Arnaldo Carvalho de Melo (0.14) - * - * Copyright (C) 1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.10 (99/06/17): - * - rewritten for the z85230 layer - * - * Version 0.11 (99/06/21): - * - some printk's fixed - * - get rid of a memory leak (it was impossible though :)) - * - * Version 0.12 (99/07/07): - * - check CTS for modem lines, not DCD (which is always high - * in case of this board) - * Version 0.13 (99/07/08): - * - Fix the transmitter status check - * - Handle the net device statistics better - * Version 0.14 (00/08/15): - * - resource release on failure at LOCOMX_init - */ - -#define VERSION "0.14" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "comx.h" -#include "z85230.h" - -MODULE_AUTHOR("Gergely Madarasz "); -MODULE_DESCRIPTION("Hardware driver for the LoCOMX board"); -MODULE_LICENSE("GPL"); - -#define RX_DMA 3 -#define TX_DMA 1 -#define LOCOMX_ID 0x33 -#define LOCOMX_IO_EXTENT 8 -#define LOCOMX_DEFAULT_IO 0x368 -#define LOCOMX_DEFAULT_IRQ 7 - -u8 z8530_locomx[] = { - 11, TCRTxCP, - 14, DTRREQ, - 255 -}; - -struct locomx_data { - int io_extent; - struct z8530_dev board; - struct timer_list status_timer; -}; - -static int LOCOMX_txe(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw = ch->HW_privdata; - - return (!hw->board.chanA.tx_next_skb); -} - - -static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb) -{ - struct net_device *dev = c->netdevice; - struct comx_channel *ch = netdev_priv(dev); - - if (ch->debug_flags & DEBUG_HW_RX) { - comx_debug_skb(dev, skb, "locomx_rx receiving"); - } - ch->LINE_rx(dev,skb); -} - -static int LOCOMX_send_packet(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw = ch->HW_privdata; - - if (ch->debug_flags & DEBUG_HW_TX) { - comx_debug_bytes(dev, skb->data, skb->len, "LOCOMX_send_packet"); - } - - if (!(ch->line_status & LINE_UP)) { - return FRAME_DROPPED; - } - - if(z8530_queue_xmit(&hw->board.chanA,skb)) { - printk(KERN_WARNING "%s: FRAME_DROPPED\n",dev->name); - return FRAME_DROPPED; - } - - if (ch->debug_flags & DEBUG_HW_TX) { - comx_debug(dev, "%s: LOCOMX_send_packet was successful\n\n", dev->name); - } - - if(!hw->board.chanA.tx_next_skb) { - return FRAME_QUEUED; - } else { - return FRAME_ACCEPTED; - } -} - -static void locomx_status_timerfun(unsigned long d) -{ - struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw = ch->HW_privdata; - - if(!(ch->line_status & LINE_UP) && - (hw->board.chanA.status & CTS)) { - ch->LINE_status(dev, ch->line_status | LINE_UP); - } - if((ch->line_status & LINE_UP) && - !(hw->board.chanA.status & CTS)) { - ch->LINE_status(dev, ch->line_status & ~LINE_UP); - } - mod_timer(&hw->status_timer,jiffies + ch->lineup_delay * HZ); -} - - -static int LOCOMX_open(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - unsigned long flags; - int ret; - - if (!dev->base_addr || !dev->irq) { - return -ENODEV; - } - - if (!request_region(dev->base_addr, hw->io_extent, dev->name)) { - return -EAGAIN; - } - - hw->board.chanA.ctrlio=dev->base_addr + 5; - hw->board.chanA.dataio=dev->base_addr + 7; - - hw->board.irq=dev->irq; - hw->board.chanA.netdevice=dev; - hw->board.chanA.dev=&hw->board; - hw->board.name=dev->name; - hw->board.chanA.txdma=TX_DMA; - hw->board.chanA.rxdma=RX_DMA; - hw->board.chanA.irqs=&z8530_nop; - hw->board.chanB.irqs=&z8530_nop; - - if(request_irq(dev->irq, z8530_interrupt, SA_INTERRUPT, - dev->name, &hw->board)) { - printk(KERN_ERR "%s: unable to obtain irq %d\n", dev->name, - dev->irq); - ret=-EAGAIN; - goto irq_fail; - } - if(request_dma(TX_DMA,"LoCOMX (TX)")) { - printk(KERN_ERR "%s: unable to obtain TX DMA (DMA channel %d)\n", - dev->name, TX_DMA); - ret=-EAGAIN; - goto dma1_fail; - } - - if(request_dma(RX_DMA,"LoCOMX (RX)")) { - printk(KERN_ERR "%s: unable to obtain RX DMA (DMA channel %d)\n", - dev->name, RX_DMA); - ret=-EAGAIN; - goto dma2_fail; - } - - save_flags(flags); - cli(); - - if(z8530_init(&hw->board)!=0) - { - printk(KERN_ERR "%s: Z8530 device not found.\n",dev->name); - ret=-ENODEV; - goto z8530_fail; - } - - hw->board.chanA.dcdcheck=CTS; - - z8530_channel_load(&hw->board.chanA, z8530_hdlc_kilostream_85230); - z8530_channel_load(&hw->board.chanA, z8530_locomx); - z8530_channel_load(&hw->board.chanB, z8530_dead_port); - - z8530_describe(&hw->board, "I/O", dev->base_addr); - - if((ret=z8530_sync_dma_open(dev, &hw->board.chanA))!=0) { - goto z8530_fail; - } - - restore_flags(flags); - - - hw->board.active=1; - hw->board.chanA.rx_function=locomx_rx; - - ch->init_status |= HW_OPEN; - if (hw->board.chanA.status & DCD) { - ch->line_status |= LINE_UP; - } else { - ch->line_status &= ~LINE_UP; - } - - comx_status(dev, ch->line_status); - - init_timer(&hw->status_timer); - hw->status_timer.function=locomx_status_timerfun; - hw->status_timer.data=(unsigned long)dev; - hw->status_timer.expires=jiffies + ch->lineup_delay * HZ; - add_timer(&hw->status_timer); - - for (; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IO) == 0 || - strcmp(procfile->name, FILENAME_IRQ) == 0) { - procfile->mode = S_IFREG | 0444; - } - } - return 0; - -z8530_fail: - restore_flags(flags); - free_dma(RX_DMA); -dma2_fail: - free_dma(TX_DMA); -dma1_fail: - free_irq(dev->irq, &hw->board); -irq_fail: - release_region(dev->base_addr, hw->io_extent); - return ret; -} - -static int LOCOMX_close(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - - hw->board.chanA.rx_function=z8530_null_rx; - netif_stop_queue(dev); - z8530_sync_dma_close(dev, &hw->board.chanA); - - z8530_shutdown(&hw->board); - - del_timer(&hw->status_timer); - free_dma(RX_DMA); - free_dma(TX_DMA); - free_irq(dev->irq,&hw->board); - release_region(dev->base_addr,8); - - for (; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IO) == 0 || - strcmp(procfile->name, FILENAME_IRQ) == 0) { - procfile->mode = S_IFREG | 0644; - } - } - - ch->init_status &= ~HW_OPEN; - return 0; -} - -static int LOCOMX_statistics(struct net_device *dev,char *page) -{ - int len = 0; - - len += sprintf(page + len, "Hello\n"); - - return len; -} - -static int LOCOMX_dump(struct net_device *dev) { - printk(KERN_INFO "LOCOMX_dump called\n"); - return(-1); -} - -static int locomx_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - int len = 0; - - if (strcmp(file->name, FILENAME_IO) == 0) { - len = sprintf(page, "0x%x\n", (unsigned int)dev->base_addr); - } else if (strcmp(file->name, FILENAME_IRQ) == 0) { - len = sprintf(page, "%d\n", (unsigned int)dev->irq); - } else { - printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", - file->name); - return -EBADF; - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) { - *eof = 1; - } - return min_t(int, count, len - off); -} - -static int locomx_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = (struct net_device *)entry->parent->data; - int val; - char *page; - - if (!(page = (char *)__get_free_page(GFP_KERNEL))) { - return -ENOMEM; - } - - if (copy_from_user(page, buffer, count = min_t(unsigned long, count, PAGE_SIZE))) { - free_page((unsigned long)page); - return -EBADF; - } - if (*(page + count - 1) == '\n') { - *(page + count - 1) = 0; - } - - if (strcmp(entry->name, FILENAME_IO) == 0) { - val = simple_strtoul(page, NULL, 0); - if (val != 0x360 && val != 0x368 && val != 0x370 && - val != 0x378) { - printk(KERN_ERR "LoCOMX: incorrect io address!\n"); - } else { - dev->base_addr = val; - } - } else if (strcmp(entry->name, FILENAME_IRQ) == 0) { - val = simple_strtoul(page, NULL, 0); - if (val != 3 && val != 4 && val != 5 && val != 6 && val != 7) { - printk(KERN_ERR "LoCOMX: incorrect irq value!\n"); - } else { - dev->irq = val; - } - } else { - printk(KERN_ERR "locomx_write_proc: internal error, filename %s\n", - entry->name); - free_page((unsigned long)page); - return -EBADF; - } - - free_page((unsigned long)page); - return count; -} - - - -static int LOCOMX_init(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct locomx_data *hw; - struct proc_dir_entry *new_file; - - /* Alloc data for private structure */ - if ((ch->HW_privdata = kmalloc(sizeof(struct locomx_data), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - memset(hw = ch->HW_privdata, 0, sizeof(struct locomx_data)); - hw->io_extent = LOCOMX_IO_EXTENT; - - /* Register /proc files */ - if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_HW_privdata; - } - new_file->data = (void *)new_file; - new_file->read_proc = &locomx_read_proc; - new_file->write_proc = &locomx_write_proc; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_io; - } - new_file->data = (void *)new_file; - new_file->read_proc = &locomx_read_proc; - new_file->write_proc = &locomx_write_proc; - new_file->nlink = 1; - -/* No clock yet */ -/* - if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, - ch->procdir)) == NULL) { - return -EIO; - } - new_file->data = (void *)new_file; - new_file->read_proc = &locomx_read_proc; - new_file->write_proc = &locomx_write_proc; - new_file->nlink = 1; -*/ - - ch->HW_access_board = NULL; - ch->HW_release_board = NULL; - ch->HW_txe = LOCOMX_txe; - ch->HW_open = LOCOMX_open; - ch->HW_close = LOCOMX_close; - ch->HW_send_packet = LOCOMX_send_packet; - ch->HW_statistics = LOCOMX_statistics; - ch->HW_set_clock = NULL; - - ch->current_stats = &hw->board.chanA.stats; - memcpy(ch->current_stats, &ch->stats, sizeof(struct net_device_stats)); - - dev->base_addr = LOCOMX_DEFAULT_IO; - dev->irq = LOCOMX_DEFAULT_IRQ; - - - /* O.K. Count one more user on this module */ - MOD_INC_USE_COUNT; - return 0; -cleanup_filename_io: - remove_proc_entry(FILENAME_IO, ch->procdir); -cleanup_HW_privdata: - kfree(ch->HW_privdata); - return -EIO; -} - - -static int LOCOMX_exit(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - - ch->HW_access_board = NULL; - ch->HW_release_board = NULL; - ch->HW_txe = NULL; - ch->HW_open = NULL; - ch->HW_close = NULL; - ch->HW_send_packet = NULL; - ch->HW_statistics = NULL; - ch->HW_set_clock = NULL; - memcpy(&ch->stats, ch->current_stats, sizeof(struct net_device_stats)); - ch->current_stats = &ch->stats; - - kfree(ch->HW_privdata); - - remove_proc_entry(FILENAME_IO, ch->procdir); - remove_proc_entry(FILENAME_IRQ, ch->procdir); -// remove_proc_entry(FILENAME_CLOCK, ch->procdir); - - MOD_DEC_USE_COUNT; - return 0; -} - -static struct comx_hardware locomx_hw = { - "locomx", - VERSION, - LOCOMX_init, - LOCOMX_exit, - LOCOMX_dump, - NULL -}; - -static int __init comx_hw_locomx_init(void) -{ - comx_register_hardware(&locomx_hw); - return 0; -} - -static void __exit comx_hw_locomx_exit(void) -{ - comx_unregister_hardware("locomx"); -} - -module_init(comx_hw_locomx_init); -module_exit(comx_hw_locomx_exit); diff --git a/drivers/net/wan/comx-hw-mixcom.c b/drivers/net/wan/comx-hw-mixcom.c deleted file mode 100644 index c6fb9ac67..000000000 --- a/drivers/net/wan/comx-hw-mixcom.c +++ /dev/null @@ -1,960 +0,0 @@ -/* - * Hardware driver for the MixCom synchronous serial board - * - * Author: Gergely Madarasz - * - * based on skeleton driver code and a preliminary hscx driver by - * Tivadar Szemethy - * - * Copyright (C) 1998-1999 ITConsult-Pro Co. - * - * Contributors: - * Arnaldo Carvalho de Melo (0.65) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.60 (99/06/11): - * - ported to the kernel, now works as builtin code - * - * Version 0.61 (99/06/11): - * - recognize the one-channel MixCOM card (id byte = 0x13) - * - printk fixes - * - * Version 0.62 (99/07/15): - * - fixes according to the new hw docs - * - report line status when open - * - * Version 0.63 (99/09/21): - * - line status report fixes - * - * Version 0.64 (99/12/01): - * - some more cosmetical fixes - * - * Version 0.65 (00/08/15) - * - resource release on failure at MIXCOM_init - */ - -#define VERSION "0.65" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "comx.h" -#include "mixcom.h" -#include "hscx.h" - -MODULE_AUTHOR("Gergely Madarasz "); -MODULE_DESCRIPTION("Hardware-level driver for the serial port of the MixCom board"); -MODULE_LICENSE("GPL"); - -#define MIXCOM_DATA(d) ((struct mixcom_privdata *)(COMX_CHANNEL(d)-> \ - HW_privdata)) - -#define MIXCOM_BOARD_BASE(d) (d->base_addr - MIXCOM_SERIAL_OFFSET - \ - (1 - MIXCOM_DATA(d)->channel) * MIXCOM_CHANNEL_OFFSET) - -#define MIXCOM_DEV_BASE(port,channel) (port + MIXCOM_SERIAL_OFFSET + \ - (1 - channel) * MIXCOM_CHANNEL_OFFSET) - -/* Values used to set the IRQ line */ -static unsigned char mixcom_set_irq[]={0xFF, 0xFF, 0xFF, 0x0, 0xFF, 0x2, 0x4, 0x6, 0xFF, 0xFF, 0x8, 0xA, 0xC, 0xFF, 0xE, 0xFF}; - -static unsigned char* hscx_versions[]={"A1", NULL, "A2", NULL, "A3", "2.1"}; - -struct mixcom_privdata { - u16 clock; - char channel; - long txbusy; - struct sk_buff *sending; - unsigned tx_ptr; - struct sk_buff *recving; - unsigned rx_ptr; - unsigned char status; - char card_has_status; -}; - -static inline void wr_hscx(struct net_device *dev, int reg, unsigned char val) -{ - outb(val, dev->base_addr + reg); -} - -static inline unsigned char rd_hscx(struct net_device *dev, int reg) -{ - return inb(dev->base_addr + reg); -} - -static inline void hscx_cmd(struct net_device *dev, int cmd) -{ - unsigned long jiffs = jiffies; - unsigned char cec; - unsigned delay = 0; - - while ((cec = (rd_hscx(dev, HSCX_STAR) & HSCX_CEC) != 0) && - time_before(jiffies, jiffs + HZ)) { - udelay(1); - if (++delay > (100000 / HZ)) break; - } - if (cec) { - printk(KERN_WARNING "%s: CEC stuck, probably no clock!\n",dev->name); - } else { - wr_hscx(dev, HSCX_CMDR, cmd); - } -} - -static inline void hscx_fill_fifo(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - register word to_send = hw->sending->len - hw->tx_ptr; - - - outsb(dev->base_addr + HSCX_FIFO, - &(hw->sending->data[hw->tx_ptr]), min_t(unsigned int, to_send, 32)); - if (to_send <= 32) { - hscx_cmd(dev, HSCX_XTF | HSCX_XME); - kfree_skb(hw->sending); - hw->sending = NULL; - hw->tx_ptr = 0; - } else { - hscx_cmd(dev, HSCX_XTF); - hw->tx_ptr += 32; - } -} - -static inline void hscx_empty_fifo(struct net_device *dev, int cnt) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - - if (hw->recving == NULL) { - if (!(hw->recving = dev_alloc_skb(HSCX_MTU + 16))) { - ch->stats.rx_dropped++; - hscx_cmd(dev, HSCX_RHR); - } else { - skb_reserve(hw->recving, 16); - skb_put(hw->recving, HSCX_MTU); - } - hw->rx_ptr = 0; - } - if (cnt > 32 || !cnt || hw->recving == NULL) { - printk(KERN_ERR "hscx_empty_fifo: cnt is %d, hw->recving %p\n", - cnt, (void *)hw->recving); - return; - } - - insb(dev->base_addr + HSCX_FIFO, &(hw->recving->data[hw->rx_ptr]),cnt); - hw->rx_ptr += cnt; - hscx_cmd(dev, HSCX_RMC); -} - - -static int MIXCOM_txe(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - - return !test_bit(0, &hw->txbusy); -} - -static int mixcom_probe(struct net_device *dev) -{ - unsigned long flags; - int id, vstr, ret=0; - - save_flags(flags); cli(); - - id=inb_p(MIXCOM_BOARD_BASE(dev) + MIXCOM_ID_OFFSET) & 0x7f; - - if (id != MIXCOM_ID ) { - ret=-ENODEV; - printk(KERN_WARNING "%s: no MixCOM board found at 0x%04lx\n",dev->name, dev->base_addr); - goto out; - } - - vstr=inb_p(dev->base_addr + HSCX_VSTR) & 0x0f; - if(vstr>=sizeof(hscx_versions)/sizeof(char*) || - hscx_versions[vstr]==NULL) { - printk(KERN_WARNING "%s: board found but no HSCX chip detected at 0x%4lx (vstr = 0x%1x)\n",dev->name,dev->base_addr,vstr); - ret = -ENODEV; - } else { - printk(KERN_INFO "%s: HSCX chip version %s\n",dev->name,hscx_versions[vstr]); - ret = 0; - } - -out: - - restore_flags(flags); - return ret; -} - -#if 0 -static void MIXCOM_set_clock(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - - if (hw->clock) { - ; - } else { - ; - } -} -#endif - -static void mixcom_board_on(struct net_device *dev) -{ - outb_p(MIXCOM_OFF , MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET); - udelay(1000); - outb_p(mixcom_set_irq[dev->irq] | MIXCOM_ON, - MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET); - udelay(1000); -} - -static void mixcom_board_off(struct net_device *dev) -{ - outb_p(MIXCOM_OFF , MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET); - udelay(1000); -} - -static void mixcom_off(struct net_device *dev) -{ - wr_hscx(dev, HSCX_CCR1, 0x0); -} - -static void mixcom_on(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - wr_hscx(dev, HSCX_CCR1, HSCX_PU | HSCX_ODS | HSCX_ITF); // power up, push-pull - wr_hscx(dev, HSCX_CCR2, HSCX_CIE /* | HSCX_RIE */ ); - wr_hscx(dev, HSCX_MODE, HSCX_TRANS | HSCX_ADM8 | HSCX_RAC | HSCX_RTS ); - wr_hscx(dev, HSCX_RLCR, HSCX_RC | 47); // 1504 bytes - wr_hscx(dev, HSCX_MASK, HSCX_RSC | HSCX_TIN ); - hscx_cmd(dev, HSCX_XRES | HSCX_RHR); - - if (ch->HW_set_clock) ch->HW_set_clock(dev); - -} - -static int MIXCOM_send_packet(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - unsigned long flags; - - if (ch->debug_flags & DEBUG_HW_TX) { - comx_debug_bytes(dev, skb->data, skb->len, "MIXCOM_send_packet"); - } - - if (!(ch->line_status & LINE_UP)) { - return FRAME_DROPPED; - } - - if (skb->len > HSCX_MTU) { - ch->stats.tx_errors++; - return FRAME_ERROR; - } - - save_flags(flags); cli(); - - if (test_and_set_bit(0, &hw->txbusy)) { - printk(KERN_ERR "%s: transmitter called while busy... dropping frame (length %d)\n", dev->name, skb->len); - restore_flags(flags); - return FRAME_DROPPED; - } - - - hw->sending = skb; - hw->tx_ptr = 0; - hw->txbusy = 1; -// atomic_inc(&skb->users); // save it - hscx_fill_fifo(dev); - restore_flags(flags); - - ch->stats.tx_packets++; - ch->stats.tx_bytes += skb->len; - - if (ch->debug_flags & DEBUG_HW_TX) { - comx_debug(dev, "MIXCOM_send_packet was successful\n\n"); - } - - return FRAME_ACCEPTED; -} - -static inline void mixcom_receive_frame(struct net_device *dev) -{ - struct comx_channel *ch=dev->priv; - struct mixcom_privdata *hw=ch->HW_privdata; - register byte rsta; - register word length; - - rsta = rd_hscx(dev, HSCX_RSTA) & (HSCX_VFR | HSCX_RDO | - HSCX_CRC | HSCX_RAB); - length = ((rd_hscx(dev, HSCX_RBCH) & 0x0f) << 8) | - rd_hscx(dev, HSCX_RBCL); - - if ( length > hw->rx_ptr ) { - hscx_empty_fifo(dev, length - hw->rx_ptr); - } - - if (!(rsta & HSCX_VFR)) { - ch->stats.rx_length_errors++; - } - if (rsta & HSCX_RDO) { - ch->stats.rx_over_errors++; - } - if (!(rsta & HSCX_CRC)) { - ch->stats.rx_crc_errors++; - } - if (rsta & HSCX_RAB) { - ch->stats.rx_frame_errors++; - } - ch->stats.rx_packets++; - ch->stats.rx_bytes += length; - - if (rsta == (HSCX_VFR | HSCX_CRC) && hw->recving) { - skb_trim(hw->recving, hw->rx_ptr - 1); - if (ch->debug_flags & DEBUG_HW_RX) { - comx_debug_skb(dev, hw->recving, - "MIXCOM_interrupt receiving"); - } - hw->recving->dev = dev; - if (ch->LINE_rx) { - ch->LINE_rx(dev, hw->recving); - } - } - else if(hw->recving) { - kfree_skb(hw->recving); - } - hw->recving = NULL; - hw->rx_ptr = 0; -} - - -static inline void mixcom_extended_interrupt(struct net_device *dev) -{ - struct comx_channel *ch=dev->priv; - struct mixcom_privdata *hw=ch->HW_privdata; - register byte exir; - - exir = rd_hscx(dev, HSCX_EXIR) & (HSCX_XDU | HSCX_RFO | HSCX_CSC ); - - if (exir & HSCX_RFO) { - ch->stats.rx_over_errors++; - if (hw->rx_ptr) { - kfree_skb(hw->recving); - hw->recving = NULL; hw->rx_ptr = 0; - } - printk(KERN_ERR "MIXCOM: rx overrun\n"); - hscx_cmd(dev, HSCX_RHR); - } - - if (exir & HSCX_XDU) { // xmit underrun - ch->stats.tx_errors++; - ch->stats.tx_aborted_errors++; - if (hw->tx_ptr) { - kfree_skb(hw->sending); - hw->sending = NULL; - hw->tx_ptr = 0; - } - hscx_cmd(dev, HSCX_XRES); - clear_bit(0, &hw->txbusy); - if (ch->LINE_tx) { - ch->LINE_tx(dev); - } - printk(KERN_ERR "MIXCOM: tx underrun\n"); - } - - if (exir & HSCX_CSC) { - ch->stats.tx_carrier_errors++; - if ((rd_hscx(dev, HSCX_STAR) & HSCX_CTS) == 0) { // Vonal le - if (test_and_clear_bit(0, &ch->lineup_pending)) { - del_timer(&ch->lineup_timer); - } else if (ch->line_status & LINE_UP) { - ch->line_status &= ~LINE_UP; - if (ch->LINE_status) { - ch->LINE_status(dev,ch->line_status); - } - } - } - if (!(ch->line_status & LINE_UP) && (rd_hscx(dev, HSCX_STAR) & - HSCX_CTS)) { // Vonal fol - if (!test_and_set_bit(0,&ch->lineup_pending)) { - ch->lineup_timer.function = comx_lineup_func; - ch->lineup_timer.data = (unsigned long)dev; - ch->lineup_timer.expires = jiffies + HZ * - ch->lineup_delay; - add_timer(&ch->lineup_timer); - hscx_cmd(dev, HSCX_XRES); - clear_bit(0, &hw->txbusy); - if (hw->sending) { - kfree_skb(hw->sending); - } - hw->sending=NULL; - hw->tx_ptr = 0; - } - } - } -} - - -static irqreturn_t MIXCOM_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - struct net_device *dev = (struct net_device *)dev_id; - struct comx_channel *ch, *twin_ch; - struct mixcom_privdata *hw, *twin_hw; - register unsigned char ista; - - if (dev==NULL) { - printk(KERN_ERR "comx_interrupt: irq %d for unknown device\n",irq); - return IRQ_NONE; - } - - ch = dev->priv; - hw = ch->HW_privdata; - - save_flags(flags); cli(); - - while((ista = (rd_hscx(dev, HSCX_ISTA) & (HSCX_RME | HSCX_RPF | - HSCX_XPR | HSCX_EXB | HSCX_EXA | HSCX_ICA)))) { - register byte ista2 = 0; - - if (ista & HSCX_RME) { - mixcom_receive_frame(dev); - } - if (ista & HSCX_RPF) { - hscx_empty_fifo(dev, 32); - } - if (ista & HSCX_XPR) { - if (hw->tx_ptr) { - hscx_fill_fifo(dev); - } else { - clear_bit(0, &hw->txbusy); - ch->LINE_tx(dev); - } - } - - if (ista & HSCX_EXB) { - mixcom_extended_interrupt(dev); - } - - if ((ista & HSCX_EXA) && ch->twin) { - mixcom_extended_interrupt(ch->twin); - } - - if ((ista & HSCX_ICA) && ch->twin && - (ista2 = rd_hscx(ch->twin, HSCX_ISTA) & - (HSCX_RME | HSCX_RPF | HSCX_XPR ))) { - if (ista2 & HSCX_RME) { - mixcom_receive_frame(ch->twin); - } - if (ista2 & HSCX_RPF) { - hscx_empty_fifo(ch->twin, 32); - } - if (ista2 & HSCX_XPR) { - twin_ch=ch->twin->priv; - twin_hw=twin_ch->HW_privdata; - if (twin_hw->tx_ptr) { - hscx_fill_fifo(ch->twin); - } else { - clear_bit(0, &twin_hw->txbusy); - ch->LINE_tx(ch->twin); - } - } - } - } - - restore_flags(flags); - return IRQ_HANDLED; -} - -static int MIXCOM_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - unsigned long flags; - int ret = -ENODEV; - - if (!dev->base_addr || !dev->irq) - goto err_ret; - - - if(hw->channel==1) { - if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status & - IRQ_ALLOCATED)) { - printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name); - ret = -EAGAIN; - goto err_ret; - } - } - - - /* Is our hw present at all ? Not checking for channel 0 if it is already - open */ - if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) { - if (!request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name)) { - ret = -EAGAIN; - goto err_ret; - } - if (mixcom_probe(dev)) { - ret = -ENODEV; - goto err_release_region; - } - } - - if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) { - if (request_irq(dev->irq, MIXCOM_interrupt, 0, - dev->name, (void *)dev)) { - printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq); - ret = -EAGAIN; - goto err_release_region; - } - } - - save_flags(flags); cli(); - - if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) { - ch->init_status|=IRQ_ALLOCATED; - mixcom_board_on(dev); - } - - mixcom_on(dev); - - - hw->status=inb(MIXCOM_BOARD_BASE(dev) + MIXCOM_STATUS_OFFSET); - if(hw->status != 0xff) { - printk(KERN_DEBUG "%s: board has status register, good\n", dev->name); - hw->card_has_status=1; - } - - hw->txbusy = 0; - ch->init_status |= HW_OPEN; - - if (rd_hscx(dev, HSCX_STAR) & HSCX_CTS) { - ch->line_status |= LINE_UP; - } else { - ch->line_status &= ~LINE_UP; - } - - restore_flags(flags); - - ch->LINE_status(dev, ch->line_status); - - for (; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IO) == 0 || - strcmp(procfile->name, FILENAME_CHANNEL) == 0 || - strcmp(procfile->name, FILENAME_CLOCK) == 0 || - strcmp(procfile->name, FILENAME_IRQ) == 0) { - procfile->mode = S_IFREG | 0444; - } - } - - return 0; - -err_release_region: - release_region(dev->base_addr, MIXCOM_IO_EXTENT); -err_ret: - return ret; -} - -static int MIXCOM_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - unsigned long flags; - - - save_flags(flags); cli(); - - mixcom_off(dev); - - /* This is channel 0, twin is not open, we can safely turn off everything */ - if(hw->channel==0 && (!(TWIN(dev)) || - !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN))) { - mixcom_board_off(dev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, MIXCOM_IO_EXTENT); - ch->init_status &= ~IRQ_ALLOCATED; - } - - /* This is channel 1, channel 0 has already been shutdown, we can release - this one too */ - if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) { - if(COMX_CHANNEL(TWIN(dev))->init_status & IRQ_ALLOCATED) { - mixcom_board_off(TWIN(dev)); - free_irq(TWIN(dev)->irq, TWIN(dev)); - release_region(TWIN(dev)->base_addr, MIXCOM_IO_EXTENT); - COMX_CHANNEL(TWIN(dev))->init_status &= ~IRQ_ALLOCATED; - } - } - - /* the ioports for channel 1 can be safely released */ - if(hw->channel==1) { - release_region(dev->base_addr, MIXCOM_IO_EXTENT); - } - - restore_flags(flags); - - /* If we don't hold any hardware open */ - if(!(ch->init_status & IRQ_ALLOCATED)) { - for (; procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IO) == 0 || - strcmp(procfile->name, FILENAME_CHANNEL) == 0 || - strcmp(procfile->name, FILENAME_CLOCK) == 0 || - strcmp(procfile->name, FILENAME_IRQ) == 0) { - procfile->mode = S_IFREG | 0644; - } - } - } - - /* channel 0 was only waiting for us to close channel 1 - close it completely */ - - if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) { - for (procfile=COMX_CHANNEL(TWIN(dev))->procdir->subdir; - procfile ; procfile = procfile->next) { - if (strcmp(procfile->name, FILENAME_IO) == 0 || - strcmp(procfile->name, FILENAME_CHANNEL) == 0 || - strcmp(procfile->name, FILENAME_CLOCK) == 0 || - strcmp(procfile->name, FILENAME_IRQ) == 0) { - procfile->mode = S_IFREG | 0644; - } - } - } - - ch->init_status &= ~HW_OPEN; - return 0; -} - -static int MIXCOM_statistics(struct net_device *dev,char *page) -{ - struct comx_channel *ch = dev->priv; - // struct mixcom_privdata *hw = ch->HW_privdata; - int len = 0; - - if(ch->init_status && IRQ_ALLOCATED) { - len += sprintf(page + len, "Mixcom board: hardware open\n"); - } - - return len; -} - -static int MIXCOM_dump(struct net_device *dev) { - return 0; -} - -static int mixcom_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - int len = 0; - - if (strcmp(file->name, FILENAME_IO) == 0) { - len = sprintf(page, "0x%x\n", - (unsigned int)MIXCOM_BOARD_BASE(dev)); - } else if (strcmp(file->name, FILENAME_IRQ) == 0) { - len = sprintf(page, "%d\n", (unsigned int)dev->irq); - } else if (strcmp(file->name, FILENAME_CLOCK) == 0) { - if (hw->clock) len = sprintf(page, "%d\n", hw->clock); - else len = sprintf(page, "external\n"); - } else if (strcmp(file->name, FILENAME_CHANNEL) == 0) { - len = sprintf(page, "%01d\n", hw->channel); - } else if (strcmp(file->name, FILENAME_TWIN) == 0) { - if (ch->twin) { - len = sprintf(page, "%s\n",ch->twin->name); - } else { - len = sprintf(page, "none\n"); - } - } else { - printk(KERN_ERR "mixcom_read_proc: internal error, filename %s\n", file->name); - return -EBADF; - } - - if (off >= len) { - *eof = 1; - return 0; - } - *start = page + off; - if (count >= len - off) *eof = 1; - return min_t(int, count, len - off); -} - - -static struct net_device *mixcom_twin_check(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *procfile = ch->procdir->parent->subdir; - struct mixcom_privdata *hw = ch->HW_privdata; - - struct net_device *twin; - struct comx_channel *ch_twin; - struct mixcom_privdata *hw_twin; - - - for ( ; procfile ; procfile = procfile->next) { - if(!S_ISDIR(procfile->mode)) continue; - - twin = procfile->data; - ch_twin = twin->priv; - hw_twin = ch_twin->HW_privdata; - - - if (twin != dev && dev->irq && dev->base_addr && - dev->irq == twin->irq && - ch->hardware == ch_twin->hardware && - dev->base_addr == twin->base_addr + - (1-2*hw->channel)*MIXCOM_CHANNEL_OFFSET && - hw->channel == (1 - hw_twin->channel)) { - if (!TWIN(twin) || TWIN(twin)==dev) { - return twin; - } - } - } - return NULL; -} - - -static void setup_twin(struct net_device* dev) -{ - - if(TWIN(dev) && TWIN(TWIN(dev))) { - TWIN(TWIN(dev))=NULL; - } - if ((TWIN(dev) = mixcom_twin_check(dev)) != NULL) { - if (TWIN(TWIN(dev)) && TWIN(TWIN(dev)) != dev) { - TWIN(dev)=NULL; - } else { - TWIN(TWIN(dev))=dev; - } - } -} - -static int mixcom_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - char *page; - int value; - - if (!(page = (char *)__get_free_page(GFP_KERNEL))) { - return -ENOMEM; - } - - if (copy_from_user(page, buffer, count = min_t(unsigned long, count, PAGE_SIZE))) { - free_page((unsigned long)page); - return -EFAULT; - } - if (*(page + count - 1) == '\n') { - *(page + count - 1) = 0; - } - - if (strcmp(entry->name, FILENAME_IO) == 0) { - value = simple_strtoul(page, NULL, 0); - if (value != 0x180 && value != 0x280 && value != 0x380) { - printk(KERN_ERR "MIXCOM: incorrect io address!\n"); - } else { - dev->base_addr = MIXCOM_DEV_BASE(value,hw->channel); - } - } else if (strcmp(entry->name, FILENAME_IRQ) == 0) { - value = simple_strtoul(page, NULL, 0); - if (value < 0 || value > 15 || mixcom_set_irq[value]==0xFF) { - printk(KERN_ERR "MIXCOM: incorrect irq value!\n"); - } else { - dev->irq = value; - } - } else if (strcmp(entry->name, FILENAME_CLOCK) == 0) { - if (strncmp("ext", page, 3) == 0) { - hw->clock = 0; - } else { - int kbps; - - kbps = simple_strtoul(page, NULL, 0); - if (!kbps) { - hw->clock = 0; - } else { - hw->clock = kbps; - } - if (hw->clock < 32 || hw->clock > 2000) { - hw->clock = 0; - printk(KERN_ERR "MIXCOM: invalid clock rate!\n"); - } - } - if (ch->init_status & HW_OPEN && ch->HW_set_clock) { - ch->HW_set_clock(dev); - } - } else if (strcmp(entry->name, FILENAME_CHANNEL) == 0) { - value = simple_strtoul(page, NULL, 0); - if (value > 2) { - printk(KERN_ERR "Invalid channel number\n"); - } else { - dev->base_addr+=(hw->channel - value) * MIXCOM_CHANNEL_OFFSET; - hw->channel = value; - } - } else { - printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", - entry->name); - return -EBADF; - } - - setup_twin(dev); - - free_page((unsigned long)page); - return count; -} - -static int MIXCOM_init(struct net_device *dev) { - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw; - struct proc_dir_entry *new_file; - - if ((ch->HW_privdata = kmalloc(sizeof(struct mixcom_privdata), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - memset(hw = ch->HW_privdata, 0, sizeof(struct mixcom_privdata)); - - if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_HW_privdata; - } - new_file->data = (void *)new_file; - new_file->read_proc = &mixcom_read_proc; - new_file->write_proc = &mixcom_write_proc; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_io; - } - new_file->data = (void *)new_file; - new_file->read_proc = &mixcom_read_proc; - new_file->write_proc = &mixcom_write_proc; - new_file->nlink = 1; - -#if 0 - if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, - ch->procdir)) == NULL) { - return -EIO; - } - new_file->data = (void *)new_file; - new_file->read_proc = &mixcom_read_proc; - new_file->write_proc = &mixcom_write_proc; - new_file->nlink = 1; -#endif - - if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_irq; - } - new_file->data = (void *)new_file; - new_file->read_proc = &mixcom_read_proc; - new_file->write_proc = &mixcom_write_proc; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, - ch->procdir)) == NULL) { - goto cleanup_filename_channel; - } - new_file->data = (void *)new_file; - new_file->read_proc = &mixcom_read_proc; - new_file->write_proc = &mixcom_write_proc; - new_file->nlink = 1; - - setup_twin(dev); - - /* Fill in ch_struct hw specific pointers */ - ch->HW_access_board = NULL; - ch->HW_release_board = NULL; - ch->HW_txe = MIXCOM_txe; - ch->HW_open = MIXCOM_open; - ch->HW_close = MIXCOM_close; - ch->HW_send_packet = MIXCOM_send_packet; - ch->HW_statistics = MIXCOM_statistics; - ch->HW_set_clock = NULL; - - dev->base_addr = MIXCOM_DEV_BASE(MIXCOM_DEFAULT_IO,0); - dev->irq = MIXCOM_DEFAULT_IRQ; - - MOD_INC_USE_COUNT; - return 0; -cleanup_filename_channel: - remove_proc_entry(FILENAME_CHANNEL, ch->procdir); -cleanup_filename_irq: - remove_proc_entry(FILENAME_IRQ, ch->procdir); -cleanup_filename_io: - remove_proc_entry(FILENAME_IO, ch->procdir); -cleanup_HW_privdata: - kfree(ch->HW_privdata); - return -EIO; -} - -static int MIXCOM_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct mixcom_privdata *hw = ch->HW_privdata; - - if(hw->channel==0 && TWIN(dev)) { - return -EBUSY; - } - - if(hw->channel==1 && TWIN(dev)) { - TWIN(TWIN(dev))=NULL; - } - - kfree(ch->HW_privdata); - remove_proc_entry(FILENAME_IO, ch->procdir); - remove_proc_entry(FILENAME_IRQ, ch->procdir); -#if 0 - remove_proc_entry(FILENAME_CLOCK, ch->procdir); -#endif - remove_proc_entry(FILENAME_CHANNEL, ch->procdir); - remove_proc_entry(FILENAME_TWIN, ch->procdir); - - MOD_DEC_USE_COUNT; - return 0; -} - -static struct comx_hardware mixcomhw = { - "mixcom", - VERSION, - MIXCOM_init, - MIXCOM_exit, - MIXCOM_dump, - NULL -}; - -static int __init comx_hw_mixcom_init(void) -{ - return comx_register_hardware(&mixcomhw); -} - -static void __exit comx_hw_mixcom_exit(void) -{ - comx_unregister_hardware("mixcom"); -} - -module_init(comx_hw_mixcom_init); -module_exit(comx_hw_mixcom_exit); diff --git a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c deleted file mode 100644 index 195bc2d25..000000000 --- a/drivers/net/wan/comx-hw-munich.c +++ /dev/null @@ -1,2854 +0,0 @@ -/* - * Hardware-level driver for the SliceCOM board for Linux kernels 2.4.X - * - * Current maintainer / latest changes: Pasztor Szilard - * - * Original author: Bartok Istvan - * Based on skeleton by Tivadar Szemethy - * - * 0.51: - * - port for 2.4.x - * - clean up some code, make it more portable - * - busted direct hardware access through mapped memory - * - fix a possible race - * - prevent procfs buffer overflow - * - * 0.50: - * - support for the pcicom board, lots of rearrangements - * - handle modem status lines - * - * 0.50a: - * - fix for falc version 1.0 - * - * 0.50b: T&t - * - fix for bad localbus - */ - -#define VERSION "0.51" -#define VERSIONSTR "SliceCOM v" VERSION ", 2002/01/07\n" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define COMX_NEW - -#ifndef COMX_NEW -#include "../include/comx.h" -#include "../include/munich32x.h" -#include "../include/falc-lh.h" -#else -#include "comx.h" -#include "munich32x.h" -#include "falc-lh.h" -#endif - -MODULE_AUTHOR("Bartok Istvan , Gergely Madarasz , Szilard Pasztor "); -MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters"); -MODULE_LICENSE("GPL"); -/* - * TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda: - */ - -#define FILENAME_BOARDNUM "boardnum" /* /proc/comx/comx0.1/boardnum */ -#define FILENAME_TIMESLOTS "timeslots" /* /proc/comx/comx0.1/timeslots */ -#define FILENAME_FRAMING "framing" /* /proc/comx/comx0.1/framing */ -#define FILENAME_LINECODE "linecode" /* /proc/comx/comx0.1/linecode */ -#define FILENAME_CLOCK_SOURCE "clock_source" /* /proc/comx/comx0.1/clock_source */ -#define FILENAME_LOOPBACK "loopback" /* /proc/comx/comx0.1/loopback */ -#define FILENAME_REG "reg" /* /proc/comx/comx0.1/reg */ -#define FILENAME_LBIREG "lbireg" /* /proc/comx/comx0.1/lbireg */ - -#define SLICECOM_BOARDNUM_DEFAULT 0 - -#define SLICECOM_FRAMING_CRC4 1 -#define SLICECOM_FRAMING_NO_CRC4 2 -#define SLICECOM_FRAMING_DEFAULT SLICECOM_FRAMING_CRC4 - -#define SLICECOM_LINECODE_HDB3 1 -#define SLICECOM_LINECODE_AMI 2 -#define SLICECOM_LINECODE_DEFAULT SLICECOM_LINECODE_HDB3 - -#define SLICECOM_CLOCK_SOURCE_LINE 1 -#define SLICECOM_CLOCK_SOURCE_INTERNAL 2 -#define SLICECOM_CLOCK_SOURCE_DEFAULT SLICECOM_CLOCK_SOURCE_LINE - -#define SLICECOM_LOOPBACK_NONE 1 -#define SLICECOM_LOOPBACK_LOCAL 2 -#define SLICECOM_LOOPBACK_REMOTE 3 -#define SLICECOM_LOOPBACK_DEFAULT SLICECOM_LOOPBACK_NONE - -#define MUNICH_VIRT(addr) (void *)(&bar1[addr]) - -struct slicecom_stringtable -{ - char *name; - int value; -}; - -/* A convention: keep "default" the last not NULL when reading from /proc, - "error" is an indication that something went wrong, we have an undefined value */ - -struct slicecom_stringtable slicecom_framings[] = -{ - {"crc4", SLICECOM_FRAMING_CRC4}, - {"no-crc4", SLICECOM_FRAMING_NO_CRC4}, - {"default", SLICECOM_FRAMING_DEFAULT}, - {"error", 0} -}; - -struct slicecom_stringtable slicecom_linecodes[] = -{ - {"hdb3", SLICECOM_LINECODE_HDB3}, - {"ami", SLICECOM_LINECODE_AMI}, - {"default", SLICECOM_LINECODE_DEFAULT}, - {"error", 0} -}; - -struct slicecom_stringtable slicecom_clock_sources[] = -{ - {"line", SLICECOM_CLOCK_SOURCE_LINE}, - {"internal", SLICECOM_CLOCK_SOURCE_INTERNAL}, - {"default", SLICECOM_CLOCK_SOURCE_DEFAULT}, - {"error", 0} -}; - -struct slicecom_stringtable slicecom_loopbacks[] = -{ - {"none", SLICECOM_LOOPBACK_NONE}, - {"local", SLICECOM_LOOPBACK_LOCAL}, - {"remote", SLICECOM_LOOPBACK_REMOTE}, - {"default", SLICECOM_LOOPBACK_DEFAULT}, - {"error", 0} -}; - -/* - * Some tunable values... - * - * Note: when tuning values which change the length of text in - * /proc/comx/comx[n]/status, keep in mind that it must be shorter then - * PAGESIZE ! - */ - -#define MAX_BOARDS 4 /* ezzel 4 kartya lehet a gepben: 0..3 */ -#define RX_DESC_MAX 8 /* Rx ring size, must be >= 4 */ -#define TX_DESC_MAX 4 /* Tx ring size, must be >= 2 */ - /* a sokkal hosszabb Tx ring mar ronthatja a nem-FIFO packet */ - /* schedulerek (fair queueing, stb.) hatekonysagat. */ -#define MAX_WORK 10 /* TOD: update the info max. ennyi-1 esemenyt dolgoz fel egy interrupt hivasnal */ - -/* - * These are tunable too, but don't touch them without fully understanding what is happening - */ - -#define UDELAY 20 /* We wait UDELAY usecs with disabled interrupts before and */ - /* after each command to avoid writing into each other's */ - /* ccb->action_spec. A _send_packet nem var, mert azt az */ - /* _interrupt()-bol is meghivhatja a LINE_tx() */ - -/* - * Just to avoid warnings about implicit declarations: - */ - -static int MUNICH_close(struct net_device *dev); -static struct comx_hardware slicecomhw; -static struct comx_hardware pcicomhw; - -static unsigned long flags; -static spinlock_t mister_lock = SPIN_LOCK_UNLOCKED; - -typedef volatile struct /* Time Slot Assignment */ -{ - u32 rxfillmask:8, // ----------------------------+------+ - // | | - rxchannel:5, // ----------------------+---+ | | - rti:1, // ---------------------+| | | | - res2:2, // -------------------++|| | | | - // |||| | | | - txfillmask:8, // ----------+------+ |||| | | | - // | | |||| | | | - txchannel:5, // ----+---+ | | |||| | | | - tti:1, // ---+| | | | |||| | | | - res1:2; // -++|| | | | |||| | | | - // 3 2 1 - // 10987654 32109876 54321098 76543210 -} timeslot_spec_t; - -typedef volatile struct /* Receive Descriptor */ -{ - u32 zero1:16, no:13, hi:1, hold:1, zero2:1; - - u32 next; - u32 data; - - u32 zero3:8, status:8, bno:13, zero4:1, c:1, fe:1; -} rx_desc_t; - -typedef volatile struct /* Transmit Descriptor */ -{ - u32 fnum:11, csm:1, no13:1, zero1:2, v110:1, no:13, hi:1, hold:1, fe:1; - - u32 next; - u32 data; - -} tx_desc_t; - -typedef volatile struct /* Channel Specification */ -{ - u32 iftf:1, mode:2, fa:1, trv:2, crc:1, inv:1, cs:1, tflag:7, ra:1, ro:1, - th:1, ta:1, to:1, ti:1, ri:1, nitbs:1, fit:1, fir:1, re:1, te:1, ch:1, - ifc:1, sfe:1, fe2:1; - - u32 frda; - u32 ftda; - - u32 itbs:6, zero1:26; - -} channel_spec_t; - -typedef volatile struct /* Configuration Control Block */ -{ - u32 action_spec; - u32 reserved1; - u32 reserved2; - timeslot_spec_t timeslot_spec[32]; - channel_spec_t channel_spec[32]; - u32 current_rx_desc[32]; - u32 current_tx_desc[32]; - u32 csa; /* Control Start Address. CSA = *CCBA; CCB = *CSA */ - /* MUNICH does it like: CCB = *( *CCBA ) */ -} munich_ccb_t; - -typedef volatile struct /* Entry in the interrupt queue */ -{ - u32 all; -} munich_intq_t; - -#define MUNICH_INTQLEN 63 /* Rx/Tx Interrupt Queue Length - (not the real len, but the TIQL/RIQL value) */ -#define MUNICH_INTQMAX ( 16*(MUNICH_INTQLEN+1) ) /* Rx/Tx/Periph Interrupt Queue size in munich_intq_t's */ -#define MUNICH_INTQSIZE ( 4*MUNICH_INTQMAX ) /* Rx/Tx/Periph Interrupt Queue size in bytes */ - -#define MUNICH_PIQLEN 4 /* Peripheral Interrupt Queue Length. Unlike the RIQL/TIQL, */ -#define MUNICH_PIQMAX ( 4*MUNICH_PIQLEN ) /* PIQL register needs it like this */ -#define MUNICH_PIQSIZE ( 4*MUNICH_PIQMAX ) - -typedef volatile u32 vol_u32; /* TOD: ezek megszunnek ha atirom readw()/writew()-re - kész */ -typedef volatile u8 vol_u8; - -typedef volatile struct /* counters of E1-errors and errored seconds, see rfc2495 */ -{ - /* use here only unsigned ints, we depend on it when calculating the sum for the last N intervals */ - - unsigned line_code_violations, /* AMI: bipolar violations, HDB3: hdb3 violations */ - path_code_violations, /* FAS errors and CRC4 errors */ - e_bit_errors, /* E-Bit Errors (the remote side received from us with CRC4-error) */ - slip_secs, /* number of seconds with (receive) Controlled Slip(s) */ - fr_loss_secs, /* number of seconds an Out Of Frame defect was detected */ - line_err_secs, /* number of seconds with one or more Line Code Violations */ - degraded_mins, /* Degraded Minute - the estimated error rate is >1E-6, but <1E-3 */ - errored_secs, /* Errored Second - at least one of these happened: - - Path Code Violation - - Out Of Frame defect - - Slip - - receiving AIS - - not incremented during an Unavailable Second */ - bursty_err_secs, /* Bursty Errored Second: (rfc2495 says it does not apply to E1) - - Path Code Violations >1, but <320 - - not a Severely Errored Second - - no AIS - - not incremented during an Unavailabla Second */ - severely_err_secs, /* Severely Errored Second: - - CRC4: >=832 Path COde Violations || >0 Out Of Frame defects - - noCRC4: >=2048 Line Code Violations - - not incremented during an Unavailable Second */ - unavail_secs; /* number of Unavailable Seconds. Unavailable state is said after: - - 10 contiguous Severely Errored Seconds - - or RAI || AIS || LOF || LOS - - (any) loopback has been set */ - - /* - * we do not strictly comply to the rfc: we do not retroactively reduce errored_secs, - * bursty_err_secs, severely_err_secs when 'unavailable state' is reached - */ - -} e1_stats_t; - -typedef volatile struct /* ezek board-adatok, nem lehetnek a slicecom_privdata -ban */ -{ - int use_count; /* num. of interfaces using the board */ - int irq; /* a kartya irq-ja. belemasoljuk a dev->irq -kba is, de csak hogy */ - /* szebb legyen az ifconfig outputja */ - /* ha != 0, az azt jelenti hogy az az irq most nekunk sikeresen */ - /* le van foglalva */ - struct pci_dev *pci; /* a kartya PCI strukturaja. NULL, ha nincs kartya */ - u32 *bar1; /* pci->base_address[0] ioremap()-ed by munich_probe(), */ - /* on x86 can be used both as a bus or virtual address. */ - /* These are the Munich's registers */ - u8 *lbi; /* pci->base_address[1] ioremap()-ed by munich_probe(), */ - /* this is a 256-byte range, the start of the LBI on the board */ - munich_ccb_t *ccb; /* virtual address of CCB */ - munich_intq_t *tiq; /* Tx Interrupt Queue */ - munich_intq_t *riq; /* Rx Interrupt Queue */ - munich_intq_t *piq; /* Peripheral Interrupt Queue (FALC interrupts arrive here) */ - int tiq_ptr, /* A 'current' helyek a tiq/riq/piq -ban. */ - riq_ptr, /* amikor feldolgoztam az interruptokat, a legelso ures */ - piq_ptr; /* interrupt_information szora mutatnak. */ - struct net_device *twins[32]; /* MUNICH channel -> network interface assignment */ - - unsigned long lastcheck; /* When were the Rx rings last checked. Time in jiffies */ - - struct timer_list modemline_timer; - char isx21; - char lineup; - char framing; /* a beallitasok tarolasa */ - char linecode; - char clock_source; - char loopback; - - char devname[30]; /* what to show in /proc/interrupts */ - unsigned histogram[MAX_WORK]; /* number of processed events in the interrupt loop */ - unsigned stat_pri_races; /* number of special events, we try to handle them */ - unsigned stat_pti_races; - unsigned stat_pri_races_missed; /* when it can not be handled, because of MAX_WORK */ - unsigned stat_pti_races_missed; - -#define SLICECOM_BOARD_INTERVALS_SIZE 97 - e1_stats_t intervals[SLICECOM_BOARD_INTERVALS_SIZE]; /* E1 line statistics */ - unsigned current_interval; /* pointer to the current interval */ - unsigned elapsed_seconds; /* elapsed seconds from the start of the current interval */ - unsigned ses_seconds; /* counter of contiguous Severely Errored Seconds */ - unsigned is_unavailable; /* set to 1 after 10 contiguous Severely Errored Seconds */ - unsigned no_ses_seconds; /* contiguous Severely Error -free seconds in unavail state */ - - unsigned deg_elapsed_seconds; /* for counting the 'Degraded Mins' */ - unsigned deg_cumulated_errors; - - struct module *owner; /* pointer to our module to avoid module load races */ -} munich_board_t; - -struct slicecom_privdata -{ - int busy; /* transmitter busy - number of packets in the Tx ring */ - int channel; /* Munich logical channel ('channel-group' in Cisco) */ - unsigned boardnum; - u32 timeslots; /* i-th bit means i-th timeslot is our */ - - int tx_ring_hist[TX_DESC_MAX]; /* histogram: number of packets in Tx ring when _send_packet is called */ - - tx_desc_t tx_desc[TX_DESC_MAX]; /* the ring of Tx descriptors */ - u8 tx_data[TX_DESC_MAX][TXBUFFER_SIZE]; /* buffers for data to transmit */ - int tx_desc_ptr; /* hanyadik descriptornal tartunk a beirassal */ - /* ahol ez all, oda irtunk utoljara */ - - rx_desc_t rx_desc[RX_DESC_MAX]; /* the ring of Rx descriptors */ - u8 rx_data[RX_DESC_MAX][RXBUFFER_SIZE]; /* buffers for received data */ - int rx_desc_ptr; /* hanyadik descriptornal tartunk az olvasassal */ - - int rafutott; -}; - -static u32 reg, reg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */ -static u32 lbireg; -static u8 lbireg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */ - -static munich_board_t slicecom_boards[MAX_BOARDS]; -static munich_board_t pcicom_boards[MAX_BOARDS]; - -/* - * Reprogram Idle Channel Registers in the FALC - send special code in not used channels - * Should be called from the open and close, when the timeslot assignment changes - */ - -void rework_idle_channels(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - munich_board_t *board = slicecom_boards + hw->boardnum; - munich_ccb_t *ccb = board->ccb; - - u8 *lbi = board->lbi; - int i, j, tmp; - - - spin_lock_irqsave(&mister_lock, flags); - - for (i = 0; i < 4; i++) - { - tmp = 0xFF; - for (j = 0; j < 8; j++) - if (ccb->timeslot_spec[8 * i + j].tti == 0) tmp ^= (0x80 >> j); - writeb(tmp, lbi + 0x30 + i); - } - - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * Set PCM framing - /proc/comx/comx0/framing - */ - -void slicecom_set_framing(int boardnum, int value) -{ - u8 *lbi = slicecom_boards[boardnum].lbi; - - spin_lock_irqsave(&mister_lock, flags); - - slicecom_boards[boardnum].framing = value; - switch (value) - { - case SLICECOM_FRAMING_CRC4: - writeb(readb(lbi + FMR1) | 8, lbi + FMR1); - writeb((readb(lbi + FMR2) & 0x3f) | 0x80, lbi + FMR2); - break; - case SLICECOM_FRAMING_NO_CRC4: - writeb(readb(lbi + FMR1) & 0xf7, lbi + FMR1); - writeb(readb(lbi + FMR2) & 0x3f, lbi + FMR2); - break; - default: - printk("slicecom: board %d: unhandled " FILENAME_FRAMING - " value %d\n", boardnum, value); - } - - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * Set PCM linecode - /proc/comx/comx0/linecode - */ - -void slicecom_set_linecode(int boardnum, int value) -{ - u8 *lbi = slicecom_boards[boardnum].lbi; - - spin_lock_irqsave(&mister_lock, flags); - - slicecom_boards[boardnum].linecode = value; - switch (value) - { - case SLICECOM_LINECODE_HDB3: - writeb(readb(lbi + FMR0) | 0xf0, lbi + FMR0); - break; - case SLICECOM_LINECODE_AMI: - writeb((readb(lbi + FMR0) & 0x0f) | 0xa0, lbi + FMR0); - break; - default: - printk("slicecom: board %d: unhandled " FILENAME_LINECODE - " value %d\n", boardnum, value); - } - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * Set PCM clock source - /proc/comx/comx0/clock_source - */ - -void slicecom_set_clock_source(int boardnum, int value) -{ - u8 *lbi = slicecom_boards[boardnum].lbi; - - spin_lock_irqsave(&mister_lock, flags); - - slicecom_boards[boardnum].clock_source = value; - switch (value) - { - case SLICECOM_CLOCK_SOURCE_LINE: - writeb(readb(lbi + LIM0) & ~1, lbi + LIM0); - break; - case SLICECOM_CLOCK_SOURCE_INTERNAL: - writeb(readb(lbi + LIM0) | 1, lbi + LIM0); - break; - default: - printk("slicecom: board %d: unhandled " FILENAME_CLOCK_SOURCE - " value %d\n", boardnum, value); - } - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * Set loopbacks - /proc/comx/comx0/loopback - */ - -void slicecom_set_loopback(int boardnum, int value) -{ - u8 *lbi = slicecom_boards[boardnum].lbi; - - spin_lock_irqsave(&mister_lock, flags); - - slicecom_boards[boardnum].loopback = value; - switch (value) - { - case SLICECOM_LOOPBACK_NONE: - writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */ - writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */ - break; - case SLICECOM_LOOPBACK_LOCAL: - writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */ - writeb(readb(lbi + LIM0) | 2, lbi + LIM0); /* Local Loop ON */ - break; - case SLICECOM_LOOPBACK_REMOTE: - writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */ - writeb(readb(lbi + LIM1) | 2, lbi + LIM1); /* Remote Loop ON */ - break; - default: - printk("slicecom: board %d: unhandled " FILENAME_LOOPBACK - " value %d\n", boardnum, value); - } - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * Update E1 line status LEDs on the adapter - */ - -void slicecom_update_leds(munich_board_t * board) -{ - u32 *bar1 = board->bar1; - u8 *lbi = board->lbi; - u8 frs0; - u32 leds; - int i; - - spin_lock_irqsave(&mister_lock, flags); - - leds = 0; - frs0 = readb(lbi + FRS0); /* FRS0 bits described on page 137 */ - - if (!(frs0 & 0xa0)) - { - leds |= 0x2000; /* Green LED: Input signal seems to be OK, no LOS, no LFA */ - if (frs0 & 0x10) - leds |= 0x8000; /* Red LED: Receiving Remote Alarm */ - } - writel(leds, MUNICH_VIRT(GPDATA)); - - if (leds == 0x2000 && !board->lineup) - { /* line up */ - board->lineup = 1; - for (i = 0; i < 32; i++) - { - if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING)) - { - struct comx_channel *ch = board->twins[i]->priv; - - if (!test_and_set_bit(0, &ch->lineup_pending)) - { - ch->lineup_timer.function = comx_lineup_func; - ch->lineup_timer.data = (unsigned long)board->twins[i]; - ch->lineup_timer.expires = jiffies + HZ * ch->lineup_delay; - add_timer(&ch->lineup_timer); - } - } - } - } - else if (leds != 0x2000 && board->lineup) - { /* line down */ - board->lineup = 0; - for (i = 0; i < 32; i++) - if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING)) - { - struct comx_channel *ch = board->twins[i]->priv; - - if (test_and_clear_bit(0, &ch->lineup_pending)) - del_timer(&ch->lineup_timer); - else if (ch->line_status & LINE_UP) - { - ch->line_status &= ~LINE_UP; - if (ch->LINE_status) - ch->LINE_status(board->twins[i], ch->line_status); - } - } - } - spin_unlock_irqrestore(&mister_lock, flags); -} - -/* - * This function gets called every second when the FALC issues the interrupt. - * Hardware counters contain error counts for last 1-second time interval. - * We add them to the global counters here. - * Read rfc2495 to understand this. - */ - -void slicecom_update_line_counters(munich_board_t * board) -{ - e1_stats_t *curr_int = &board->intervals[board->current_interval]; - - u8 *lbi = board->lbi; - - unsigned framing_errors, code_violations, path_code_violations, crc4_errors, - e_bit_errors; - unsigned slip_detected, /* this one has logical value, not the number of slips! */ - out_of_frame_defect, /* logical value */ - ais_defect, /* logical value */ - errored_sec, bursty_err_sec, severely_err_sec = 0, failure_sec; - u8 isr2, isr3, isr5, frs0; - - spin_lock_irqsave(&mister_lock, flags); - - isr2 = readb(lbi + ISR2); /* ISR0-5 described on page 156 */ - isr3 = readb(lbi + ISR3); - isr5 = readb(lbi + ISR5); - frs0 = readb(lbi + FRS0); /* FRS0 described on page 137 */ - - /* Error Events: */ - - code_violations = readb(lbi + CVCL) + (readb(lbi + CVCH) << 8); - framing_errors = readb(lbi + FECL) + (readb(lbi + FECH) << 8); - crc4_errors = readb(lbi + CEC1L) + (readb(lbi + CEC1H) << 8); - e_bit_errors = readb(lbi + EBCL) + (readb(lbi + EBCH) << 8); - slip_detected = isr3 & (ISR3_RSN | ISR3_RSP); - - path_code_violations = framing_errors + crc4_errors; - - curr_int->line_code_violations += code_violations; - curr_int->path_code_violations += path_code_violations; - curr_int->e_bit_errors += e_bit_errors; - - /* Performance Defects: */ - - /* there was an LFA in the last second, but maybe disappeared: */ - out_of_frame_defect = (isr2 & ISR2_LFA) || (frs0 & FRS0_LFA); - - /* there was an AIS in the last second, but maybe disappeared: */ - ais_defect = (isr2 & ISR2_AIS) || (frs0 & FRS0_AIS); - - /* Performance Parameters: */ - - if (out_of_frame_defect) - curr_int->fr_loss_secs++; - if (code_violations) - curr_int->line_err_secs++; - - errored_sec = ((board->framing == SLICECOM_FRAMING_NO_CRC4) && - (code_violations)) || path_code_violations || - out_of_frame_defect || slip_detected || ais_defect; - - bursty_err_sec = !out_of_frame_defect && !ais_defect && - (path_code_violations > 1) && (path_code_violations < 320); - - switch (board->framing) - { - case SLICECOM_FRAMING_CRC4: - severely_err_sec = out_of_frame_defect || - (path_code_violations >= 832); - break; - case SLICECOM_FRAMING_NO_CRC4: - severely_err_sec = (code_violations >= 2048); - break; - } - - /* - * failure_sec: true if there was a condition leading to a failure - * (and leading to unavailable state) in this second: - */ - - failure_sec = (isr2 & ISR2_RA) || (frs0 & FRS0_RRA) /* Remote/Far End/Distant Alarm Failure */ - || ais_defect || out_of_frame_defect /* AIS or LOF Failure */ - || (isr2 & ISR2_LOS) || (frs0 & FRS0_LOS) /* Loss Of Signal Failure */ - || (board->loopback != SLICECOM_LOOPBACK_NONE); /* Loopback has been set */ - - if (board->is_unavailable) - { - if (severely_err_sec) - board->no_ses_seconds = 0; - else - board->no_ses_seconds++; - - if ((board->no_ses_seconds >= 10) && !failure_sec) - { - board->is_unavailable = 0; - board->ses_seconds = 0; - board->no_ses_seconds = 0; - } - } - else - { - if (severely_err_sec) - board->ses_seconds++; - else - board->ses_seconds = 0; - - if ((board->ses_seconds >= 10) || failure_sec) - { - board->is_unavailable = 1; - board->ses_seconds = 0; - board->no_ses_seconds = 0; - } - } - - if (board->is_unavailable) - curr_int->unavail_secs++; - else - { - if (slip_detected) - curr_int->slip_secs++; - curr_int->errored_secs += errored_sec; - curr_int->bursty_err_secs += bursty_err_sec; - curr_int->severely_err_secs += severely_err_sec; - } - - /* the RFC does not say clearly which errors to count here, we try to count bit errors */ - - if (!board->is_unavailable && !severely_err_sec) - { - board->deg_cumulated_errors += code_violations; - board->deg_elapsed_seconds++; - if (board->deg_elapsed_seconds >= 60) - { - if (board->deg_cumulated_errors >= 123) - curr_int->degraded_mins++; - board->deg_cumulated_errors = 0; - board->deg_elapsed_seconds = 0; - } - - } - - board->elapsed_seconds++; - if (board->elapsed_seconds >= 900) - { - board->current_interval = - (board->current_interval + 1) % SLICECOM_BOARD_INTERVALS_SIZE; - memset((void *)&board->intervals[board->current_interval], 0, - sizeof(e1_stats_t)); - board->elapsed_seconds = 0; - } - - spin_unlock_irqrestore(&mister_lock, flags); -} - -static void pcicom_modemline(unsigned long b) -{ - munich_board_t *board = (munich_board_t *) b; - struct net_device *dev = board->twins[0]; - struct comx_channel *ch = netdev_priv(dev); - unsigned long regs; - - regs = readl((void *)(&board->bar1[GPDATA])); - if ((ch->line_status & LINE_UP) && (regs & 0x0800)) - { - ch->line_status &= ~LINE_UP; - board->lineup = 0; - if (ch->LINE_status) - { - ch->LINE_status(dev, ch->line_status); - } - } - - if (!(ch->line_status & LINE_UP) && !(regs & 0x0800)) - { - ch->line_status |= LINE_UP; - board->lineup = 1; - if (ch->LINE_status) - { - ch->LINE_status(dev, ch->line_status); - } - } - - mod_timer((struct timer_list *)&board->modemline_timer, jiffies + HZ); -} - -/* - * Is it possible to transmit ? - * Called (may be called) by the protocol layer - */ - -static int MUNICH_txe(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - - return (hw->busy < TX_DESC_MAX - 1); -} - -/* - * Hw probe function. Detects all the boards in the system, - * and fills up slicecom_boards[] and pcicom_boards[] - * Returns 0 on success. - * We do not disable interrupts! - */ -static int munich_probe(void) -{ - struct pci_dev *pci; - int boardnum; - int slicecom_boardnum; - int pcicom_boardnum; - u32 *bar1; - u8 *lbi; - munich_board_t *board; - - for (boardnum = 0; boardnum < MAX_BOARDS; boardnum++) - { - pcicom_boards[boardnum].pci = 0; - pcicom_boards[boardnum].bar1 = 0; - pcicom_boards[boardnum].lbi = 0; - slicecom_boards[boardnum].pci = 0; - slicecom_boards[boardnum].bar1 = 0; - slicecom_boards[boardnum].lbi = 0; - } - - pci = NULL; - board = NULL; - slicecom_boardnum = 0; - pcicom_boardnum = 0; - - for (boardnum = 0; - boardnum < MAX_BOARDS && (pci = pci_find_device(PCI_VENDOR_ID_SIEMENS, - PCI_DEVICE_ID_SIEMENS_MUNICH32X, pci)); boardnum++) - { - if (pci_enable_device(pci)) - continue; - - printk("munich_probe: munich chip found, IRQ %d\n", pci->irq); - - bar1 = ioremap_nocache(pci->resource[0].start, 0x100); - lbi = ioremap_nocache(pci->resource[1].start, 0x100); - - if (bar1 && lbi) - { - pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0xe0000); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - /* check the type of the card */ - writel(LREG0_MAGIC, MUNICH_VIRT(LREG0)); - writel(LREG1_MAGIC, MUNICH_VIRT(LREG1)); - writel(LREG2_MAGIC, MUNICH_VIRT(LREG2)); - writel(LREG3_MAGIC, MUNICH_VIRT(LREG3)); - writel(LREG4_MAGIC, MUNICH_VIRT(LREG4)); - writel(LREG5_MAGIC, MUNICH_VIRT(LREG5)); - writel(LCONF_MAGIC2,MUNICH_VIRT(LCONF)); /* enable the DMSM */ - - if ((readb(lbi + VSTR) == 0x13) || (readb(lbi + VSTR) == 0x10)) - { - board = slicecom_boards + slicecom_boardnum; - sprintf((char *)board->devname, "slicecom%d", - slicecom_boardnum); - board->isx21 = 0; - slicecom_boardnum++; - } - else if ((readb(lbi + VSTR) == 0x6) || (readb(lbi + GIS) == 0x6)) - { - board = pcicom_boards + pcicom_boardnum; - sprintf((char *)board->devname, "pcicom%d", pcicom_boardnum); - board->isx21 = 1; - pcicom_boardnum++; - } - if (board) - { - printk("munich_probe: %s board found\n", board->devname); - writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */ - board->pci = pci; - board->bar1 = bar1; - board->lbi = lbi; - board->framing = SLICECOM_FRAMING_DEFAULT; - board->linecode = SLICECOM_LINECODE_DEFAULT; - board->clock_source = SLICECOM_CLOCK_SOURCE_DEFAULT; - board->loopback = SLICECOM_LOOPBACK_DEFAULT; - board->owner = THIS_MODULE; - } - else - { - printk("munich_probe: Board error, VSTR: %02X\n", - readb(lbi + VSTR)); - iounmap((void *)bar1); - iounmap((void *)lbi); - } - } - else - { - printk("munich_probe: ioremap() failed, not enabling this board!\n"); - /* .pci = NULL, so the MUNICH_open will not try to open it */ - if (bar1) iounmap((void *)bar1); - if (lbi) iounmap((void *)lbi); - } - } - - if (!pci && !boardnum) - { - printk("munich_probe: no PCI present!\n"); - return -ENODEV; - } - - if (pcicom_boardnum + slicecom_boardnum == 0) - { - printk - ("munich_probe: Couldn't find any munich board: vendor:device %x:%x not found\n", - PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_MUNICH32X); - return -ENODEV; - } - - /* Found some */ - if (pcicom_boardnum) - printk("%d pcicom board(s) found.\n", pcicom_boardnum); - if (slicecom_boardnum) - printk("%d slicecom board(s) found.\n", slicecom_boardnum); - - return 0; -} - -/* - * Reset the hardware. Get called only from within this module if needed. - */ -#if 0 -static int slicecom_reset(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - - printk("slicecom_reset: resetting the hardware\n"); - - /* Begin to reset the hardware */ - - if (ch->HW_set_clock) - ch->HW_set_clock(dev); - - /* And finish it */ - - return 0; -} -#endif - -/* - * Transmit a packet. - * Called by the protocol layer - * Return values: - * FRAME_ACCEPTED: frame is being transmited, transmitter is busy - * FRAME_QUEUED: frame is being transmitted, there's more room in - * the transmitter for additional packet(s) - * FRAME_ERROR: - * FRAME_DROPPED: there was some error - */ - -static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - - /* Send it to the debug facility too if needed: */ - - if (ch->debug_flags & DEBUG_HW_TX) - comx_debug_bytes(dev, skb->data, skb->len, "MUNICH_send_packet"); - - /* If the line is inactive, don't accept: */ - - /* TODO: atgondolni hogy mi is legyen itt */ - /* if (!(ch->line_status & LINE_UP)) return FRAME_DROPPED; */ - - /* More check, to be sure: */ - - if (skb->len > TXBUFFER_SIZE) - { - ch->stats.tx_errors++; - kfree_skb(skb); - return FRAME_ERROR; - } - - /* Maybe you have to disable irq's while programming the hw: */ - - spin_lock_irqsave(&mister_lock, flags); - - /* And more check: */ - - if (hw->busy >= TX_DESC_MAX - 1) - { - printk(KERN_ERR - "%s: Transmitter called while busy... dropping frame, busy = %d\n", - dev->name, hw->busy); - spin_unlock_irqrestore(&mister_lock, flags); - kfree_skb(skb); - return FRAME_DROPPED; - } - - if (hw->busy >= 0) - hw->tx_ring_hist[hw->busy]++; - /* DELL: */ - else - printk("slicecom: %s: FATAL: busy = %d\n", dev->name, hw->busy); - -// /* DEL: */ -// printk("slicecom: %s: _send_packet called, busy = %d\n", dev->name, hw->busy ); - - /* Packet can go, update stats: */ - - ch->stats.tx_packets++; - ch->stats.tx_bytes += skb->len; - - /* Pass the packet to the HW: */ - /* Step forward with the transmit descriptors: */ - - hw->tx_desc_ptr = (hw->tx_desc_ptr + 1) % TX_DESC_MAX; - - memcpy(&(hw->tx_data[hw->tx_desc_ptr][0]), skb->data, skb->len); - hw->tx_desc[hw->tx_desc_ptr].no = skb->len; - - /* We don't issue any command, just step with the HOLD bit */ - - hw->tx_desc[hw->tx_desc_ptr].hold = 1; - hw->tx_desc[(hw->tx_desc_ptr + TX_DESC_MAX - 1) % TX_DESC_MAX].hold = 0; - -#ifdef COMX_NEW - dev_kfree_skb(skb); -#endif - /* csomag kerult a Tx ringbe: */ - - hw->busy++; - - /* Report it: */ - - if (ch->debug_flags & DEBUG_HW_TX) - comx_debug(dev, "%s: MUNICH_send_packet was successful\n\n", dev->name); - - if (hw->busy >= TX_DESC_MAX - 1) - { - spin_unlock_irqrestore(&mister_lock, flags); - return FRAME_ACCEPTED; - } - - spin_unlock_irqrestore(&mister_lock, flags); - - /* All done */ - - return FRAME_QUEUED; -} - -/* - * Interrupt handler routine. - * Called by the Linux kernel. - * BEWARE! The interrupts are enabled on the call! - */ -static irqreturn_t MUNICH_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct sk_buff *skb; - int length; - int rx_status; - int work; /* hany esemenyt kezeltem mar le */ - u32 *bar1; - u8 *lbi; - u32 stat, /* az esemenyek, amiket a ebben a loop korben le kell meg kezelni */ - race_stat = 0, /* race eseten ebben uzenek magamnak hogy mit kell meg lekezelni */ - ack; /* ezt fogom a vegen a STAT-ba irni, kiveszek belole 1-1 bitet ha */ - - /* az adott dolgot nem kell ack-olni mert volt vele munkam, es */ - /* legjobb ha visszaterek ide megegyszer */ - munich_intq_t int_info; - - struct net_device *dev; - struct comx_channel *ch; - struct slicecom_privdata *hw; - munich_board_t *board = (munich_board_t *) dev_id; - int channel; - - // , boardnum = (int)dev_id; - - // board = munich_boards + boardnum; - bar1 = board->bar1; - lbi = board->lbi; - - // Do not uncomment this under heavy load! :-> - // printk("MUNICH_interrupt: masked STAT=0x%08x, tiq=0x%08x, riq=0x%08x, piq=0x%08x\n", stat, board->tiq[0].all, board->riq[0].all, board->piq[0].all ); - - for (work = 0; (stat = (race_stat | (readl(MUNICH_VIRT(STAT)) & ~STAT_NOT_HANDLED_BY_INTERRUPT))) && (work < MAX_WORK - 1); work++) - { - ack = stat & (STAT_PRI | STAT_PTI | STAT_LBII); - - /* Handle the interrupt information in the Rx queue. We don't really trust */ - /* info from this queue, because it can be overflowed, so later check */ - /* every Rx ring for received packets. But there are some errors which can't */ - /* be counted from the Rx rings, so we parse it. */ - - int_info = board->riq[board->riq_ptr]; - if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ - { - ack &= ~STAT_PRI; /* don't ack the interrupt, we had some work to do */ - - channel = PCM_INT_CHANNEL(int_info.all); - dev = board->twins[channel]; - - if (dev == NULL) - { - printk - ("MUNICH_interrupt: got an Rx interrupt info for NULL device " - "%s.twins[%d], int_info = 0x%08x\n", board->devname, - channel, int_info.all); - goto go_for_next_interrupt; - } - - ch = netdev_priv(dev); - hw = (struct slicecom_privdata *)ch->HW_privdata; - - // printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n", - // stat, int_info.all, hw->rx_desc_ptr, hw->rx_desc[ hw->rx_desc_ptr ].status ); - - if (int_info.all & PCM_INT_HI) - printk("SliceCOM: %s: Host Initiated interrupt\n", dev->name); - if (int_info.all & PCM_INT_IFC) - printk("SliceCOM: %s: Idle/Flag Change\n", dev->name); - /* TOD: jo ez az Idle/Flag Change valamire? - azonnal latszik belole hogy mikor ad a masik oldal */ - /* TOD: ilyen IT most nem is jon, mert ki van maszkolva az interrupt, biztosan kell ez? */ - - if (int_info.all & PCM_INT_FO) - /* Internal buffer (RB) overrun */ - ch->stats.rx_over_errors++; /* TOD: Ez azt jelenti hogy a belso RB nem volt hozzaferheto, es ezert kihagyott valamit. De nem csak csomag lehetett, hanem esemeny, stb. is. lasd page 247. Ezzel a 'cat status'-hoz igazodok, de a netdevice.h szerint nem egyertelmu hogy ide ez kellene. Nem lehet hogy rx_missed ? */ - /* DE: nem gotozok sehova, elvileg jo igy */ - /* kesobb meg visszaterek az FO-ra, ha packet-FO volt. Keresd a "packet-FO"-t. */ - if (int_info.all & PCM_INT_FI) /* frame received, but we do not trust the int_info queue */ - if (int_info.all & PCM_INT_SF) - { /* Short Frame: rovidebb mint a CRC */ - /* "rovidebb mint CRC+2byte" vizsgalat a "CRC+2"-nel */ - ch->stats.rx_length_errors++; /* TOD: noveljem? ne noveljem? */ - goto go_for_next_interrupt; - } - - go_for_next_interrupt: /* One step in the interrupt queue */ - board->riq[board->riq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */ - board->riq_ptr = (board->riq_ptr + 1) % MUNICH_INTQMAX; - - } - - /* Check every Rx ring for incomed packets: */ - - for (channel = 0; channel < 32; channel++) - { - dev = board->twins[channel]; - - if (dev != NULL) - { - ch = netdev_priv(dev); - hw = (struct slicecom_privdata *)ch->HW_privdata; - - rx_status = hw->rx_desc[hw->rx_desc_ptr].status; - - if (!(rx_status & 0x80)) /* mar jart itt a hardver */ - { - ack &= ~STAT_PRI; /* Don't ack, we had some work */ - - /* Ez most egy kicsit zuros, mert itt mar nem latom az int_infot */ - if (rx_status & RX_STATUS_ROF) - ch->stats.rx_over_errors++; /* TOD: 'cat status'-hoz igazodok */ - - if (rx_status & RX_STATUS_RA) - /* Abort received or issued on channel */ - ch->stats.rx_frame_errors++; /* or HOLD bit in the descriptor */ - /* TOD: 'cat status'-hoz igazodok */ - - if (rx_status & RX_STATUS_LFD) - { /* Long Frame (longer then MFL in the MODE1) */ - ch->stats.rx_length_errors++; - goto go_for_next_frame; - } - - if (rx_status & RX_STATUS_NOB) - { /* Not n*8 bits long frame - frame alignment */ - ch->stats.rx_frame_errors++; /* ez viszont nem igazodik a 'cat status'-hoz */ - goto go_for_next_frame; - } - - if (rx_status & RX_STATUS_CRCO) - { /* CRC error */ - ch->stats.rx_crc_errors++; - goto go_for_next_frame; - } - - if (rx_status & RX_STATUS_SF) - { /* Short Frame: rovidebb mint CRC+2byte */ - ch->stats.rx_errors++; /* The HW does not set PCI_INT_ERR bit for this one, see page 246 */ - ch->stats.rx_length_errors++; - goto go_for_next_frame; - } - - if (rx_status != 0) - { - printk("SliceCOM: %s: unhandled rx_status: 0x%02x\n", - dev->name, rx_status); - goto go_for_next_frame; - } - - /* frame received without errors: */ - - length = hw->rx_desc[hw->rx_desc_ptr].bno; - ch->stats.rx_packets++; /* Count only 'good' packets */ - ch->stats.rx_bytes += length; - - /* Allocate a larger skb and reserve the heading for efficiency: */ - - if ((skb = dev_alloc_skb(length + 16)) == NULL) - { - ch->stats.rx_dropped++; - goto go_for_next_frame; - } - - /* Do bookkeeping: */ - - skb_reserve(skb, 16); - skb_put(skb, length); - skb->dev = dev; - - /* Now copy the data into the buffer: */ - - memcpy(skb->data, &(hw->rx_data[hw->rx_desc_ptr][0]), length); - - /* DEL: UGLY HACK!!!! */ - if (*((int *)skb->data) == 0x02000000 && - *(((int *)skb->data) + 1) == 0x3580008f) - { - printk("%s: swapping hack\n", dev->name); - *((int *)skb->data) = 0x3580008f; - *(((int *)skb->data) + 1) = 0x02000000; - } - - if (ch->debug_flags & DEBUG_HW_RX) - comx_debug_skb(dev, skb, "MUNICH_interrupt receiving"); - - /* Pass it to the protocol entity: */ - - ch->LINE_rx(dev, skb); - - go_for_next_frame: - /* DEL: rafutott-e a HOLD bitre -detektalas */ - { - if( ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->hold - && ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->status != 0xff) - hw->rafutott++; /* rafutott: hanyszor volt olyan hogy a current descriptoron HOLD bit volt, es a hw mar befejezte az irast (azaz a hw rafutott a HOLD bitre) */ - } - - // if( jiffies % 2 ) /* DELL: okozzunk egy kis Rx ring slipet :) */ - // { - /* Step forward with the receive descriptors: */ - /* if you change this, change the copy of it below too! Search for: "RxSlip" */ - hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 1) % RX_DESC_MAX].hold = 1; - hw->rx_desc[hw->rx_desc_ptr].status = 0xFF; /* megjelolom hogy itt meg nem jart a hw */ - hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 0; - hw->rx_desc_ptr = (hw->rx_desc_ptr + 1) % RX_DESC_MAX; - // } - } - } - } - - stat &= ~STAT_PRI; - -// } - -// if( stat & STAT_PTI ) /* TOD: primko megvalositas: mindig csak egy esemenyt dolgozok fel, */ - /* es nem torlom a STAT-ot, ezert ujra visszajon ide a rendszer. Amikor */ - /* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot. */ - /* 'needs a rewrite', de elso megoldasnak jo lesz */ -// { - int_info = board->tiq[board->tiq_ptr]; - if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ - { - ack &= ~STAT_PTI; /* don't ack the interrupt, we had some work to do */ - - channel = PCM_INT_CHANNEL(int_info.all); - dev = board->twins[channel]; - - if (dev == NULL) - { - printk("MUNICH_interrupt: got a Tx interrupt for NULL device " - "%s.twins[%d], int_info = 0x%08x\n", - board->isx21 ? "pcicom" : "slicecom", channel, int_info.all); - goto go_for_next_tx_interrupt; - } - - ch = netdev_priv(dev); - hw = (struct slicecom_privdata *)ch->HW_privdata; - - // printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr ); - - if (int_info.all & PCM_INT_FE2) - { /* "Tx available" */ - /* do nothing */ - } - else if (int_info.all & PCM_INT_FO) - { /* Internal buffer (RB) overrun */ - ch->stats.rx_over_errors++; - } - else - { - printk("slicecom: %s: unhandled Tx int_info: 0x%08x\n", - dev->name, int_info.all); - } - - go_for_next_tx_interrupt: - board->tiq[board->tiq_ptr].all = 0; - board->tiq_ptr = (board->tiq_ptr + 1) % MUNICH_INTQMAX; - } - - /* Check every Tx ring for incoming packets: */ - - for (channel = 0; channel < 32; channel++) - { - dev = board->twins[channel]; - - if (dev != NULL) - { - int newbusy; - - ch = netdev_priv(dev); - hw = (struct slicecom_privdata *)ch->HW_privdata; - - /* We don't trust the "Tx available" info from the TIQ, but check */ - /* every ring if there is some free room */ - - if (ch->init_status && netif_running(dev)) - { - newbusy = ( TX_DESC_MAX + (& hw->tx_desc[ hw->tx_desc_ptr ]) - - (tx_desc_t*)phys_to_virt(board->ccb->current_tx_desc[ hw->channel ]) ) % TX_DESC_MAX; - - if(newbusy < 0) - { - printk("slicecom: %s: FATAL: fresly computed busy = %d, HW: 0x%p, SW: 0x%p\n", - dev->name, newbusy, - phys_to_virt(board->ccb->current_tx_desc[hw->channel]), - & hw->tx_desc[hw->tx_desc_ptr]); - } - - /* Fogyott valami a Tx ringbol? */ - - if (newbusy < hw->busy) - { - // ack &= ~STAT_PTI; /* Don't ack, we had some work */ - hw->busy = newbusy; - if (ch->LINE_tx) - ch->LINE_tx(dev); /* Report it to protocol driver */ - } - else if (newbusy > hw->busy) - printk("slicecom: %s: newbusy > hw->busy, this should not happen!\n", dev->name); - } - } - } - stat &= ~STAT_PTI; - - int_info = board->piq[board->piq_ptr]; - if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */ - { - ack &= ~STAT_LBII; /* don't ack the interrupt, we had some work to do */ - - /* We do not really use (yet) the interrupt info from this queue, */ - - // printk("slicecom: %s: LBI Interrupt event: %08x\n", board->devname, int_info.all); - - if (!board->isx21) - { - slicecom_update_leds(board); - slicecom_update_line_counters(board); - } - - goto go_for_next_lbi_interrupt; /* To avoid warning about unused label */ - - go_for_next_lbi_interrupt: /* One step in the interrupt queue */ - board->piq[board->piq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */ - board->piq_ptr = (board->piq_ptr + 1) % MUNICH_PIQMAX; - } - stat &= ~STAT_LBII; - - writel(ack, MUNICH_VIRT(STAT)); - - if (stat & STAT_TSPA) - { - // printk("slicecom: %s: PCM TSP Asynchronous\n", board->devname); - writel(STAT_TSPA, MUNICH_VIRT(STAT)); - stat &= ~STAT_TSPA; - } - - if (stat & STAT_RSPA) - { - // printk("slicecom: %s: PCM RSP Asynchronous\n", board->devname); - writel(STAT_RSPA, MUNICH_VIRT(STAT)); - stat &= ~STAT_RSPA; - } - if (stat) - { - printk("MUNICH_interrupt: unhandled interrupt, STAT=0x%08x\n", - stat); - writel(stat, MUNICH_VIRT(STAT)); /* ha valamit megsem kezeltunk le, azert ack-ot kuldunk neki */ - } - - } - board->histogram[work]++; - - /* We can miss these if we reach the MAX_WORK */ - /* Count it to see how often it happens */ - - if (race_stat & STAT_PRI) - board->stat_pri_races_missed++; - if (race_stat & STAT_PTI) - board->stat_pti_races_missed++; - return IRQ_HANDLED; -} - -/* - * Hardware open routine. - * Called by comx (upper) layer when the user wants to bring up the interface - * with ifconfig. - * Initializes hardware, allocates resources etc. - * Returns 0 on OK, or standard error value on error. - */ - -static int MUNICH_open(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - munich_board_t *board; - munich_ccb_t *ccb; - - u32 *bar1; - u8 *lbi; - u32 stat; - unsigned long flags, jiffs; - - int i, channel; - u32 timeslots = hw->timeslots; - - board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - bar1 = board->bar1; - lbi = board->lbi; - - /* TODO: a timeslotok ellenorzese kell majd ide .. hat, biztos? mar a write_proc-ban is - ellenorzom valamennyire. - if (!dev->io || !dev->irq) return -ENODEV; - */ - - if (!board->pci) - { - printk("MUNICH_open: no %s board with boardnum = %d\n", - ch->hardware->name, hw->boardnum); - return -ENODEV; - } - - spin_lock_irqsave(&mister_lock, flags); - /* lock the section to avoid race with multiple opens and make sure - that no interrupts get called while this lock is active */ - - if (board->use_count == 0) /* bring up the board if it was unused */ - /* if fails, frees allocated resources and returns. */ - /* TOD: is it safe? nem kellene resetelni a kartyat? */ - { - printk("MUNICH_open: %s: bringing up board\n", board->devname); - - /* Clean up the board's static struct if messed: */ - - for (i = 0; i < 32; i++) - board->twins[i] = NULL; - for (i = 0; i < MAX_WORK; i++) - board->histogram[i] = 0; - - board->lineup = 0; - - /* Allocate CCB: */ - board->ccb = kmalloc(sizeof(munich_ccb_t), GFP_KERNEL); - if (board->ccb == NULL) - { - spin_unlock_irqrestore(&mister_lock, flags); - return -ENOMEM; - } - memset((void *)board->ccb, 0, sizeof(munich_ccb_t)); - board->ccb->csa = virt_to_phys(board->ccb); - ccb = board->ccb; - for (i = 0; i < 32; i++) - { - ccb->timeslot_spec[i].tti = 1; - ccb->timeslot_spec[i].rti = 1; - } - - /* Interrupt queues: */ - - board->tiq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL); - if (board->tiq == NULL) - { - spin_unlock_irqrestore(&mister_lock, flags); - return -ENOMEM; - } - memset((void *)board->tiq, 0, MUNICH_INTQSIZE); - - board->riq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL); - if (board->riq == NULL) - { - spin_unlock_irqrestore(&mister_lock, flags); - return -ENOMEM; - } - memset((void *)board->riq, 0, MUNICH_INTQSIZE); - - board->piq = kmalloc(MUNICH_PIQSIZE, GFP_KERNEL); - if (board->piq == NULL) - { - spin_unlock_irqrestore(&mister_lock, flags); - return -ENOMEM; - } - memset((void *)board->piq, 0, MUNICH_PIQSIZE); - - board->tiq_ptr = 0; - board->riq_ptr = 0; - board->piq_ptr = 0; - - /* Request irq: */ - - board->irq = 0; - - /* (char*) cast to avoid warning about discarding volatile: */ - if (request_irq(board->pci->irq, MUNICH_interrupt, 0, - (char *)board->devname, (void *)board)) - { - printk("MUNICH_open: %s: unable to obtain irq %d\n", board->devname, - board->pci->irq); - /* TOD: free other resources (a sok malloc feljebb) */ - spin_unlock_irqrestore(&mister_lock, flags); - return -EAGAIN; - } - board->irq = board->pci->irq; /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */ - - /* Programming device: */ - - /* Reset the board like a power-on: */ - /* TOD: - - It is not a real power-on: if a DMA transaction fails with master abort, the board - stays in half-dead state. - - It doesn't reset the FALC line driver */ - - pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - writel(virt_to_phys(&ccb->csa), MUNICH_VIRT(CCBA)); - writel(virt_to_phys( board->tiq ), MUNICH_VIRT(TIQBA)); - writel(MUNICH_INTQLEN, MUNICH_VIRT(TIQL)); - writel(virt_to_phys( board->riq ), MUNICH_VIRT(RIQBA)); - writel(MUNICH_INTQLEN, MUNICH_VIRT(RIQL)); - writel(virt_to_phys( board->piq ), MUNICH_VIRT(PIQBA)); - writel(MUNICH_PIQLEN, MUNICH_VIRT(PIQL)); - - /* Put the magic values into the registers: */ - - writel(MODE1_MAGIC, MUNICH_VIRT(MODE1)); - writel(MODE2_MAGIC, MUNICH_VIRT(MODE2)); - - writel(LREG0_MAGIC, MUNICH_VIRT(LREG0)); - writel(LREG1_MAGIC, MUNICH_VIRT(LREG1)); - writel(LREG2_MAGIC, MUNICH_VIRT(LREG2)); - writel(LREG3_MAGIC, MUNICH_VIRT(LREG3)); - writel(LREG4_MAGIC, MUNICH_VIRT(LREG4)); - writel(LREG5_MAGIC, MUNICH_VIRT(LREG5)); - - writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */ - writel(LCONF_MAGIC2, MUNICH_VIRT(LCONF)); /* enable the DMSM */ - - writel(~0, MUNICH_VIRT(TXPOLL)); - writel(board->isx21 ? 0x1400 : 0xa000, MUNICH_VIRT(GPDIR)); - - if (readl(MUNICH_VIRT(STAT))) writel(readl(MUNICH_VIRT(STAT)), MUNICH_VIRT(STAT)); - - ccb->action_spec = CCB_ACTIONSPEC_RES | CCB_ACTIONSPEC_IA; - writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the PCM core reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - stat = 0; /* Wait for the action to complete max. 1 second */ - jiffs = jiffies; - while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - - if (stat & STAT_PCMF) - { - printk(KERN_ERR - "MUNICH_open: %s: Initial ARPCM failed. STAT=0x%08x\n", - board->devname, stat); - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); - free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut down hw? */ - board->irq = 0; - spin_unlock_irqrestore(&mister_lock, flags); - return -EAGAIN; - } - else if (!(stat & STAT_PCMA)) - { - printk(KERN_ERR - "MUNICH_open: %s: Initial ARPCM timeout. STAT=0x%08x\n", - board->devname, stat); - free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut off the hw? */ - board->irq = 0; - spin_unlock_irqrestore(&mister_lock, flags); - return -EIO; - } - - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); /* Acknowledge */ - - if (board->isx21) writel(0, MUNICH_VIRT(GPDATA)); - - printk("MUNICH_open: %s: succesful HW-open took %ld jiffies\n", - board->devname, jiffies - jiffs); - - /* Set up the FALC hanging on the Local Bus: */ - - if (!board->isx21) - { - writeb(0x0e, lbi + FMR1); - writeb(0, lbi + LIM0); - writeb(0xb0, lbi + LIM1); /* TODO: input threshold */ - writeb(0xf7, lbi + XPM0); - writeb(0x02, lbi + XPM1); - writeb(0x00, lbi + XPM2); - writeb(0xf0, lbi + FMR0); - writeb(0x80, lbi + PCD); - writeb(0x80, lbi + PCR); - writeb(0x00, lbi + LIM2); - writeb(0x07, lbi + XC0); - writeb(0x3d, lbi + XC1); - writeb(0x05, lbi + RC0); - writeb(0x00, lbi + RC1); - writeb(0x83, lbi + FMR2); - writeb(0x9f, lbi + XSW); - writeb(0x0f, lbi + XSP); - writeb(0x00, lbi + TSWM); - writeb(0xe0, lbi + MODE); - writeb(0xff, lbi + IDLE); /* Idle Code to send in unused timeslots */ - writeb(0x83, lbi + IPC); /* interrupt query line mode: Push/pull output, active high */ - writeb(0xbf, lbi + IMR3); /* send an interrupt every second */ - - slicecom_set_framing(hw->boardnum, board->framing); - slicecom_set_linecode(hw->boardnum, board->linecode); - slicecom_set_clock_source(hw->boardnum, board->clock_source); - slicecom_set_loopback(hw->boardnum, board->loopback); - - memset((void *)board->intervals, 0, sizeof(board->intervals)); - board->current_interval = 0; - board->elapsed_seconds = 0; - board->ses_seconds = 0; - board->is_unavailable = 0; - board->no_ses_seconds = 0; - board->deg_elapsed_seconds = 0; - board->deg_cumulated_errors = 0; - } - - /* Enable the interrupts last */ - /* These interrupts will be enabled. We do not need the others. */ - - writel(readl(MUNICH_VIRT(IMASK)) & ~(STAT_PTI | STAT_PRI | STAT_LBII | STAT_TSPA | STAT_RSPA), MUNICH_VIRT(IMASK)); - } - - spin_unlock_irqrestore(&mister_lock, flags); - - dev->irq = board->irq; /* hogy szep legyen az ifconfig outputja */ - ccb = board->ccb; /* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */ - - spin_lock_irqsave(&mister_lock, flags); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - /* Check if the selected timeslots aren't used already */ - - for (i = 0; i < 32; i++) - if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti) - { - printk("MUNICH_open: %s: timeslot %d already used by %s\n", - dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name); - spin_unlock_irqrestore(&mister_lock, flags); - return -EBUSY; /* TODO: lehet hogy valami mas errno kellene? */ - } - - /* find a free channel: */ - /* TODO: ugly, rewrite it */ - - for (channel = 0; channel <= 32; channel++) - { - if (channel == 32) - { /* not found a free one */ - printk - ("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n", - dev->name); - spin_unlock_irqrestore(&mister_lock, flags); - return -ENODEV; - } - if (board->twins[channel] == NULL) - break; /* found the first free one */ - } - - board->lastcheck = jiffies; /* avoid checking uninitialized hardware channel */ - - /* Open the channel. If fails, calls MUNICH_close() to properly free resources and stop the HW */ - - hw->channel = channel; - board->twins[channel] = dev; - - board->use_count++; /* meg nem nyitottuk meg a csatornat, de a twins-ben - mar elfoglaltunk egyet, es ha a _close-t akarjuk hivni, akkor ez kell. */ - for (i = 0; i < 32; i++) - if ((1 << i) & timeslots) - { - ccb->timeslot_spec[i].tti = 0; - ccb->timeslot_spec[i].txchannel = channel; - ccb->timeslot_spec[i].txfillmask = ~0; - - ccb->timeslot_spec[i].rti = 0; - ccb->timeslot_spec[i].rxchannel = channel; - ccb->timeslot_spec[i].rxfillmask = ~0; - } - - if (!board->isx21) rework_idle_channels(dev); - - memset((void *)&(hw->tx_desc), 0, TX_DESC_MAX * sizeof(tx_desc_t)); - memset((void *)&(hw->rx_desc), 0, RX_DESC_MAX * sizeof(rx_desc_t)); - - for (i = 0; i < TX_DESC_MAX; i++) - { - hw->tx_desc[i].fe = 1; - hw->tx_desc[i].fnum = 2; - hw->tx_desc[i].data = virt_to_phys( & (hw->tx_data[i][0]) ); - hw->tx_desc[i].next = virt_to_phys( & (hw->tx_desc[ (i+1) % TX_DESC_MAX ]) ); - - } - hw->tx_desc_ptr = 0; /* we will send an initial packet so it is correct: "oda irtunk utoljara" */ - hw->busy = 0; - hw->tx_desc[hw->tx_desc_ptr].hold = 1; - hw->tx_desc[hw->tx_desc_ptr].no = 1; /* TOD: inkabb csak 0 hosszut kuldjunk ki az initkor? */ - - for (i = 0; i < RX_DESC_MAX; i++) - { - hw->rx_desc[i].no = RXBUFFER_SIZE; - hw->rx_desc[i].data = virt_to_phys(&(hw->rx_data[i][0])); - hw->rx_desc[i].next = virt_to_phys(&(hw->rx_desc[(i+1) % RX_DESC_MAX])); - hw->rx_desc[i].status = 0xFF; - } - hw->rx_desc_ptr = 0; - - hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 1; - - memset((void *)&ccb->channel_spec[channel], 0, sizeof(channel_spec_t)); - - ccb->channel_spec[channel].ti = 0; /* Transmit off */ - ccb->channel_spec[channel].to = 1; - ccb->channel_spec[channel].ta = 0; - - ccb->channel_spec[channel].th = 1; /* Transmit hold */ - - ccb->channel_spec[channel].ri = 0; /* Receive off */ - ccb->channel_spec[channel].ro = 1; - ccb->channel_spec[channel].ra = 0; - - ccb->channel_spec[channel].mode = 3; /* HDLC */ - - ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8); - writel(CMD_ARPCM, MUNICH_VIRT(CMD)); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - spin_unlock_irqrestore(&mister_lock, flags); - - stat = 0; - jiffs = jiffies; - while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - - if (stat & STAT_PCMF) - { - printk(KERN_ERR "MUNICH_open: %s: %s channel %d off failed\n", - dev->name, board->devname, channel); - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); - MUNICH_close(dev); - return -EAGAIN; - } - else if (!(stat & STAT_PCMA)) - { - printk(KERN_ERR "MUNICH_open: %s: %s channel %d off timeout\n", - dev->name, board->devname, channel); - MUNICH_close(dev); - return -EIO; - } - - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); - // printk("MUNICH_open: %s: succesful channel off took %ld jiffies\n", board->devname, jiffies-jiffs); - - spin_lock_irqsave(&mister_lock, flags); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - ccb->channel_spec[channel].ifc = 1; /* 1 .. 'Idle/Flag change' interrupt letiltva */ - ccb->channel_spec[channel].fit = 1; - ccb->channel_spec[channel].nitbs = 1; - ccb->channel_spec[channel].itbs = 2; - - /* TODOO: lehet hogy jo lenne igy, de utana kellene nezni hogy nem okoz-e fragmentaciot */ - // ccb->channel_spec[channel].itbs = 2 * number_of_timeslots; - // printk("open: %s: number_of_timeslots: %d\n", dev->name, number_of_timeslots); - - ccb->channel_spec[channel].mode = 3; /* HDLC */ - ccb->channel_spec[channel].ftda = virt_to_phys(&(hw->tx_desc)); - ccb->channel_spec[channel].frda = virt_to_phys(&(hw->rx_desc[0])); - - ccb->channel_spec[channel].ti = 1; /* Transmit init */ - ccb->channel_spec[channel].to = 0; - ccb->channel_spec[channel].ta = 1; - - ccb->channel_spec[channel].th = 0; - - ccb->channel_spec[channel].ri = 1; /* Receive init */ - ccb->channel_spec[channel].ro = 0; - ccb->channel_spec[channel].ra = 1; - - ccb->action_spec = CCB_ACTIONSPEC_ICO | (channel << 8); - writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the channel init */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - spin_unlock_irqrestore(&mister_lock, flags); - - stat = 0; /* Wait for the action to complete max. 1 second */ - jiffs = jiffies; - while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - - if (stat & STAT_PCMF) - { - printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM failed\n", - board->devname); - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); - MUNICH_close(dev); - return -EAGAIN; - } - else if (!(stat & STAT_PCMA)) - { - printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM timeout\n", - board->devname); - MUNICH_close(dev); - return -EIO; - } - - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); - // printk("MUNICH_open: %s: succesful channel open took %ld jiffies\n", board->devname, jiffies-jiffs); - - spin_lock_irqsave(&mister_lock, flags); - - ccb->channel_spec[channel].nitbs = 0; /* once ITBS defined, these must be 0 */ - ccb->channel_spec[channel].itbs = 0; - - if (board->isx21) - { - init_timer(&board->modemline_timer); - board->modemline_timer.data = (unsigned long)board; - board->modemline_timer.function = pcicom_modemline; - board->modemline_timer.expires = jiffies + HZ; - add_timer((struct timer_list *)&board->modemline_timer); - } - - /* It is done. Declare that we're open: */ - hw->busy = 0; /* It may be 1 if the frame at Tx init already ended, but it is not */ - /* a real problem: we compute hw->busy on every interrupt */ - hw->rafutott = 0; - ch->init_status |= HW_OPEN; - - /* Initialize line state: */ - if (board->lineup) - ch->line_status |= LINE_UP; - else - ch->line_status &= ~LINE_UP; - - /* Remove w attribute from /proc files associated to hw parameters: - no write when the device is open */ - - for (; procfile; procfile = procfile->next) - if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 || - strcmp(procfile->name, FILENAME_TIMESLOTS) == 0) - procfile->mode = S_IFREG | 0444; - - spin_unlock_irqrestore(&mister_lock, flags); - - return 0; -} - -/* - * Hardware close routine. - * Called by comx (upper) layer when the user wants to bring down the interface - * with ifconfig. - * We also call it from MUNICH_open, if the open fails. - * Brings down hardware, frees resources, stops receiver - * Returns 0 on OK, or standard error value on error. - */ - -static int MUNICH_close(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - struct proc_dir_entry *procfile = ch->procdir->subdir; - munich_board_t *board; - munich_ccb_t *ccb; - - u32 *bar1; - u32 timeslots = hw->timeslots; - int stat, i, channel = hw->channel; - unsigned long jiffs; - - board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - ccb = board->ccb; - bar1 = board->bar1; - - if (board->isx21) - del_timer((struct timer_list *)&board->modemline_timer); - - spin_lock_irqsave(&mister_lock, flags); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - /* Disable receiver for the channel: */ - - for (i = 0; i < 32; i++) - if ((1 << i) & timeslots) - { - ccb->timeslot_spec[i].tti = 1; - ccb->timeslot_spec[i].txfillmask = 0; /* just to be double-sure :) */ - - ccb->timeslot_spec[i].rti = 1; - ccb->timeslot_spec[i].rxfillmask = 0; - } - - if (!board->isx21) rework_idle_channels(dev); - - ccb->channel_spec[channel].ti = 0; /* Receive off, Transmit off */ - ccb->channel_spec[channel].to = 1; - ccb->channel_spec[channel].ta = 0; - ccb->channel_spec[channel].th = 1; - - ccb->channel_spec[channel].ri = 0; - ccb->channel_spec[channel].ro = 1; - ccb->channel_spec[channel].ra = 0; - - board->twins[channel] = NULL; - - ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8); - writel(CMD_ARPCM, MUNICH_VIRT(CMD)); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - - spin_unlock_irqrestore(&mister_lock, flags); - - stat = 0; - jiffs = jiffies; - while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ)) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - - if (stat & STAT_PCMF) - { - printk(KERN_ERR - "MUNICH_close: %s: FATAL: channel off ARPCM failed, not closing!\n", - dev->name); - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT)); - /* If we return success, the privdata (and the descriptor list) will be freed */ - return -EIO; - } - else if (!(stat & STAT_PCMA)) - printk(KERN_ERR "MUNICH_close: %s: channel off ARPCM timeout\n", - board->devname); - - writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); - // printk("MUNICH_close: %s: channel off took %ld jiffies\n", board->devname, jiffies-jiffs); - - spin_lock_irqsave(&mister_lock, flags); - - if (board->use_count) board->use_count--; - - if (!board->use_count) /* we were the last user of the board */ - { - printk("MUNICH_close: bringing down board %s\n", board->devname); - - /* program down the board: */ - - writel(0x0000FF7F, MUNICH_VIRT(IMASK)); /* do not send any interrupts */ - writel(0, MUNICH_VIRT(CMD)); /* stop the timer if someone started it */ - writel(~0U, MUNICH_VIRT(STAT)); /* if an interrupt came between the cli()-sti(), quiet it */ - if (ch->hardware == &pcicomhw) - writel(0x1400, MUNICH_VIRT(GPDATA)); - - /* Put the board into 'reset' state: */ - pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000); - - /* Free irq and other resources: */ - if (board->irq) - free_irq(board->irq, (void *)board); /* Ha nem inicializalta magat, akkor meg nincs irq */ - board->irq = 0; - - /* Free CCB and the interrupt queues */ - if (board->ccb) kfree((void *)board->ccb); - if (board->tiq) kfree((void *)board->tiq); - if (board->riq) kfree((void *)board->riq); - if (board->piq) kfree((void *)board->piq); - board->ccb = NULL; - board->tiq = board->riq = board->piq = NULL; - } - - /* Enable setting of hw parameters */ - for (; procfile; procfile = procfile->next) - if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 || - strcmp(procfile->name, FILENAME_TIMESLOTS) == 0) - procfile->mode = S_IFREG | 0644; - - /* We're not open anymore */ - ch->init_status &= ~HW_OPEN; - - spin_unlock_irqrestore(&mister_lock, flags); - - return 0; -} - -/* - * Give (textual) status information. - * The text it returns will be a part of what appears when the user does a - * cat /proc/comx/comx[n]/status - * Don't write more than PAGESIZE. - * Return value: number of bytes written (length of the string, incl. 0) - */ - -static int MUNICH_minden(struct net_device *dev, char *page) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - munich_board_t *board; - struct net_device *devp; - - u8 *lbi; - e1_stats_t *curr_int, *prev_int; - e1_stats_t last4, last96; /* sum of last 4, resp. last 96 intervals */ - unsigned *sump, /* running pointer for the sum data */ - *p; /* running pointer for the interval data */ - - int len = 0; - u8 frs0, frs1; - u8 fmr2; - int i, j; - u32 timeslots; - - board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - lbi = board->lbi; - curr_int = &board->intervals[board->current_interval]; - prev_int = - &board-> - intervals[(board->current_interval + SLICECOM_BOARD_INTERVALS_SIZE - - 1) % SLICECOM_BOARD_INTERVALS_SIZE]; - - if (!board->isx21) - { - frs0 = readb(lbi + FRS0); - fmr2 = readb(lbi + FMR2); - len += scnprintf(page + len, PAGE_SIZE - len, "Controller status:\n"); - if (frs0 == 0) - len += scnprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n"); - else - { - if (frs0 & FRS0_LOS) - len += scnprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n"); - else - { - if (frs0 & FRS0_AIS) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tAlarm Indication Signal\n"); - else - { - if (frs0 & FRS0_AUXP) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tAuxiliary Pattern Indication\n"); - if (frs0 & FRS0_LFA) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tLoss of Frame Alignment\n"); - else - { - if (frs0 & FRS0_RRA) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tReceive Remote Alarm\n"); - - /* You can't set this framing with the /proc interface, but it */ - /* may be good to have here this alarm if you set it by hand: */ - - if ((board->framing == SLICECOM_FRAMING_CRC4) && - (frs0 & FRS0_LMFA)) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tLoss of CRC4 Multiframe Alignment\n"); - - if (((fmr2 & 0xc0) == 0xc0) && (frs0 & FRS0_NMF)) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tNo CRC4 Multiframe alignment Found after 400 msec\n"); - } - } - } - } - - frs1 = readb(lbi + FRS1); - if (FRS1_XLS & frs1) - len += scnprintf(page + len, PAGE_SIZE - len, - "\tTransmit Line Short\n"); - - /* debug Rx ring: DEL: - vagy meghagyni, de akkor legyen kicsit altalanosabb */ - } - - len += scnprintf(page + len, PAGE_SIZE - len, "Rx ring:\n"); - len += scnprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott); - len += scnprintf(page + len, PAGE_SIZE - len, - "\tlastcheck: %ld, jiffies: %ld\n", board->lastcheck, jiffies); - len += scnprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n", - (u32) virt_to_phys(&hw->rx_desc[0])); - len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n", - hw->rx_desc_ptr); - len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n", - (u32) virt_to_phys(&hw->rx_desc[hw->rx_desc_ptr])); - len += scnprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n", - board->ccb->current_rx_desc[hw->channel]); - - for (i = 0; i < RX_DESC_MAX; i++) - len += scnprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n", - *((u32 *) & hw->rx_desc[i] + 0), - *((u32 *) & hw->rx_desc[i] + 1), - *((u32 *) & hw->rx_desc[i] + 2), - *((u32 *) & hw->rx_desc[i] + 3)); - - if (!board->isx21) - { - len += scnprintf(page + len, PAGE_SIZE - len, - "Interfaces using this board: (channel-group, interface, timeslots)\n"); - for (i = 0; i < 32; i++) - { - devp = board->twins[i]; - if (devp != NULL) - { - timeslots = - ((struct slicecom_privdata *)((struct comx_channel *)devp-> - priv)->HW_privdata)-> - timeslots; - len += scnprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i, - devp->name); - for (j = 0; j < 32; j++) - if ((1 << j) & timeslots) - len += scnprintf(page + len, PAGE_SIZE - len, "%d ", j); - len += scnprintf(page + len, PAGE_SIZE - len, "\n"); - } - } - } - - len += scnprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n"); - for (i = 0; i < MAX_WORK; i++) - len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i, - board->histogram[i], (i && - ((i + 1) % 4 == 0 || - i == MAX_WORK - 1)) ? '\n' : ' '); - - len += scnprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n"); - for (i = 0; i < TX_DESC_MAX; i++) - len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i, - hw->tx_ring_hist[i], (i && - ((i + 1) % 4 == 0 || - i == - TX_DESC_MAX - 1)) ? '\n' : ' '); - - if (!board->isx21) - { - - memset((void *)&last4, 0, sizeof(last4)); - memset((void *)&last96, 0, sizeof(last96)); - - /* Calculate the sum of last 4 intervals: */ - - for (i = 1; i <= 4; i++) - { - p = (unsigned *)&board->intervals[(board->current_interval + - SLICECOM_BOARD_INTERVALS_SIZE - - i) % SLICECOM_BOARD_INTERVALS_SIZE]; - sump = (unsigned *)&last4; - for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++) - sump[j] += p[j]; - } - - /* Calculate the sum of last 96 intervals: */ - - for (i = 1; i <= 96; i++) - { - p = (unsigned *)&board->intervals[(board->current_interval + - SLICECOM_BOARD_INTERVALS_SIZE - - i) % SLICECOM_BOARD_INTERVALS_SIZE]; - sump = (unsigned *)&last96; - for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++) - sump[j] += p[j]; - } - - len += scnprintf(page + len, PAGE_SIZE - len, - "Data in current interval (%d seconds elapsed):\n", - board->elapsed_seconds); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", - curr_int->line_code_violations, - curr_int->path_code_violations, curr_int->e_bit_errors); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", - curr_int->slip_secs, curr_int->fr_loss_secs, - curr_int->line_err_secs, curr_int->degraded_mins); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", - curr_int->errored_secs, curr_int->bursty_err_secs, - curr_int->severely_err_secs, curr_int->unavail_secs); - - len += scnprintf(page + len, PAGE_SIZE - len, - "Data in Interval 1 (15 minutes):\n"); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", - prev_int->line_code_violations, - prev_int->path_code_violations, prev_int->e_bit_errors); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", - prev_int->slip_secs, prev_int->fr_loss_secs, - prev_int->line_err_secs, prev_int->degraded_mins); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", - prev_int->errored_secs, prev_int->bursty_err_secs, - prev_int->severely_err_secs, prev_int->unavail_secs); - - len += scnprintf(page + len, PAGE_SIZE - len, - "Data in last 4 intervals (1 hour):\n"); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", - last4.line_code_violations, last4.path_code_violations, - last4.e_bit_errors); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", - last4.slip_secs, last4.fr_loss_secs, last4.line_err_secs, - last4.degraded_mins); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", - last4.errored_secs, last4.bursty_err_secs, - last4.severely_err_secs, last4.unavail_secs); - - len += scnprintf(page + len, PAGE_SIZE - len, - "Data in last 96 intervals (24 hours):\n"); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n", - last96.line_code_violations, last96.path_code_violations, - last96.e_bit_errors); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n", - last96.slip_secs, last96.fr_loss_secs, - last96.line_err_secs, last96.degraded_mins); - len += scnprintf(page + len, PAGE_SIZE - len, - " %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n", - last96.errored_secs, last96.bursty_err_secs, - last96.severely_err_secs, last96.unavail_secs); - - } - -// len +=scnprintf( page + len, PAGE_SIZE - len, "Special events:\n" ); -// len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed ); -// len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed ); - return len; -} - -/* - * Memory dump function. Not used currently. - */ -static int BOARD_dump(struct net_device *dev) -{ - printk - ("BOARD_dump() requested. It is unimplemented, it should not be called\n"); - return (-1); -} - -/* - * /proc file read function for the files registered by this module. - * This function is called by the procfs implementation when a user - * wants to read from a file registered by this module. - * page is the workspace, start should point to the real start of data, - * off is the file offset, data points to the file's proc_dir_entry - * structure. - * Returns the number of bytes copied to the request buffer. - */ - -static int munich_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - munich_board_t *board; - - int len = 0, i; - u32 timeslots = hw->timeslots; - - board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - if (!strcmp(file->name, FILENAME_BOARDNUM)) - len = sprintf(page, "%d\n", hw->boardnum); - else if (!strcmp(file->name, FILENAME_TIMESLOTS)) - { - for (i = 0; i < 32; i++) - if ((1 << i) & timeslots) - len += scnprintf(page + len, PAGE_SIZE - len, "%d ", i); - len += scnprintf(page + len, PAGE_SIZE - len, "\n"); - } - else if (!strcmp(file->name, FILENAME_FRAMING)) - { - i = 0; - while (slicecom_framings[i].value && - slicecom_framings[i].value != board->framing) - i++; - len += scnprintf(page + len, PAGE_SIZE - len, "%s\n", - slicecom_framings[i].name); - } - else if (!strcmp(file->name, FILENAME_LINECODE)) - { - i = 0; - while (slicecom_linecodes[i].value && - slicecom_linecodes[i].value != board->linecode) - i++; - len += scnprintf(page + len, PAGE_SIZE - len, "%s\n", - slicecom_linecodes[i].name); - } - else if (!strcmp(file->name, FILENAME_CLOCK_SOURCE)) - { - i = 0; - while (slicecom_clock_sources[i].value && - slicecom_clock_sources[i].value != board->clock_source) - i++; - len += - scnprintf(page + len, PAGE_SIZE - len, "%s\n", - slicecom_clock_sources[i].name); - } - else if (!strcmp(file->name, FILENAME_LOOPBACK)) - { - i = 0; - while (slicecom_loopbacks[i].value && - slicecom_loopbacks[i].value != board->loopback) - i++; - len += scnprintf(page + len, PAGE_SIZE - len, "%s\n", - slicecom_loopbacks[i].name); - } - /* We set permissions to write-only for REG and LBIREG, but root can read them anyway: */ - else if (!strcmp(file->name, FILENAME_REG)) - { - len += scnprintf(page + len, PAGE_SIZE - len, - "%s: " FILENAME_REG ": write-only file\n", dev->name); - } - else if (!strcmp(file->name, FILENAME_LBIREG)) - { - len += scnprintf(page + len, PAGE_SIZE - len, - "%s: " FILENAME_LBIREG ": write-only file\n", dev->name); - } - else - { - printk("slicecom_read_proc: internal error, filename %s\n", file->name); - return -EBADF; - } - /* file handling administration: count eof status, offset, start address - and count: */ - - if (off >= len) - { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) - *eof = 1; - return min((off_t) count, (off_t) len - off); -} - -/* - * Write function for /proc files registered by us. - * See the comment on read function above. - * Beware! buffer is in userspace!!! - * Returns the number of bytes written - */ - -static int munich_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw = ch->HW_privdata; - munich_board_t *board; - - unsigned long ts, tmp_boardnum; - - u32 tmp_timeslots = 0; - char *page, *p; - int i; - - board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - /* Paranoia checking: */ - - if (PDE(file->f_dentry->d_inode) != entry) - { - printk(KERN_ERR "munich_write_proc: file <-> data internal error\n"); - return -EIO; - } - - /* Request tmp buffer */ - if (!(page = (char *)__get_free_page(GFP_KERNEL))) - return -ENOMEM; - - /* Copy user data and cut trailing \n */ - if (copy_from_user(page, buffer, count = min(count, PAGE_SIZE))) { - free_page((unsigned long)page); - return -EFAULT; - } - if (*(page + count - 1) == '\n') - *(page + count - 1) = 0; - *(page + PAGE_SIZE - 1) = 0; - - if (!strcmp(entry->name, FILENAME_BOARDNUM)) - { - tmp_boardnum = simple_strtoul(page, NULL, 0); - if (0 <= tmp_boardnum && tmp_boardnum < MAX_BOARDS) - hw->boardnum = tmp_boardnum; - else - { - printk("%s: " FILENAME_BOARDNUM " range is 0...%d\n", dev->name, - MAX_BOARDS - 1); - free_page((unsigned long)page); - return -EINVAL; - } - } - else if (!strcmp(entry->name, FILENAME_TIMESLOTS)) - { - p = page; - while (*p) - { - if (isspace(*p)) - p++; - else - { - ts = simple_strtoul(p, &p, 10); /* base = 10: Don't read 09 as an octal number */ - /* ts = 0 ha nem tudta beolvasni a stringet, erre egy kicsit epitek itt: */ - if (0 <= ts && ts < 32) - { - tmp_timeslots |= (1 << ts); - } - else - { - printk("%s: " FILENAME_TIMESLOTS " range is 1...31\n", - dev->name); - free_page((unsigned long)page); - return -EINVAL; - } - } - } - hw->timeslots = tmp_timeslots; - } - else if (!strcmp(entry->name, FILENAME_FRAMING)) - { - i = 0; - while (slicecom_framings[i].value && - strncmp(slicecom_framings[i].name, page, - strlen(slicecom_framings[i].name))) - i++; - if (!slicecom_framings[i].value) - { - printk("slicecom: %s: Invalid " FILENAME_FRAMING " '%s'\n", - dev->name, page); - free_page((unsigned long)page); - return -EINVAL; - } - else - { /* - * If somebody says: - * echo >boardnum 0 - * echo >framing no-crc4 - * echo >boardnum 1 - * - when the framing was set, hw->boardnum was 0, so it would set the framing for board 0 - * Workaround: allow to set it only if interface is administrative UP - */ - if (netif_running(dev)) - slicecom_set_framing(hw->boardnum, slicecom_framings[i].value); - else - { - printk("%s: " FILENAME_FRAMING - " can not be set while the interface is DOWN\n", - dev->name); - free_page((unsigned long)page); - return -EINVAL; - } - } - } - else if (!strcmp(entry->name, FILENAME_LINECODE)) - { - i = 0; - while (slicecom_linecodes[i].value && - strncmp(slicecom_linecodes[i].name, page, - strlen(slicecom_linecodes[i].name))) - i++; - if (!slicecom_linecodes[i].value) - { - printk("slicecom: %s: Invalid " FILENAME_LINECODE " '%s'\n", - dev->name, page); - free_page((unsigned long)page); - return -EINVAL; - } - else - { /* - * Allow to set it only if interface is administrative UP, - * for the same reason as FILENAME_FRAMING - */ - if (netif_running(dev)) - slicecom_set_linecode(hw->boardnum, - slicecom_linecodes[i].value); - else - { - printk("%s: " FILENAME_LINECODE - " can not be set while the interface is DOWN\n", - dev->name); - free_page((unsigned long)page); - return -EINVAL; - } - } - } - else if (!strcmp(entry->name, FILENAME_CLOCK_SOURCE)) - { - i = 0; - while (slicecom_clock_sources[i].value && - strncmp(slicecom_clock_sources[i].name, page, - strlen(slicecom_clock_sources[i].name))) - i++; - if (!slicecom_clock_sources[i].value) - { - printk("%s: Invalid " FILENAME_CLOCK_SOURCE " '%s'\n", dev->name, - page); - free_page((unsigned long)page); - return -EINVAL; - } - else - { /* - * Allow to set it only if interface is administrative UP, - * for the same reason as FILENAME_FRAMING - */ - if (netif_running(dev)) - slicecom_set_clock_source(hw->boardnum, - slicecom_clock_sources[i].value); - else - { - printk("%s: " FILENAME_CLOCK_SOURCE - " can not be set while the interface is DOWN\n", - dev->name); - free_page((unsigned long)page); - return -EINVAL; - } - } - } - else if (!strcmp(entry->name, FILENAME_LOOPBACK)) - { - i = 0; - while (slicecom_loopbacks[i].value && - strncmp(slicecom_loopbacks[i].name, page, - strlen(slicecom_loopbacks[i].name))) - i++; - if (!slicecom_loopbacks[i].value) - { - printk("%s: Invalid " FILENAME_LOOPBACK " '%s'\n", dev->name, page); - free_page((unsigned long)page); - return -EINVAL; - } - else - { /* - * Allow to set it only if interface is administrative UP, - * for the same reason as FILENAME_FRAMING - */ - if (netif_running(dev)) - slicecom_set_loopback(hw->boardnum, - slicecom_loopbacks[i].value); - else - { - printk("%s: " FILENAME_LOOPBACK - " can not be set while the interface is DOWN\n", - dev->name); - free_page((unsigned long)page); - return -EINVAL; - } - } - } - else if (!strcmp(entry->name, FILENAME_REG)) - { /* DEL: 'reg' csak tmp */ - char *p; - u32 *bar1 = board->bar1; - - reg = simple_strtoul(page, &p, 0); - reg_ertek = simple_strtoul(p + 1, NULL, 0); - - if (reg < 0x100) - { - printk("reg(0x%02x) := 0x%08x jiff: %lu\n", reg, reg_ertek, jiffies); - writel(reg_ertek, MUNICH_VIRT(reg >> 2)); - } - else - { - printk("reg(0x%02x) is 0x%08x jiff: %lu\n", reg - 0x100, - readl(MUNICH_VIRT((reg - 0x100) >> 2)), jiffies); - } - } - else if (!strcmp(entry->name, FILENAME_LBIREG)) - { /* DEL: 'lbireg' csak tmp */ - char *p; - u8 *lbi = board->lbi; - - lbireg = simple_strtoul(page, &p, 0); - lbireg_ertek = simple_strtoul(p + 1, NULL, 0); - - if (lbireg < 0x100) - { - printk("lbireg(0x%02x) := 0x%02x jiff: %lu\n", lbireg, - lbireg_ertek, jiffies); - writeb(lbireg_ertek, lbi + lbireg); - } - else - printk("lbireg(0x%02x) is 0x%02x jiff: %lu\n", lbireg - 0x100, - readb(lbi + lbireg - 0x100), jiffies); - } - else - { - printk(KERN_ERR "munich_write_proc: internal error, filename %s\n", - entry->name); - free_page((unsigned long)page); - return -EBADF; - } - - /* Don't forget to free the workspace */ - free_page((unsigned long)page); - return count; -} - -/* - * Boardtype init function. - * Called by the comx (upper) layer, when you set boardtype. - * Allocates resources associated to using munich board for this device, - * initializes ch_struct pointers etc. - * Returns 0 on success and standard error codes on error. - */ - -static int init_escape(struct comx_channel *ch) -{ - kfree(ch->HW_privdata); - return -EIO; -} - -static int BOARD_init(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - struct slicecom_privdata *hw; - struct proc_dir_entry *new_file; - - /* Alloc data for private structure */ - if ((ch->HW_privdata = - kmalloc(sizeof(struct slicecom_privdata), GFP_KERNEL)) == NULL) - return -ENOMEM; - - memset(hw = ch->HW_privdata, 0, sizeof(struct slicecom_privdata)); - - /* Register /proc files */ - if ((new_file = create_proc_entry(FILENAME_BOARDNUM, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - if (ch->hardware == &slicecomhw) - { - if ((new_file = create_proc_entry(FILENAME_TIMESLOTS, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_FRAMING, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_LINECODE, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_CLOCK_SOURCE, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_LOOPBACK, S_IFREG | 0644, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - } - - /* DEL: ez itt csak fejlesztesi celokra!! */ - if ((new_file = create_proc_entry(FILENAME_REG, S_IFREG | 0200, ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - /* DEL: ez itt csak fejlesztesi celokra!! */ - if ((new_file = create_proc_entry(FILENAME_LBIREG, S_IFREG | 0200, - ch->procdir)) == NULL) - return init_escape(ch); - new_file->data = (void *)new_file; - new_file->read_proc = &munich_read_proc; - new_file->write_proc = &munich_write_proc; -// new_file->proc_iops = &comx_normal_inode_ops; - new_file->nlink = 1; - - /* Fill in ch_struct hw specific pointers: */ - - ch->HW_txe = MUNICH_txe; - ch->HW_open = MUNICH_open; - ch->HW_close = MUNICH_close; - ch->HW_send_packet = MUNICH_send_packet; -#ifndef COMX_NEW - ch->HW_minden = MUNICH_minden; -#else - ch->HW_statistics = MUNICH_minden; -#endif - - hw->boardnum = SLICECOM_BOARDNUM_DEFAULT; - hw->timeslots = ch->hardware == &pcicomhw ? 0xffffffff : 2; - - /* O.K. Count one more user on this module */ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * Boardtype exit function. - * Called by the comx (upper) layer, when you clear boardtype from munich. - * Frees resources associated to using munich board for this device, - * resets ch_struct pointers etc. - */ -static int BOARD_exit(struct net_device *dev) -{ - struct comx_channel *ch = netdev_priv(dev); - - /* Free private data area */ -// board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); - - kfree(ch->HW_privdata); - /* Remove /proc files */ - remove_proc_entry(FILENAME_BOARDNUM, ch->procdir); - if (ch->hardware == &slicecomhw) - { - remove_proc_entry(FILENAME_TIMESLOTS, ch->procdir); - remove_proc_entry(FILENAME_FRAMING, ch->procdir); - remove_proc_entry(FILENAME_LINECODE, ch->procdir); - remove_proc_entry(FILENAME_CLOCK_SOURCE, ch->procdir); - remove_proc_entry(FILENAME_LOOPBACK, ch->procdir); - } - remove_proc_entry(FILENAME_REG, ch->procdir); - remove_proc_entry(FILENAME_LBIREG, ch->procdir); - - /* Minus one user for the module accounting */ - MOD_DEC_USE_COUNT; - return 0; -} - -static struct comx_hardware slicecomhw = -{ - "slicecom", -#ifdef COMX_NEW - VERSION, -#endif - BOARD_init, - BOARD_exit, - BOARD_dump, - NULL -}; - -static struct comx_hardware pcicomhw = -{ - "pcicom", -#ifdef COMX_NEW - VERSION, -#endif - BOARD_init, - BOARD_exit, - BOARD_dump, - NULL -}; - -/* Module management */ - -static int __init init_mister(void) -{ - printk(VERSIONSTR); - comx_register_hardware(&slicecomhw); - comx_register_hardware(&pcicomhw); - return munich_probe(); -} - -static void __exit cleanup_mister(void) -{ - int i; - - comx_unregister_hardware("slicecom"); - comx_unregister_hardware("pcicom"); - - for (i = 0; i < MAX_BOARDS; i++) - { - if (slicecom_boards[i].bar1) - iounmap((void *)slicecom_boards[i].bar1); - if (slicecom_boards[i].lbi) - iounmap((void *)slicecom_boards[i].lbi); - if (pcicom_boards[i].bar1) - iounmap((void *)pcicom_boards[i].bar1); - if (pcicom_boards[i].lbi) - iounmap((void *)pcicom_boards[i].lbi); - } -} - -module_init(init_mister); -module_exit(cleanup_mister); diff --git a/drivers/net/wan/comx-proto-fr.c b/drivers/net/wan/comx-proto-fr.c deleted file mode 100644 index c9551366b..000000000 --- a/drivers/net/wan/comx-proto-fr.c +++ /dev/null @@ -1,1014 +0,0 @@ -/* - * Frame-relay protocol module for the COMX driver - * for Linux 2.2.X - * - * Original author: Tivadar Szemethy - * Maintainer: Gergely Madarasz - * - * Copyright (C) 1998-1999 ITConsult-Pro Co. - * - * Contributors: - * Arnaldo Carvalho de Melo (0.73) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.70 (99/06/14): - * - cleaned up the source code a bit - * - ported back to kernel, now works as builtin code - * - * Version 0.71 (99/06/25): - * - use skb priorities and queues for sending keepalive - * - use device queues for slave->master data transmit - * - set IFF_RUNNING only line protocol up - * - fixes on slave device flags - * - * Version 0.72 (99/07/09): - * - handle slave tbusy with master tbusy (should be fixed) - * - fix the keepalive timer addition/deletion - * - * Version 0.73 (00/08/15) - * - resource release on failure at fr_master_init and - * fr_slave_init - */ - -#define VERSION "0.73" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "comx.h" -#include "comxhw.h" - -MODULE_AUTHOR("Author: Tivadar Szemethy "); -MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers" - "for Linux kernel 2.4.X"); -MODULE_LICENSE("GPL"); - -#define FRAD_UI 0x03 -#define NLPID_IP 0xcc -#define NLPID_Q933_LMI 0x08 -#define NLPID_CISCO_LMI 0x09 -#define Q933_ENQ 0x75 -#define Q933_LINESTAT 0x51 -#define Q933_COUNTERS 0x53 - -#define MAXALIVECNT 3 /* No. of failures */ - -struct fr_data { - u16 dlci; - struct net_device *master; - char keepa_pend; - char keepa_freq; - char keepalivecnt, keeploopcnt; - struct timer_list keepa_timer; - u8 local_cnt, remote_cnt; -}; - -static struct comx_protocol fr_master_protocol; -static struct comx_protocol fr_slave_protocol; -static struct comx_hardware fr_dlci; - -static void fr_keepalive_send(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct sk_buff *skb; - u8 *fr_packet; - - skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC); - - if(skb==NULL) - return; - - skb_reserve(skb, dev->hard_header_len); - - fr_packet=(u8*)skb_put(skb, 13); - - fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2; - fr_packet[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1 - fr_packet[2] = FRAD_UI; - fr_packet[3] = NLPID_Q933_LMI; - fr_packet[4] = 0; - fr_packet[5] = Q933_ENQ; - fr_packet[6] = Q933_LINESTAT; - fr_packet[7] = 0x01; - fr_packet[8] = 0x01; - fr_packet[9] = Q933_COUNTERS; - fr_packet[10] = 0x02; - fr_packet[11] = ++fr->local_cnt; - fr_packet[12] = fr->remote_cnt; - - skb->dev = dev; - skb->priority = TC_PRIO_CONTROL; - dev_queue_xmit(skb); -} - -static void fr_keepalive_timerfun(unsigned long d) -{ - struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct comx_channel *sch; - struct fr_data *sfr; - struct net_device *sdev; - - if (ch->init_status & LINE_OPEN) { - if (fr->keepalivecnt == MAXALIVECNT) { - comx_status(dev, ch->line_status & ~PROTO_UP); - dev->flags &= ~IFF_RUNNING; - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) - && (sfr->master == dev) && - (sdev->flags & IFF_UP)) { - sdev->flags &= ~IFF_RUNNING; - comx_status(sdev, - sch->line_status & ~PROTO_UP); - } - } - } - if (fr->keepalivecnt <= MAXALIVECNT) { - ++fr->keepalivecnt; - } - fr_keepalive_send(dev); - } - mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq); -} - -static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb, - u16 dlci, u8 nlpid) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct comx_channel *sch; - struct fr_data *sfr; - struct net_device *sdev; - - if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) { - return; - } - - fr->remote_cnt = skb->data[7]; - if (skb->data[8] == fr->local_cnt) { // keepalive UP! - fr->keepalivecnt = 0; - if ((ch->line_status & LINE_UP) && - !(ch->line_status & PROTO_UP)) { - comx_status(dev, ch->line_status |= PROTO_UP); - dev->flags |= IFF_RUNNING; - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) - && (sfr->master == dev) && - (sdev->flags & IFF_UP)) { - sdev->flags |= IFF_RUNNING; - comx_status(sdev, - sch->line_status | PROTO_UP); - } - } - } - } -} - -static void fr_set_keepalive(struct net_device *dev, int keepa) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - - if (!keepa && fr->keepa_freq) { // switch off - fr->keepa_freq = 0; - if (ch->line_status & LINE_UP) { - comx_status(dev, ch->line_status | PROTO_UP); - dev->flags |= IFF_RUNNING; - del_timer(&fr->keepa_timer); - } - return; - } - - if (keepa) { // bekapcs - if(fr->keepa_freq && (ch->line_status & LINE_UP)) { - del_timer(&fr->keepa_timer); - } - fr->keepa_freq = keepa; - fr->local_cnt = fr->remote_cnt = 0; - init_timer(&fr->keepa_timer); - fr->keepa_timer.expires = jiffies + HZ; - fr->keepa_timer.function = fr_keepalive_timerfun; - fr->keepa_timer.data = (unsigned long)dev; - ch->line_status &= ~(PROTO_UP | PROTO_LOOP); - dev->flags &= ~IFF_RUNNING; - comx_status(dev, ch->line_status); - if(ch->line_status & LINE_UP) { - add_timer(&fr->keepa_timer); - } - } -} - -static void fr_rx(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct net_device *sdev = dev; - struct comx_channel *sch; - struct fr_data *sfr; - u16 dlci; - u8 nlpid; - - if(skb->len <= 4 || skb->data[2] != FRAD_UI) { - kfree_skb(skb); - return; - } - - /* Itt majd ki kell talalni, melyik slave kapja a csomagot */ - dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4); - if ((nlpid = skb->data[3]) == 0) { // Optional padding - nlpid = skb->data[4]; - skb_pull(skb, 1); - } - skb_pull(skb, 4); /* DLCI and header throw away */ - - if (ch->debug_flags & DEBUG_COMX_DLCI) { - comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n", - dlci, nlpid); - comx_debug_skb(dev, skb, "Contents"); - } - - /* Megkeressuk, kihez tartozik */ - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && - (sfr->master == dev) && (sfr->dlci == dlci)) { - skb->dev = sdev; - if (ch->debug_flags & DEBUG_COMX_DLCI) { - comx_debug(dev, "Passing it to %s\n",sdev->name); - } - if (dev != sdev) { - sch->stats.rx_packets++; - sch->stats.rx_bytes += skb->len; - } - break; - } - } - switch(nlpid) { - case NLPID_IP: - skb->protocol = htons(ETH_P_IP); - skb->mac.raw = skb->data; - comx_rx(sdev, skb); - break; - case NLPID_Q933_LMI: - fr_rx_lmi(dev, skb, dlci, nlpid); - default: - kfree_skb(skb); - break; - } -} - -static int fr_tx(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct net_device *sdev; - struct comx_channel *sch; - struct fr_data *sfr; - int cnt = 1; - - /* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel, - es annal a slave-nel aki eppen kuldott. - Egy helyen akkor all, ha a master kuldott. - Ez megint jo lesz majd, ha utemezni akarunk */ - - /* This should be fixed, the slave tbusy should be set when - the masters queue is full and reset when not */ - - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && - (sfr->master == dev) && (netif_queue_stopped(sdev))) { - netif_wake_queue(sdev); - cnt++; - } - } - - netif_wake_queue(dev); - return 0; -} - -static void fr_status(struct net_device *dev, unsigned short status) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct net_device *sdev; - struct comx_channel *sch; - struct fr_data *sfr; - - if (status & LINE_UP) { - if (!fr->keepa_freq) { - status |= PROTO_UP; - } - } else { - status &= ~(PROTO_UP | PROTO_LOOP); - } - - if (dev == fr->master && fr->keepa_freq) { - if (status & LINE_UP) { - fr->keepa_timer.expires = jiffies + HZ; - add_timer(&fr->keepa_timer); - fr->keepalivecnt = MAXALIVECNT + 1; - fr->keeploopcnt = 0; - } else { - del_timer(&fr->keepa_timer); - } - } - - /* Itt a status valtozast vegig kell vinni az osszes slave-n */ - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) && (sfr->master == dev)) { - if(status & LINE_UP) { - netif_wake_queue(sdev); - } - comx_status(sdev, status); - if(status & (PROTO_UP | PROTO_LOOP)) { - dev->flags |= IFF_RUNNING; - } else { - dev->flags &= ~IFF_RUNNING; - } - } - } -} - -static int fr_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct proc_dir_entry *comxdir = ch->procdir; - struct comx_channel *mch; - - if (!(ch->init_status & HW_OPEN)) { - return -ENODEV; - } - - if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) || - (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) { - printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n"); - return -EINVAL; - } - - if (!fr->master) { - return -ENODEV; - } - mch = fr->master->priv; - if (fr->master != dev && (!(mch->init_status & LINE_OPEN) - || (mch->protocol != &fr_master_protocol))) { - printk(KERN_ERR "Master %s is inactive, or incorrectly set up, " - "unable to open %s\n", fr->master->name, dev->name); - return -ENODEV; - } - - ch->init_status |= LINE_OPEN; - ch->line_status &= ~(PROTO_UP | PROTO_LOOP); - dev->flags &= ~IFF_RUNNING; - - if (fr->master == dev) { - if (fr->keepa_freq) { - fr->keepa_timer.function = fr_keepalive_timerfun; - fr->keepa_timer.data = (unsigned long)dev; - add_timer(&fr->keepa_timer); - } else { - if (ch->line_status & LINE_UP) { - ch->line_status |= PROTO_UP; - dev->flags |= IFF_RUNNING; - } - } - } else { - ch->line_status = mch->line_status; - if(fr->master->flags & IFF_RUNNING) { - dev->flags |= IFF_RUNNING; - } - } - - for (; comxdir ; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_DLCI) == 0 || - strcmp(comxdir->name, FILENAME_MASTER) == 0 || - strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) { - comxdir->mode = S_IFREG | 0444; - } - } -// comx_status(dev, ch->line_status); - return 0; -} - -static int fr_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct proc_dir_entry *comxdir = ch->procdir; - - if (fr->master == dev) { // Ha master - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct net_device *sdev = dev; - struct comx_channel *sch; - struct fr_data *sfr; - - if (!(ch->init_status & HW_OPEN)) { - return -ENODEV; - } - - if (fr->keepa_freq) { - del_timer(&fr->keepa_timer); - } - - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) && - (sfr->master == dev) && - (sch->init_status & LINE_OPEN)) { - dev_close(sdev); - } - } - } - - ch->init_status &= ~LINE_OPEN; - ch->line_status &= ~(PROTO_UP | PROTO_LOOP); - dev->flags &= ~IFF_RUNNING; - - for (; comxdir ; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_DLCI) == 0 || - strcmp(comxdir->name, FILENAME_MASTER) == 0 || - strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) { - comxdir->mode = S_IFREG | 0444; - } - } - - return 0; -} - -static int fr_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct comx_channel *sch, *mch; - struct fr_data *fr = ch->LINE_privdata; - struct fr_data *sfr; - struct net_device *sdev; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - - if (!fr->master) { - printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name); - return 0; - } - - mch = fr->master->priv; - - /* Ennek majd a slave utemezeskor lesz igazan jelentosege */ - if (ch->debug_flags & DEBUG_COMX_DLCI) { - comx_debug_skb(dev, skb, "Sending frame"); - } - - if (dev != fr->master) { - struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); - if (!newskb) - return -ENOMEM; - newskb->dev=fr->master; - dev_queue_xmit(newskb); - ch->stats.tx_bytes += skb->len; - ch->stats.tx_packets++; - dev_kfree_skb(skb); - } else { - netif_stop_queue(dev); - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && - (sfr->master == dev) && (netif_queue_stopped(sdev))) { - netif_stop_queue(sdev); - } - } - - switch(mch->HW_send_packet(dev, skb)) { - case FRAME_QUEUED: - netif_wake_queue(dev); - break; - case FRAME_ACCEPTED: - case FRAME_DROPPED: - break; - case FRAME_ERROR: - printk(KERN_ERR "%s: Transmit frame error (len %d)\n", - dev->name, skb->len); - break; - } - } - return 0; -} - -static int fr_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - - skb_push(skb, dev->hard_header_len); - /* Put in DLCI */ - skb->data[0] = (fr->dlci & (1024 - 15)) >> 2; - skb->data[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1 - skb->data[2] = FRAD_UI; - skb->data[3] = NLPID_IP; - - return dev->hard_header_len; -} - -static int fr_statistics(struct net_device *dev, char *page) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - int len = 0; - - if (fr->master == dev) { - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - struct net_device *sdev; - struct comx_channel *sch; - struct fr_data *sfr; - int slaves = 0; - - len += sprintf(page + len, - "This is a Frame Relay master device\nSlaves: "); - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) && - (sfr->master == dev) && (sdev != dev)) { - slaves++; - len += sprintf(page + len, "%s ", sdev->name); - } - } - len += sprintf(page + len, "%s\n", slaves ? "" : "(none)"); - if (fr->keepa_freq) { - len += sprintf(page + len, "Line keepalive (value %d) " - "status %s [%d]\n", fr->keepa_freq, - ch->line_status & PROTO_LOOP ? "LOOP" : - ch->line_status & PROTO_UP ? "UP" : "DOWN", - fr->keepalivecnt); - } else { - len += sprintf(page + len, "Line keepalive protocol " - "is not set\n"); - } - } else { // if slave - len += sprintf(page + len, - "This is a Frame Relay slave device, master: %s\n", - fr->master ? fr->master->name : "(not set)"); - } - return len; -} - -static int fr_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; - struct fr_data *fr = NULL; - int len = 0; - - if (ch) { - fr = ch->LINE_privdata; - } - - if (strcmp(file->name, FILENAME_DLCI) == 0) { - len = sprintf(page, "%04d\n", fr->dlci); - } else if (strcmp(file->name, FILENAME_MASTER) == 0) { - len = sprintf(page, "%-9s\n", fr->master ? fr->master->name : - "(none)"); - } else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) { - len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq) - : sprintf(page, "off\n"); - } else { - printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name); - return -EBADF; - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) *eof = 1; - return min_t(int, count, len - off); -} - -static int fr_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = entry->parent->data; - struct comx_channel *ch = dev->priv; - struct fr_data *fr = NULL; - char *page; - - if (ch) { - fr = ch->LINE_privdata; - } - - if (!(page = (char *)__get_free_page(GFP_KERNEL))) { - return -ENOMEM; - } - - if (copy_from_user(page, buffer, count)) { - free_page((unsigned long)page); - return -EFAULT; - } - if (*(page + count - 1) == '\n') { - *(page + count - 1) = 0; - } - - if (strcmp(entry->name, FILENAME_DLCI) == 0) { - u16 dlci_new = simple_strtoul(page, NULL, 10); - - if (dlci_new > 1023) { - printk(KERN_ERR "Invalid DLCI value\n"); - } - else fr->dlci = dlci_new; - } else if (strcmp(entry->name, FILENAME_MASTER) == 0) { - struct net_device *new_master = dev_get_by_name(page); - - if (new_master && new_master->type == ARPHRD_FRAD) { - struct comx_channel *sch = new_master->priv; - struct fr_data *sfr = sch->LINE_privdata; - - if (sfr && sfr->master == new_master) { - if(fr->master) - dev_put(fr->master); - fr->master = new_master; - /* Megorokli a master statuszat */ - ch->line_status = sch->line_status; - } - } - } else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) { - int keepa_new = -1; - - if (strcmp(page, KEEPALIVE_OFF) == 0) { - keepa_new = 0; - } else { - keepa_new = simple_strtoul(page, NULL, 10); - } - - if (keepa_new < 0 || keepa_new > 100) { - printk(KERN_ERR "invalid keepalive\n"); - } else { - if (fr->keepa_freq && keepa_new != fr->keepa_freq) { - fr_set_keepalive(dev, 0); - } - if (keepa_new) { - fr_set_keepalive(dev, keepa_new); - } - } - } else { - printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", - entry->name); - count = -EBADF; - } - - free_page((unsigned long)page); - return count; -} - -static int fr_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - struct net_device *sdev = dev; - struct comx_channel *sch; - struct fr_data *sfr; - struct proc_dir_entry *dir = ch->procdir->parent->subdir; - - /* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */ - if (fr->master && fr->master == dev) { - for (; dir ; dir = dir->next) { - if(!S_ISDIR(dir->mode)) { - continue; - } - if ((sdev = dir->data) && (sch = sdev->priv) && - (sdev->type == ARPHRD_DLCI) && - (sfr = sch->LINE_privdata) && (sfr->master == dev)) { - dev_close(sdev); - sfr->master = NULL; - } - } - } - dev->flags = 0; - dev->type = 0; - dev->mtu = 0; - dev->hard_header_len = 0; - - ch->LINE_rx = NULL; - ch->LINE_tx = NULL; - ch->LINE_status = NULL; - ch->LINE_open = NULL; - ch->LINE_close = NULL; - ch->LINE_xmit = NULL; - ch->LINE_header = NULL; - ch->LINE_rebuild_header = NULL; - ch->LINE_statistics = NULL; - - ch->LINE_status = 0; - - if (fr->master != dev) { // if not master, remove dlci - if(fr->master) - dev_put(fr->master); - remove_proc_entry(FILENAME_DLCI, ch->procdir); - remove_proc_entry(FILENAME_MASTER, ch->procdir); - } else { - if (fr->keepa_freq) { - fr_set_keepalive(dev, 0); - } - remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir); - remove_proc_entry(FILENAME_DLCI, ch->procdir); - } - - kfree(fr); - ch->LINE_privdata = NULL; - - MOD_DEC_USE_COUNT; - return 0; -} - -static int fr_master_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr; - struct proc_dir_entry *new_file; - - if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(fr, 0, sizeof(struct fr_data)); - fr->master = dev; // this means master - fr->dlci = 0; // let's say default - - dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->type = ARPHRD_FRAD; - dev->mtu = 1500; - dev->hard_header_len = 4; - dev->addr_len = 0; - - ch->LINE_rx = fr_rx; - ch->LINE_tx = fr_tx; - ch->LINE_status = fr_status; - ch->LINE_open = fr_open; - ch->LINE_close = fr_close; - ch->LINE_xmit = fr_xmit; - ch->LINE_header = fr_header; - ch->LINE_rebuild_header = NULL; - ch->LINE_statistics = fr_statistics; - - if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_LINE_privdata; - } - new_file->data = (void *)new_file; - new_file->read_proc = &fr_read_proc; - new_file->write_proc = &fr_write_proc; - new_file->size = 5; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_dlci; - } - new_file->data = (void *)new_file; - new_file->read_proc = &fr_read_proc; - new_file->write_proc = &fr_write_proc; - new_file->size = 4; - new_file->nlink = 1; - - fr_set_keepalive(dev, 0); - - MOD_INC_USE_COUNT; - return 0; -cleanup_filename_dlci: - remove_proc_entry(FILENAME_DLCI, ch->procdir); -cleanup_LINE_privdata: - kfree(fr); - return -EIO; -} - -static int fr_slave_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr; - struct proc_dir_entry *new_file; - - if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), - GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(fr, 0, sizeof(struct fr_data)); - - dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->type = ARPHRD_DLCI; - dev->mtu = 1500; - dev->hard_header_len = 4; - dev->addr_len = 0; - - ch->LINE_rx = fr_rx; - ch->LINE_tx = fr_tx; - ch->LINE_status = fr_status; - ch->LINE_open = fr_open; - ch->LINE_close = fr_close; - ch->LINE_xmit = fr_xmit; - ch->LINE_header = fr_header; - ch->LINE_rebuild_header = NULL; - ch->LINE_statistics = fr_statistics; - - if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_LINE_privdata; - } - - new_file->data = (void *)new_file; - new_file->read_proc = &fr_read_proc; - new_file->write_proc = &fr_write_proc; - new_file->size = 5; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, - ch->procdir)) == NULL) { - goto cleanup_filename_dlci; - } - new_file->data = (void *)new_file; - new_file->read_proc = &fr_read_proc; - new_file->write_proc = &fr_write_proc; - new_file->size = 10; - new_file->nlink = 1; - MOD_INC_USE_COUNT; - return 0; -cleanup_filename_dlci: - remove_proc_entry(FILENAME_DLCI, ch->procdir); -cleanup_LINE_privdata: - kfree(fr); - return -EIO; -} - -static int dlci_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - ch->init_status |= HW_OPEN; - - MOD_INC_USE_COUNT; - return 0; -} - -static int dlci_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - ch->init_status &= ~HW_OPEN; - - MOD_DEC_USE_COUNT; - return 0; -} - -static int dlci_txe(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct fr_data *fr = ch->LINE_privdata; - - if (!fr->master) { - return 0; - } - - ch = fr->master->priv; - fr = ch->LINE_privdata; - return ch->HW_txe(fr->master); -} - -static int dlci_statistics(struct net_device *dev, char *page) -{ - return 0; -} - -static int dlci_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - ch->HW_open = dlci_open; - ch->HW_close = dlci_close; - ch->HW_txe = dlci_txe; - ch->HW_statistics = dlci_statistics; - - /* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */ - - MOD_INC_USE_COUNT; - return 0; -} - -static int dlci_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - ch->HW_open = NULL; - ch->HW_close = NULL; - ch->HW_txe = NULL; - ch->HW_statistics = NULL; - - MOD_DEC_USE_COUNT; - return 0; -} - -static int dlci_dump(struct net_device *dev) -{ - printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name); - return -1; -} - -static struct comx_protocol fr_master_protocol = { - .name = "frad", - .version = VERSION, - .encap_type = ARPHRD_FRAD, - .line_init = fr_master_init, - .line_exit = fr_exit, -}; - -static struct comx_protocol fr_slave_protocol = { - .name = "ietf-ip", - .version = VERSION, - .encap_type = ARPHRD_DLCI, - .line_init = fr_slave_init, - .line_exit = fr_exit, -}; - -static struct comx_hardware fr_dlci = { - .name = "dlci", - .version = VERSION, - .hw_init = dlci_init, - .hw_exit = dlci_exit, - .hw_dump = dlci_dump, -}; - -static int __init comx_proto_fr_init(void) -{ - int ret; - - if ((ret = comx_register_hardware(&fr_dlci))) { - return ret; - } - if ((ret = comx_register_protocol(&fr_master_protocol))) { - return ret; - } - return comx_register_protocol(&fr_slave_protocol); -} - -static void __exit comx_proto_fr_exit(void) -{ - comx_unregister_hardware(fr_dlci.name); - comx_unregister_protocol(fr_master_protocol.name); - comx_unregister_protocol(fr_slave_protocol.name); -} - -module_init(comx_proto_fr_init); -module_exit(comx_proto_fr_exit); diff --git a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c deleted file mode 100644 index b203ff689..000000000 --- a/drivers/net/wan/comx-proto-lapb.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * LAPB protocol module for the COMX driver - * for Linux kernel 2.2.X - * - * Original author: Tivadar Szemethy - * Maintainer: Gergely Madarasz - * - * Copyright (C) 1997-1999 (C) ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.80 (99/06/14): - * - cleaned up the source code a bit - * - ported back to kernel, now works as non-module - * - * Changed (00/10/29, Henner Eisen): - * - comx_rx() / comxlapb_data_indication() return status. - * - */ - -#define VERSION "0.80" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "comx.h" -#include "comxhw.h" - -static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode, - int size, struct proc_dir_entry *dir); - -static void comxlapb_rx(struct net_device *dev, struct sk_buff *skb) -{ - if (!dev || !dev->priv) { - dev_kfree_skb(skb); - } else { - lapb_data_received(dev, skb); - } -} - -static int comxlapb_tx(struct net_device *dev) -{ - netif_wake_queue(dev); - return 0; -} - -static int comxlapb_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return dev->hard_header_len; -} - -static void comxlapb_status(struct net_device *dev, unsigned short status) -{ - struct comx_channel *ch; - - if (!dev || !(ch = dev->priv)) { - return; - } - if (status & LINE_UP) { - netif_wake_queue(dev); - } - comx_status(dev, status); -} - -static int comxlapb_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - int err = 0; - - if (!(ch->init_status & HW_OPEN)) { - return -ENODEV; - } - - err = lapb_connect_request(dev); - - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(dev, "%s: lapb opened, error code: %d\n", - dev->name, err); - } - - if (!err) { - ch->init_status |= LINE_OPEN; - MOD_INC_USE_COUNT; - } - return err; -} - -static int comxlapb_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - if (!(ch->init_status & HW_OPEN)) { - return -ENODEV; - } - - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(dev, "%s: lapb closed\n", dev->name); - } - - lapb_disconnect_request(dev); - - ch->init_status &= ~LINE_OPEN; - ch->line_status &= ~PROTO_UP; - MOD_DEC_USE_COUNT; - return 0; -} - -static int comxlapb_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct sk_buff *skb2; - - if (!dev || !(ch = dev->priv) || !(dev->flags & (IFF_UP | IFF_RUNNING))) { - return -ENODEV; - } - - if (dev->type == ARPHRD_X25) { // first byte tells what to do - switch(skb->data[0]) { - case 0x00: - break; // transmit - case 0x01: - lapb_connect_request(dev); - kfree_skb(skb); - return 0; - case 0x02: - lapb_disconnect_request(dev); - default: - kfree_skb(skb); - return 0; - } - skb_pull(skb,1); - } - - netif_stop_queue(dev); - - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { - lapb_data_request(dev, skb2); - } - - return FRAME_ACCEPTED; -} - -static int comxlapb_statistics(struct net_device *dev, char *page) -{ - struct lapb_parms_struct parms; - int len = 0; - - len += sprintf(page + len, "Line status: "); - if (lapb_getparms(dev, &parms) != LAPB_OK) { - len += sprintf(page + len, "not initialized\n"); - return len; - } - len += sprintf(page + len, "%s (%s), T1: %d/%d, T2: %d/%d, N2: %d/%d, " - "window: %d\n", parms.mode & LAPB_DCE ? "DCE" : "DTE", - parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD", - parms.t1timer, parms.t1, parms.t2timer, parms.t2, - parms.n2count, parms.n2, parms.window); - - return len; -} - -static int comxlapb_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct lapb_parms_struct parms; - int len = 0; - - if (lapb_getparms(dev, &parms)) { - return -ENODEV; - } - - if (strcmp(file->name, FILENAME_T1) == 0) { - len += sprintf(page + len, "%02u / %02u\n", - parms.t1timer, parms.t1); - } else if (strcmp(file->name, FILENAME_T2) == 0) { - len += sprintf(page + len, "%02u / %02u\n", - parms.t2timer, parms.t2); - } else if (strcmp(file->name, FILENAME_N2) == 0) { - len += sprintf(page + len, "%02u / %02u\n", - parms.n2count, parms.n2); - } else if (strcmp(file->name, FILENAME_WINDOW) == 0) { - len += sprintf(page + len, "%u\n", parms.window); - } else if (strcmp(file->name, FILENAME_MODE) == 0) { - len += sprintf(page + len, "%s, %s\n", - parms.mode & LAPB_DCE ? "DCE" : "DTE", - parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD"); - } else { - printk(KERN_ERR "comxlapb: internal error, filename %s\n", file->name); - return -EBADF; - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) { - *eof = 1; - } - return min_t(int, count, len - off); -} - -static int comxlapb_write_proc(struct file *file, const char *buffer, - u_long count, void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = entry->parent->data; - struct lapb_parms_struct parms; - unsigned long parm; - char *page; - - if (lapb_getparms(dev, &parms)) { - return -ENODEV; - } - - if (!(page = (char *)__get_free_page(GFP_KERNEL))) { - return -ENOMEM; - } - - if (copy_from_user(page, buffer, count)) { - free_page((unsigned long)page); - return -EFAULT; - } - if (*(page + count - 1) == '\n') { - *(page + count - 1) = 0; - } - - if (strcmp(entry->name, FILENAME_T1) == 0) { - parm=simple_strtoul(page,NULL,10); - if (parm > 0 && parm < 100) { - parms.t1=parm; - lapb_setparms(dev, &parms); - } - } else if (strcmp(entry->name, FILENAME_T2) == 0) { - parm=simple_strtoul(page, NULL, 10); - if (parm > 0 && parm < 100) { - parms.t2=parm; - lapb_setparms(dev, &parms); - } - } else if (strcmp(entry->name, FILENAME_N2) == 0) { - parm=simple_strtoul(page, NULL, 10); - if (parm > 0 && parm < 100) { - parms.n2=parm; - lapb_setparms(dev, &parms); - } - } else if (strcmp(entry->name, FILENAME_WINDOW) == 0) { - parms.window = simple_strtoul(page, NULL, 10); - lapb_setparms(dev, &parms); - } else if (strcmp(entry->name, FILENAME_MODE) == 0) { - if (comx_strcasecmp(page, "dte") == 0) { - parms.mode &= ~(LAPB_DCE | LAPB_DTE); - parms.mode |= LAPB_DTE; - } else if (comx_strcasecmp(page, "dce") == 0) { - parms.mode &= ~(LAPB_DTE | LAPB_DCE); - parms.mode |= LAPB_DCE; - } else if (comx_strcasecmp(page, "std") == 0 || - comx_strcasecmp(page, "standard") == 0) { - parms.mode &= ~LAPB_EXTENDED; - parms.mode |= LAPB_STANDARD; - } else if (comx_strcasecmp(page, "ext") == 0 || - comx_strcasecmp(page, "extended") == 0) { - parms.mode &= ~LAPB_STANDARD; - parms.mode |= LAPB_EXTENDED; - } - lapb_setparms(dev, &parms); - } else { - printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n", - entry->name); - return -EBADF; - } - - free_page((unsigned long)page); - return count; -} - -static void comxlapb_connected(struct net_device *dev, int reason) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *comxdir = ch->procdir->subdir; - - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(ch->dev, "%s: lapb connected, reason: %d\n", - ch->dev->name, reason); - } - - if (ch->dev->type == ARPHRD_X25) { - unsigned char *p; - struct sk_buff *skb; - - if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "comxlapb: out of memory!\n"); - return; - } - p = skb_put(skb,1); - *p = 0x01; // link established - skb->dev = ch->dev; - skb->protocol = htons(ETH_P_X25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); - ch->dev->last_rx = jiffies; - } - - for (; comxdir; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_MODE) == 0) { - comxdir->mode = S_IFREG | 0444; - } - } - - - ch->line_status |= PROTO_UP; - comx_status(ch->dev, ch->line_status); -} - -static void comxlapb_disconnected(struct net_device *dev, int reason) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *comxdir = ch->procdir->subdir; - - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(ch->dev, "%s: lapb disconnected, reason: %d\n", - ch->dev->name, reason); - } - - if (ch->dev->type == ARPHRD_X25) { - unsigned char *p; - struct sk_buff *skb; - - if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "comxlapb: out of memory!\n"); - return; - } - p = skb_put(skb,1); - *p = 0x02; // link disconnected - skb->dev = ch->dev; - skb->protocol = htons(ETH_P_X25); - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - - netif_rx(skb); - ch->dev->last_rx = jiffies; - } - - for (; comxdir; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_MODE) == 0) { - comxdir->mode = S_IFREG | 0644; - } - } - - ch->line_status &= ~PROTO_UP; - comx_status(ch->dev, ch->line_status); -} - -static int comxlapb_data_indication(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = dev->priv; - - if (ch->dev->type == ARPHRD_X25) { - skb_push(skb, 1); - - if (skb_cow(skb, 1)) - return NET_RX_DROP; - - skb->data[0] = 0; // indicate data for X25 - skb->protocol = htons(ETH_P_X25); - } else { - skb->protocol = htons(ETH_P_IP); - } - - skb->dev = ch->dev; - skb->mac.raw = skb->data; - return comx_rx(ch->dev, skb); -} - -static void comxlapb_data_transmit(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = dev->priv; - - if (ch->HW_send_packet) { - ch->HW_send_packet(ch->dev, skb); - } -} - -static int comxlapb_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - dev->flags = 0; - dev->type = 0; - dev->mtu = 0; - dev->hard_header_len = 0; - - ch->LINE_rx = NULL; - ch->LINE_tx = NULL; - ch->LINE_status = NULL; - ch->LINE_open = NULL; - ch->LINE_close = NULL; - ch->LINE_xmit = NULL; - ch->LINE_header = NULL; - ch->LINE_statistics = NULL; - - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(dev, "%s: unregistering lapb\n", dev->name); - } - lapb_unregister(dev); - - remove_proc_entry(FILENAME_T1, ch->procdir); - remove_proc_entry(FILENAME_T2, ch->procdir); - remove_proc_entry(FILENAME_N2, ch->procdir); - remove_proc_entry(FILENAME_MODE, ch->procdir); - remove_proc_entry(FILENAME_WINDOW, ch->procdir); - - MOD_DEC_USE_COUNT; - return 0; -} - -static int comxlapb_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct lapb_register_struct lapbreg; - - dev->mtu = 1500; - dev->hard_header_len = 4; - dev->addr_len = 0; - - ch->LINE_rx = comxlapb_rx; - ch->LINE_tx = comxlapb_tx; - ch->LINE_status = comxlapb_status; - ch->LINE_open = comxlapb_open; - ch->LINE_close = comxlapb_close; - ch->LINE_xmit = comxlapb_xmit; - ch->LINE_header = comxlapb_header; - ch->LINE_statistics = comxlapb_statistics; - - lapbreg.connect_confirmation = comxlapb_connected; - lapbreg.connect_indication = comxlapb_connected; - lapbreg.disconnect_confirmation = comxlapb_disconnected; - lapbreg.disconnect_indication = comxlapb_disconnected; - lapbreg.data_indication = comxlapb_data_indication; - lapbreg.data_transmit = comxlapb_data_transmit; - if (lapb_register(dev, &lapbreg)) { - return -ENOMEM; - } - if (ch->debug_flags & DEBUG_COMX_LAPB) { - comx_debug(dev, "%s: lapb registered\n", dev->name); - } - - if (!create_comxlapb_proc_entry(FILENAME_T1, 0644, 8, ch->procdir)) { - return -ENOMEM; - } - if (!create_comxlapb_proc_entry(FILENAME_T2, 0644, 8, ch->procdir)) { - return -ENOMEM; - } - if (!create_comxlapb_proc_entry(FILENAME_N2, 0644, 8, ch->procdir)) { - return -ENOMEM; - } - if (!create_comxlapb_proc_entry(FILENAME_MODE, 0644, 14, ch->procdir)) { - return -ENOMEM; - } - if (!create_comxlapb_proc_entry(FILENAME_WINDOW, 0644, 0, ch->procdir)) { - return -ENOMEM; - } - - MOD_INC_USE_COUNT; - return 0; -} - -static int comxlapb_init_lapb(struct net_device *dev) -{ - dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->type = ARPHRD_LAPB; - - return(comxlapb_init(dev)); -} - -static int comxlapb_init_x25(struct net_device *dev) -{ - dev->flags = IFF_NOARP; - dev->type = ARPHRD_X25; - - return(comxlapb_init(dev)); -} - -static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode, - int size, struct proc_dir_entry *dir) -{ - struct proc_dir_entry *new_file; - - if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) { - new_file->data = (void *)new_file; - new_file->read_proc = &comxlapb_read_proc; - new_file->write_proc = &comxlapb_write_proc; - new_file->size = size; - new_file->nlink = 1; - } - return(new_file); -} - -static struct comx_protocol comxlapb_protocol = { - "lapb", - VERSION, - ARPHRD_LAPB, - comxlapb_init_lapb, - comxlapb_exit, - NULL -}; - -static struct comx_protocol comx25_protocol = { - "x25", - VERSION, - ARPHRD_X25, - comxlapb_init_x25, - comxlapb_exit, - NULL -}; - -static int __init comx_proto_lapb_init(void) -{ - int ret; - - if ((ret = comx_register_protocol(&comxlapb_protocol)) != 0) { - return ret; - } - return comx_register_protocol(&comx25_protocol); -} - -static void __exit comx_proto_lapb_exit(void) -{ - comx_unregister_protocol(comxlapb_protocol.name); - comx_unregister_protocol(comx25_protocol.name); -} - -module_init(comx_proto_lapb_init); -module_exit(comx_proto_lapb_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/comx-proto-ppp.c b/drivers/net/wan/comx-proto-ppp.c deleted file mode 100644 index 3f4501014..000000000 --- a/drivers/net/wan/comx-proto-ppp.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Synchronous PPP / Cisco-HDLC driver for the COMX boards - * - * Author: Gergely Madarasz - * - * based on skeleton code by Tivadar Szemethy - * - * Copyright (C) 1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * Version 0.10 (99/06/10): - * - written the first code :) - * - * Version 0.20 (99/06/16): - * - added hdlc protocol - * - protocol up is IFF_RUNNING - * - * Version 0.21 (99/07/15): - * - some small fixes with the line status - * - * Version 0.22 (99/08/05): - * - don't test IFF_RUNNING but the pp_link_state of the sppp - * - * Version 0.23 (99/12/02): - * - tbusy fixes - * - */ - -#define VERSION "0.23" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "comx.h" - -MODULE_AUTHOR("Author: Gergely Madarasz "); -MODULE_DESCRIPTION("Cisco-HDLC / Synchronous PPP driver for the COMX sync serial boards"); -MODULE_LICENSE("GPL"); - -static struct comx_protocol syncppp_protocol; -static struct comx_protocol hdlc_protocol; - -struct syncppp_data { - struct timer_list status_timer; -}; - -static void syncppp_status_timerfun(unsigned long d) { - struct net_device *dev=(struct net_device *)d; - struct comx_channel *ch=dev->priv; - struct syncppp_data *spch=ch->LINE_privdata; - struct sppp *sp = (struct sppp *)sppp_of(dev); - - if(!(ch->line_status & PROTO_UP) && - (sp->pp_link_state==SPPP_LINK_UP)) { - comx_status(dev, ch->line_status | PROTO_UP); - } - if((ch->line_status & PROTO_UP) && - (sp->pp_link_state==SPPP_LINK_DOWN)) { - comx_status(dev, ch->line_status & ~PROTO_UP); - } - mod_timer(&spch->status_timer,jiffies + HZ*3); -} - -static int syncppp_tx(struct net_device *dev) -{ - struct comx_channel *ch=dev->priv; - - if(ch->line_status & LINE_UP) { - netif_wake_queue(dev); - } - return 0; -} - -static void syncppp_status(struct net_device *dev, unsigned short status) -{ - status &= ~(PROTO_UP | PROTO_LOOP); - if(status & LINE_UP) { - netif_wake_queue(dev); - sppp_open(dev); - } else { - /* Line went down */ - netif_stop_queue(dev); - sppp_close(dev); - } - comx_status(dev, status); -} - -static int syncppp_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct syncppp_data *spch = ch->LINE_privdata; - - if (!(ch->init_status & HW_OPEN)) return -ENODEV; - - ch->init_status |= LINE_OPEN; - ch->line_status &= ~(PROTO_UP | PROTO_LOOP); - - if(ch->line_status & LINE_UP) { - sppp_open(dev); - } - - init_timer(&spch->status_timer); - spch->status_timer.function=syncppp_status_timerfun; - spch->status_timer.data=(unsigned long)dev; - spch->status_timer.expires=jiffies + HZ*3; - add_timer(&spch->status_timer); - - return 0; -} - -static int syncppp_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct syncppp_data *spch = ch->LINE_privdata; - - if (!(ch->init_status & HW_OPEN)) return -ENODEV; - del_timer(&spch->status_timer); - - sppp_close(dev); - - ch->init_status &= ~LINE_OPEN; - ch->line_status &= ~(PROTO_UP | PROTO_LOOP); - - return 0; -} - -static int syncppp_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - netif_stop_queue(dev); - switch(ch->HW_send_packet(dev, skb)) { - case FRAME_QUEUED: - netif_wake_queue(dev); - break; - case FRAME_ACCEPTED: - case FRAME_DROPPED: - break; - case FRAME_ERROR: - printk(KERN_ERR "%s: Transmit frame error (len %d)\n", - dev->name, skb->len); - break; - } - return 0; -} - - -static int syncppp_statistics(struct net_device *dev, char *page) -{ - int len = 0; - - len += sprintf(page + len, " "); - return len; -} - - -static int syncppp_exit(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - sppp_detach(dev); - - dev->flags = 0; - dev->type = 0; - dev->mtu = 0; - - ch->LINE_rx = NULL; - ch->LINE_tx = NULL; - ch->LINE_status = NULL; - ch->LINE_open = NULL; - ch->LINE_close = NULL; - ch->LINE_xmit = NULL; - ch->LINE_header = NULL; - ch->LINE_rebuild_header = NULL; - ch->LINE_statistics = NULL; - - kfree(ch->LINE_privdata); - ch->LINE_privdata = NULL; - - MOD_DEC_USE_COUNT; - return 0; -} - -static int syncppp_init(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct ppp_device *pppdev = (struct ppp_device *)ch->if_ptr; - - ch->LINE_privdata = kmalloc(sizeof(struct syncppp_data), GFP_KERNEL); - if (!ch->LINE_privdata) - return -ENOMEM; - - pppdev->dev = dev; - sppp_attach(pppdev); - - if(ch->protocol == &hdlc_protocol) { - pppdev->sppp.pp_flags |= PP_CISCO; - dev->type = ARPHRD_HDLC; - } else { - pppdev->sppp.pp_flags &= ~PP_CISCO; - dev->type = ARPHRD_PPP; - } - - ch->LINE_rx = sppp_input; - ch->LINE_tx = syncppp_tx; - ch->LINE_status = syncppp_status; - ch->LINE_open = syncppp_open; - ch->LINE_close = syncppp_close; - ch->LINE_xmit = syncppp_xmit; - ch->LINE_header = NULL; - ch->LINE_statistics = syncppp_statistics; - - - MOD_INC_USE_COUNT; - return 0; -} - -static struct comx_protocol syncppp_protocol = { - "ppp", - VERSION, - ARPHRD_PPP, - syncppp_init, - syncppp_exit, - NULL -}; - -static struct comx_protocol hdlc_protocol = { - "hdlc", - VERSION, - ARPHRD_PPP, - syncppp_init, - syncppp_exit, - NULL -}; - -static int __init comx_proto_ppp_init(void) -{ - int ret; - - ret = comx_register_protocol(&hdlc_protocol); - if (!ret) { - ret = comx_register_protocol(&syncppp_protocol); - if (ret) - comx_unregister_protocol(hdlc_protocol.name); - } - return ret; -} - -static void __exit comx_proto_ppp_exit(void) -{ - comx_unregister_protocol(syncppp_protocol.name); - comx_unregister_protocol(hdlc_protocol.name); -} - -module_init(comx_proto_ppp_init); -module_exit(comx_proto_ppp_exit); diff --git a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c deleted file mode 100644 index 6c0e3fcd2..000000000 --- a/drivers/net/wan/comx.c +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * Device driver framework for the COMX line of synchronous serial boards - * - * for Linux kernel 2.2.X / 2.4.X - * - * Original authors: Arpad Bakay , - * Peter Bajan , - * Previous maintainer: Tivadar Szemethy - * Current maintainer: Gergely Madarasz - * - * Copyright (C) 1995-1999 ITConsult-Pro Co. - * - * Contributors: - * Arnaldo Carvalho de Melo (0.85) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.80 (99/06/11): - * - clean up source code (playing a bit of indent) - * - port back to kernel, add support for non-module versions - * - add support for board resets when channel protocol is down - * - reset the device structure after protocol exit - * the syncppp driver needs it - * - add support for /proc/comx/protocols and - * /proc/comx/boardtypes - * - * Version 0.81 (99/06/21): - * - comment out the board reset support code, the locomx - * driver seems not buggy now - * - printk() levels fixed - * - * Version 0.82 (99/07/08): - * - Handle stats correctly if the lowlevel driver is - * is not a comx one (locomx - z85230) - * - * Version 0.83 (99/07/15): - * - reset line_status when interface is down - * - * Version 0.84 (99/12/01): - * - comx_status should not check for IFF_UP (to report - * line status from dev->open()) - * - * Version 0.85 (00/08/15): - * - resource release on failure in comx_mkdir - * - fix return value on failure at comx_write_proc - * - * Changed (00/10/29, Henner Eisen): - * - comx_rx() / comxlapb_data_indication() return status. - */ - -#define VERSION "0.85" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_KMOD -#include -#endif - -#ifndef CONFIG_PROC_FS -#error For now, COMX really needs the /proc filesystem -#endif - -#include -#include "comx.h" - -MODULE_AUTHOR("Gergely Madarasz "); -MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters"); -MODULE_LICENSE("GPL"); - -static struct comx_hardware *comx_channels = NULL; -static struct comx_protocol *comx_lines = NULL; - -static int comx_mkdir(struct inode *, struct dentry *, int); -static int comx_rmdir(struct inode *, struct dentry *); -static struct dentry *comx_lookup(struct inode *, struct dentry *, struct nameidata *); - -static struct inode_operations comx_root_inode_ops = { - .lookup = comx_lookup, - .mkdir = comx_mkdir, - .rmdir = comx_rmdir, -}; - -static int comx_delete_dentry(struct dentry *dentry); -static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode, - int size, struct proc_dir_entry *dir); - -static struct dentry_operations comx_dentry_operations = { - .d_delete = comx_delete_dentry, -}; - - -static struct proc_dir_entry * comx_root_dir; - -struct comx_debugflags_struct comx_debugflags[] = { - { "comx_rx", DEBUG_COMX_RX }, - { "comx_tx", DEBUG_COMX_TX }, - { "hw_tx", DEBUG_HW_TX }, - { "hw_rx", DEBUG_HW_RX }, - { "hdlc_keepalive", DEBUG_HDLC_KEEPALIVE }, - { "comxppp", DEBUG_COMX_PPP }, - { "comxlapb", DEBUG_COMX_LAPB }, - { "dlci", DEBUG_COMX_DLCI }, - { NULL, 0 } -}; - - -int comx_debug(struct net_device *dev, char *fmt, ...) -{ - struct comx_channel *ch = dev->priv; - char *page,*str; - va_list args; - int len; - - if (!ch->debug_area) return 0; - - if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM; - - va_start(args, fmt); - len = vsprintf(str = page, fmt, args); - va_end(args); - - if (len >= PAGE_SIZE) { - printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len); - free_page((unsigned long)page); - return -EINVAL; - } - - while (len) { - int to_copy; - int free = (ch->debug_start - ch->debug_end + ch->debug_size) - % ch->debug_size; - - to_copy = min_t(int, free ? free : ch->debug_size, - min_t(int, ch->debug_size - ch->debug_end, len)); - memcpy(ch->debug_area + ch->debug_end, str, to_copy); - str += to_copy; - len -= to_copy; - ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size; - if (ch->debug_start == ch->debug_end) // Full ? push start away - ch->debug_start = (ch->debug_start + len + 1) % - ch->debug_size; - ch->debug_file->size = (ch->debug_end - ch->debug_start + - ch->debug_size) % ch->debug_size; - } - - free_page((unsigned long)page); - return 0; -} - -int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg) -{ - struct comx_channel *ch = dev->priv; - - if (!ch->debug_area) return 0; - if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg); - if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg); - - return comx_debug_bytes(dev, skb->data, skb->len, msg); -} - -int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len, - char *msg) -{ - int pos = 0; - struct comx_channel *ch = dev->priv; - - if (!ch->debug_area) return 0; - - comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len); - - while (pos != len) { - char line[80]; - int i = 0; - - memset(line, 0, 80); - sprintf(line,"%04d ", pos); - do { - sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]); - sprintf(line + 60 + (pos % 16), "%c", - isprint(bytes[pos]) ? bytes[pos] : '.'); - pos++; - } while (pos != len && pos % 16); - - while ( i++ != 78 ) if (line[i] == 0) line[i] = ' '; - line[77] = '\n'; - line[78] = 0; - - comx_debug(dev, "%s", line); - } - comx_debug(dev, "\n"); - return 0; -} - -static void comx_loadavg_timerfun(unsigned long d) -{ - struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; - - ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes; - ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = - ch->current_stats->tx_bytes; - - ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size; - - mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]); -} - -#if 0 -static void comx_reset_timerfun(unsigned long d) -{ - struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; - - if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) { - if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) { - ch->HW_reset(dev); - } - } - - mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout); -} -#endif - -static int comx_open(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *comxdir = ch->procdir->subdir; - int ret=0; - - if (!ch->protocol || !ch->hardware) return -ENODEV; - - if ((ret = ch->HW_open(dev))) return ret; - if ((ret = ch->LINE_open(dev))) { - ch->HW_close(dev); - return ret; - }; - - for (; comxdir ; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 || - strcmp(comxdir->name, FILENAME_PROTOCOL) == 0) - comxdir->mode = S_IFREG | 0444; - } - -#if 0 - ch->reset_pending = 1; - ch->reset_timeout = 30; - ch->reset_timer.function = comx_reset_timerfun; - ch->reset_timer.data = (unsigned long)dev; - ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout; - add_timer(&ch->reset_timer); -#endif - - return 0; -} - -static int comx_close(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - struct proc_dir_entry *comxdir = ch->procdir->subdir; - int ret = -ENODEV; - - if (test_and_clear_bit(0, &ch->lineup_pending)) { - del_timer(&ch->lineup_timer); - } - -#if 0 - del_timer(&ch->reset_timer); -#endif - - if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) { - ret = ch->LINE_close(dev); - } - - if (ret) return ret; - - if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) { - ret = ch->HW_close(dev); - } - - ch->line_status=0; - - for (; comxdir ; comxdir = comxdir->next) { - if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 || - strcmp(comxdir->name, FILENAME_PROTOCOL) == 0) - comxdir->mode = S_IFREG | 0644; - } - - return ret; -} - -void comx_status(struct net_device *dev, int status) -{ - struct comx_channel *ch = dev->priv; - -#if 0 - if(status & (PROTO_UP | PROTO_LOOP)) { - clear_bit(0,&ch->reset_pending); - } -#endif - - printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n", - dev->name, status & LINE_UP ? "UP" : "DOWN", - status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ? - "UP" : "DOWN"); - - ch->line_status = status; -} - -static int comx_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - int rc; - - if (skb->len > dev->mtu + dev->hard_header_len) { - printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name, - (int)skb->len, dev->mtu); - } - - if (ch->debug_flags & DEBUG_COMX_TX) { - comx_debug_skb(dev, skb, "comx_xmit skb"); - } - - rc=ch->LINE_xmit(skb, dev); -// if (!rc) dev_kfree_skb(skb); - - return rc; -} - -static int comx_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct comx_channel *ch = dev->priv; - - if (ch->LINE_header) { - return (ch->LINE_header(skb, dev, type, daddr, saddr, len)); - } else { - return 0; - } -} - -static int comx_rebuild_header(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct comx_channel *ch = dev->priv; - - if (ch->LINE_rebuild_header) { - return(ch->LINE_rebuild_header(skb)); - } else { - return 0; - } -} - -int comx_rx(struct net_device *dev, struct sk_buff *skb) -{ - struct comx_channel *ch = dev->priv; - - if (ch->debug_flags & DEBUG_COMX_RX) { - comx_debug_skb(dev, skb, "comx_rx skb"); - } - if (skb) { - netif_rx(skb); - dev->last_rx = jiffies; - } - return 0; -} - -static struct net_device_stats *comx_stats(struct net_device *dev) -{ - struct comx_channel *ch = dev->priv; - - return ch->current_stats; -} - -void comx_lineup_func(unsigned long d) -{ - struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; - - del_timer(&ch->lineup_timer); - clear_bit(0, &ch->lineup_pending); - - if (ch->LINE_status) { - ch->LINE_status(dev, ch->line_status |= LINE_UP); - } -} - -#define LOADAVG(avg, off) (int) \ - ((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \ - % ch->loadavg_size + off] - ch->avg_bytes[(ch->loadavg_counter - 1 \ - - ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \ - % ch->loadavg_size + off]) / ch->loadavg[avg] * 8) - -static int comx_statistics(struct net_device *dev, char *page) -{ - struct comx_channel *ch = dev->priv; - int len = 0; - int tmp; - int i = 0; - char tmpstr[20]; - int tmpstrlen = 0; - - len += sprintf(page + len, "Interface administrative status is %s, " - "modem status is %s, protocol is %s\n", - dev->flags & IFF_UP ? "UP" : "DOWN", - ch->line_status & LINE_UP ? "UP" : "DOWN", - ch->line_status & PROTO_LOOP ? "LOOP" : - ch->line_status & PROTO_UP ? "UP" : "DOWN"); - len += sprintf(page + len, "Modem status changes: %lu, Transmitter status " - "is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ? - ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev)); - len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (", - LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0)); - tmpstr[0] = 0; - for (i=0; i != 3; i++) { - char tf; - - tf = ch->loadavg[i] % 60 == 0 && - ch->loadavg[i] / 60 > 0 ? 'm' : 's'; - tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s", - ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf, - i == 2 ? ")\n" : "/"); - } - len += sprintf(page + len, - "%s (output): %d / %d / %d bits/s (%s", tmpstr, - LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size), - LOADAVG(2, ch->loadavg_size), tmpstr); - - len += sprintf(page + len, "Debug flags: "); - tmp = len; i = 0; - while (comx_debugflags[i].name) { - if (ch->debug_flags & comx_debugflags[i].value) - len += sprintf(page + len, "%s ", - comx_debugflags[i].name); - i++; - } - len += sprintf(page + len, "%s\n", tmp == len ? "none" : ""); - - len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, " - "aborts: %lu\n buffer overrun: %lu, pbuffer overrun: %lu\n" - "TX errors: underrun: %lu\n", - ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors, - ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors, - ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors, - ch->current_stats->tx_fifo_errors); - - if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) { - len += ch->LINE_statistics(dev, page + len); - } else { - len += sprintf(page+len, "Line status: driver not initialized\n"); - } - if (ch->HW_statistics && (ch->init_status & HW_OPEN)) { - len += ch->HW_statistics(dev, page + len); - } else { - len += sprintf(page+len, "Board status: driver not initialized\n"); - } - - return len; -} - -static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct comx_channel *ch = dev->priv; - - if (ch->LINE_ioctl) { - return(ch->LINE_ioctl(dev, ifr, cmd)); - } - return -EINVAL; -} - -static void comx_reset_dev(struct net_device *dev) -{ - dev->open = comx_open; - dev->stop = comx_close; - dev->hard_start_xmit = comx_xmit; - dev->hard_header = comx_header; - dev->rebuild_header = comx_rebuild_header; - dev->get_stats = comx_stats; - dev->do_ioctl = comx_ioctl; - dev->change_mtu = NULL; - dev->tx_queue_len = 20; - dev->flags = IFF_NOARP; -} - -static int comx_init_dev(struct net_device *dev) -{ - struct comx_channel *ch; - - if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(ch, 0, sizeof(struct comx_channel)); - - ch->loadavg[0] = 5; - ch->loadavg[1] = 300; - ch->loadavg[2] = 900; - ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; - if ((ch->avg_bytes = kmalloc(ch->loadavg_size * - sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) { - kfree(ch); - return -ENOMEM; - } - - memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2); - ch->loadavg_counter = 0; - ch->loadavg_timer.function = comx_loadavg_timerfun; - ch->loadavg_timer.data = (unsigned long)dev; - ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0]; - add_timer(&ch->loadavg_timer); - - dev->priv = (void *)ch; - ch->dev = dev; - ch->line_status &= ~LINE_UP; - - ch->current_stats = &ch->stats; - - comx_reset_dev(dev); - return 0; -} - -static int comx_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; - int len = 0; - - if (strcmp(file->name, FILENAME_STATUS) == 0) { - len = comx_statistics(dev, page); - } else if (strcmp(file->name, FILENAME_HARDWARE) == 0) { - len = sprintf(page, "%s\n", ch->hardware ? - ch->hardware->name : HWNAME_NONE); - } else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) { - len = sprintf(page, "%s\n", ch->protocol ? - ch->protocol->name : PROTONAME_NONE); - } else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) { - len = sprintf(page, "%01d\n", ch->lineup_delay); - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) { - *eof = 1; - } - return min_t(int, count, len - off); -} - - -static int comx_root_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct proc_dir_entry *file = (struct proc_dir_entry *)data; - struct comx_hardware *hw; - struct comx_protocol *line; - - int len = 0; - - if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) { - for(hw=comx_channels;hw;hw=hw->next) - len+=sprintf(page+len, "%s\n", hw->name); - } else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) { - for(line=comx_lines;line;line=line->next) - len+=sprintf(page+len, "%s\n", line->name); - } - - if (off >= len) { - *eof = 1; - return 0; - } - - *start = page + off; - if (count >= len - off) { - *eof = 1; - } - return min_t(int, count, len - off); -} - - - -static int comx_write_proc(struct file *file, const char *buffer, u_long count, - void *data) -{ - struct proc_dir_entry *entry = (struct proc_dir_entry *)data; - struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch = dev->priv; - char *page; - struct comx_hardware *hw = comx_channels; - struct comx_protocol *line = comx_lines; - int ret=0; - - if (count > PAGE_SIZE) { - printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE); - return -ENOSPC; - } - - if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; - - if(copy_from_user(page, buffer, count)) - { - count = -EFAULT; - goto out; - } - - if (page[count-1] == '\n') - page[count-1] = '\0'; - else if (count < PAGE_SIZE) - page[count] = '\0'; - else if (page[count]) { - count = -EINVAL; - goto out; - } - - if (strcmp(entry->name, FILENAME_DEBUG) == 0) { - int i; - int ret = 0; - - if ((i = simple_strtoul(page, NULL, 10)) != 0) { - unsigned long flags; - - save_flags(flags); cli(); - if (ch->debug_area) kfree(ch->debug_area); - if ((ch->debug_area = kmalloc(ch->debug_size = i, - GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - } - ch->debug_start = ch->debug_end = 0; - restore_flags(flags); - free_page((unsigned long)page); - return ret ? ret : count; - } - - if (*page != '+' && *page != '-') { - free_page((unsigned long)page); - return -EINVAL; - } - while (comx_debugflags[i].value && - strncmp(comx_debugflags[i].name, page + 1, - strlen(comx_debugflags[i].name))) { - i++; - } - - if (comx_debugflags[i].value == 0) { - printk(KERN_ERR "Invalid debug option\n"); - free_page((unsigned long)page); - return -EINVAL; - } - if (*page == '+') { - ch->debug_flags |= comx_debugflags[i].value; - } else { - ch->debug_flags &= ~comx_debugflags[i].value; - } - } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) { - if(strlen(page)>10) { - free_page((unsigned long)page); - return -EINVAL; - } - while (hw) { - if (strcmp(hw->name, page) == 0) { - break; - } else { - hw = hw->next; - } - } -#ifdef CONFIG_KMOD - if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){ - request_module("comx-hw-%s",page); - } - hw=comx_channels; - while (hw) { - if (comx_strcasecmp(hw->name, page) == 0) { - break; - } else { - hw = hw->next; - } - } -#endif - - if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw) { - free_page((unsigned long)page); - return -ENODEV; - } - if (ch->init_status & HW_OPEN) { - free_page((unsigned long)page); - return -EBUSY; - } - if (ch->hardware && ch->hardware->hw_exit && - (ret=ch->hardware->hw_exit(dev))) { - free_page((unsigned long)page); - return ret; - } - ch->hardware = hw; - entry->size = strlen(page) + 1; - if (hw && hw->hw_init) hw->hw_init(dev); - } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) { - if(strlen(page)>10) { - free_page((unsigned long)page); - return -EINVAL; - } - while (line) { - if (comx_strcasecmp(line->name, page) == 0) { - break; - } else { - line = line->next; - } - } -#ifdef CONFIG_KMOD - if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) { - request_module("comx-proto-%s",page); - } - line=comx_lines; - while (line) { - if (comx_strcasecmp(line->name, page) == 0) { - break; - } else { - line = line->next; - } - } -#endif - - if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) { - free_page((unsigned long)page); - return -ENODEV; - } - - if (ch->init_status & LINE_OPEN) { - free_page((unsigned long)page); - return -EBUSY; - } - - if (ch->protocol && ch->protocol->line_exit && - (ret=ch->protocol->line_exit(dev))) { - free_page((unsigned long)page); - return ret; - } - ch->protocol = line; - entry->size = strlen(page) + 1; - comx_reset_dev(dev); - if (line && line->line_init) line->line_init(dev); - } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) { - int i; - - if ((i = simple_strtoul(page, NULL, 10)) != 0) { - if (i >=0 && i < 10) { - ch->lineup_delay = i; - } else { - printk(KERN_ERR "comx: invalid lineup_delay value\n"); - } - } - } -out: - free_page((unsigned long)page); - return count; -} - -static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - struct proc_dir_entry *new_dir, *debug_file; - struct net_device *dev; - struct comx_channel *ch; - int ret = -EIO; - - if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(dev, 0, sizeof(struct net_device)); - - lock_kernel(); - if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, - comx_root_dir)) == NULL) { - goto cleanup_dev; - } - - new_dir->nlink = 2; - new_dir->data = NULL; // ide jon majd a struct dev - - /* Ezek kellenek */ - if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644, - strlen(HWNAME_NONE) + 1, new_dir)) { - goto cleanup_new_dir; - } - if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644, - strlen(PROTONAME_NONE) + 1, new_dir)) { - goto cleanup_filename_hardware; - } - if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) { - goto cleanup_filename_protocol; - } - if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) { - goto cleanup_filename_status; - } - - if ((debug_file = create_proc_entry(FILENAME_DEBUG, - S_IFREG | 0644, new_dir)) == NULL) { - goto cleanup_filename_lineupdelay; - } - debug_file->data = (void *)debug_file; - debug_file->read_proc = NULL; // see below - debug_file->write_proc = &comx_write_proc; - debug_file->nlink = 1; - - strcpy(dev->name, (char *)new_dir->name); - dev->init = comx_init_dev; - - if (register_netdevice(dev)) { - goto cleanup_filename_debug; - } - ch = dev->priv; - if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), - GFP_KERNEL)) == NULL) { - goto cleanup_register; - } - memset(ch->if_ptr, 0, sizeof(struct ppp_device)); - ch->debug_file = debug_file; - ch->procdir = new_dir; - new_dir->data = dev; - - ch->debug_start = ch->debug_end = 0; - if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE, - GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto cleanup_if_ptr; - } - - ch->lineup_delay = DEFAULT_LINEUP_DELAY; - - MOD_INC_USE_COUNT; - unlock_kernel(); - return 0; -cleanup_if_ptr: - kfree(ch->if_ptr); -cleanup_register: - unregister_netdevice(dev); -cleanup_filename_debug: - remove_proc_entry(FILENAME_DEBUG, new_dir); -cleanup_filename_lineupdelay: - remove_proc_entry(FILENAME_LINEUPDELAY, new_dir); -cleanup_filename_status: - remove_proc_entry(FILENAME_STATUS, new_dir); -cleanup_filename_protocol: - remove_proc_entry(FILENAME_PROTOCOL, new_dir); -cleanup_filename_hardware: - remove_proc_entry(FILENAME_HARDWARE, new_dir); -cleanup_new_dir: - remove_proc_entry(dentry->d_name.name, comx_root_dir); -cleanup_dev: - kfree(dev); - unlock_kernel(); - return ret; -} - -static int comx_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct proc_dir_entry *entry = PDE(dentry->d_inode); - struct net_device *dev; - struct comx_channel *ch; - int ret; - - lock_kernel(); - dev = entry->data; - ch = dev->priv; - if (dev->flags & IFF_UP) { - printk(KERN_ERR "%s: down interface before removing it\n", dev->name); - unlock_kernel(); - return -EBUSY; - } - - if (ch->protocol && ch->protocol->line_exit && - (ret=ch->protocol->line_exit(dev))) { - unlock_kernel(); - return ret; - } - if (ch->hardware && ch->hardware->hw_exit && - (ret=ch->hardware->hw_exit(dev))) { - if(ch->protocol && ch->protocol->line_init) { - ch->protocol->line_init(dev); - } - unlock_kernel(); - return ret; - } - ch->protocol = NULL; - ch->hardware = NULL; - - del_timer(&ch->loadavg_timer); - kfree(ch->avg_bytes); - - unregister_netdev(dev); - if (ch->debug_area) { - kfree(ch->debug_area); - } - if (dev->priv) { - kfree(dev->priv); - } - free_netdev(dev); - - remove_proc_entry(FILENAME_DEBUG, entry); - remove_proc_entry(FILENAME_LINEUPDELAY, entry); - remove_proc_entry(FILENAME_STATUS, entry); - remove_proc_entry(FILENAME_HARDWARE, entry); - remove_proc_entry(FILENAME_PROTOCOL, entry); - remove_proc_entry(dentry->d_name.name, comx_root_dir); - - MOD_DEC_USE_COUNT; - unlock_kernel(); - return 0; -} - -static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) -{ - struct proc_dir_entry *de; - struct inode *inode = NULL; - - lock_kernel(); - if ((de = PDE(dir)) != NULL) { - for (de = de->subdir ; de ; de = de->next) { - if ((de->namelen == dentry->d_name.len) && - (memcmp(dentry->d_name.name, de->name, - de->namelen) == 0)) { - if ((inode = proc_get_inode(dir->i_sb, - de->low_ino, de)) == NULL) { - printk(KERN_ERR "COMX: lookup error\n"); - unlock_kernel(); - return ERR_PTR(-EINVAL); - } - break; - } - } - } - unlock_kernel(); - dentry->d_op = &comx_dentry_operations; - d_add(dentry, inode); - return NULL; -} - -int comx_strcasecmp(const char *cs, const char *ct) -{ - register signed char __res; - - while (1) { - if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) { - break; - } - } - return __res; -} - -static int comx_delete_dentry(struct dentry *dentry) -{ - return 1; -} - -static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode, - int size, struct proc_dir_entry *dir) -{ - struct proc_dir_entry *new_file; - - if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) { - new_file->data = (void *)new_file; - new_file->read_proc = &comx_read_proc; - new_file->write_proc = &comx_write_proc; - new_file->size = size; - new_file->nlink = 1; - } - return(new_file); -} - -int comx_register_hardware(struct comx_hardware *comx_hw) -{ - struct comx_hardware *hw = comx_channels; - - if (!hw) { - comx_channels = comx_hw; - } else { - while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) { - hw = hw->next; - } - if (strcmp(comx_hw->name, hw->name) == 0) { - return -1; - } - hw->next = comx_hw; - } - - printk(KERN_INFO "COMX: driver for hardware type %s, version %s\n", comx_hw->name, comx_hw->version); - return 0; -} - -int comx_unregister_hardware(char *name) -{ - struct comx_hardware *hw = comx_channels; - - if (!hw) { - return -1; - } - - if (strcmp(hw->name, name) == 0) { - comx_channels = comx_channels->next; - return 0; - } - - while (hw->next != NULL && strcmp(hw->next->name,name) != 0) { - hw = hw->next; - } - - if (hw->next != NULL && strcmp(hw->next->name, name) == 0) { - hw->next = hw->next->next; - return 0; - } - return -1; -} - -int comx_register_protocol(struct comx_protocol *comx_line) -{ - struct comx_protocol *pr = comx_lines; - - if (!pr) { - comx_lines = comx_line; - } else { - while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) { - pr = pr->next; - } - if (strcmp(comx_line->name, pr->name) == 0) { - return -1; - } - pr->next = comx_line; - } - - printk(KERN_INFO "COMX: driver for protocol type %s, version %s\n", comx_line->name, comx_line->version); - return 0; -} - -int comx_unregister_protocol(char *name) -{ - struct comx_protocol *pr = comx_lines; - - if (!pr) { - return -1; - } - - if (strcmp(pr->name, name) == 0) { - comx_lines = comx_lines->next; - return 0; - } - - while (pr->next != NULL && strcmp(pr->next->name,name) != 0) { - pr = pr->next; - } - - if (pr->next != NULL && strcmp(pr->next->name, name) == 0) { - pr->next = pr->next->next; - return 0; - } - return -1; -} - -static int __init comx_init(void) -{ - struct proc_dir_entry *new_file; - - comx_root_dir = create_proc_entry("comx", - S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root); - if (!comx_root_dir) - return -ENOMEM; - comx_root_dir->proc_iops = &comx_root_inode_ops; - - if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, - S_IFREG | 0444, comx_root_dir)) == NULL) { - return -ENOMEM; - } - - new_file->data = new_file; - new_file->read_proc = &comx_root_read_proc; - new_file->write_proc = NULL; - new_file->nlink = 1; - - if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, - S_IFREG | 0444, comx_root_dir)) == NULL) { - return -ENOMEM; - } - - new_file->data = new_file; - new_file->read_proc = &comx_root_read_proc; - new_file->write_proc = NULL; - new_file->nlink = 1; - - - printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. \n", - VERSION); - return 0; -} - -static void __exit comx_exit(void) -{ - remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir); - remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir); - remove_proc_entry(comx_root_dir->name, &proc_root); -} - -module_init(comx_init); -module_exit(comx_exit); - -EXPORT_SYMBOL(comx_register_hardware); -EXPORT_SYMBOL(comx_unregister_hardware); -EXPORT_SYMBOL(comx_register_protocol); -EXPORT_SYMBOL(comx_unregister_protocol); -EXPORT_SYMBOL(comx_debug_skb); -EXPORT_SYMBOL(comx_debug_bytes); -EXPORT_SYMBOL(comx_debug); -EXPORT_SYMBOL(comx_lineup_func); -EXPORT_SYMBOL(comx_status); -EXPORT_SYMBOL(comx_rx); -EXPORT_SYMBOL(comx_strcasecmp); -EXPORT_SYMBOL(comx_root_dir); diff --git a/drivers/net/wan/comx.h b/drivers/net/wan/comx.h deleted file mode 100644 index 0f7404f21..000000000 --- a/drivers/net/wan/comx.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * General definitions for the COMX driver - * - * Original authors: Arpad Bakay , - * Peter Bajan , - * Previous maintainer: Tivadar Szemethy - * Currently maintained by: Gergely Madarasz - * - * Copyright (C) 1995-1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * net_device_stats: - * rx_length_errors rec_len < 4 || rec_len > 2000 - * rx_over_errors receive overrun (OVR) - * rx_crc_errors rx crc error - * rx_frame_errors aborts rec'd (ABO) - * rx_fifo_errors status fifo overrun (PBUFOVR) - * rx_missed_errors receive buffer overrun (BUFOVR) - * tx_aborted_errors ? - * tx_carrier_errors modem line status changes - * tx_fifo_errors tx underrun (locomx) - */ -#include - -struct comx_protocol { - char *name; - char *version; - unsigned short encap_type; - int (*line_init)(struct net_device *dev); - int (*line_exit)(struct net_device *dev); - struct comx_protocol *next; - }; - -struct comx_hardware { - char *name; - char *version; - int (*hw_init)(struct net_device *dev); - int (*hw_exit)(struct net_device *dev); - int (*hw_dump)(struct net_device *dev); - struct comx_hardware *next; - }; - -struct comx_channel { - void *if_ptr; // General purpose pointer - struct net_device *dev; // Where we belong to - struct net_device *twin; // On dual-port cards - struct proc_dir_entry *procdir; // the directory - - unsigned char init_status; - unsigned char line_status; - - struct timer_list lineup_timer; // against line jitter - long int lineup_pending; - unsigned char lineup_delay; - -#if 0 - struct timer_list reset_timer; // for board resetting - long reset_pending; - int reset_timeout; -#endif - - struct net_device_stats stats; - struct net_device_stats *current_stats; -#if 0 - unsigned long board_resets; -#endif - unsigned long *avg_bytes; - int loadavg_counter, loadavg_size; - int loadavg[3]; - struct timer_list loadavg_timer; - int debug_flags; - char *debug_area; - int debug_start, debug_end, debug_size; - struct proc_dir_entry *debug_file; -#ifdef CONFIG_COMX_DEBUG_RAW - char *raw; - int raw_len; -#endif - // LINE specific - struct comx_protocol *protocol; - void (*LINE_rx)(struct net_device *dev, struct sk_buff *skb); - int (*LINE_tx)(struct net_device *dev); - void (*LINE_status)(struct net_device *dev, u_short status); - int (*LINE_open)(struct net_device *dev); - int (*LINE_close)(struct net_device *dev); - int (*LINE_xmit)(struct sk_buff *skb, struct net_device *dev); - int (*LINE_header)(struct sk_buff *skb, struct net_device *dev, - u_short type,void *daddr, void *saddr, - unsigned len); - int (*LINE_rebuild_header)(struct sk_buff *skb); - int (*LINE_statistics)(struct net_device *dev, char *page); - int (*LINE_parameter_check)(struct net_device *dev); - int (*LINE_ioctl)(struct net_device *dev, struct ifreq *ifr, - int cmd); - void (*LINE_mod_use)(int); - void * LINE_privdata; - - // HW specific - - struct comx_hardware *hardware; - void (*HW_board_on)(struct net_device *dev); - void (*HW_board_off)(struct net_device *dev); - struct net_device *(*HW_access_board)(struct net_device *dev); - void (*HW_release_board)(struct net_device *dev, struct net_device *savep); - int (*HW_txe)(struct net_device *dev); - int (*HW_open)(struct net_device *dev); - int (*HW_close)(struct net_device *dev); - int (*HW_send_packet)(struct net_device *dev,struct sk_buff *skb); - int (*HW_statistics)(struct net_device *dev, char *page); -#if 0 - int (*HW_reset)(struct net_device *dev, char *page); -#endif - int (*HW_load_board)(struct net_device *dev); - void (*HW_set_clock)(struct net_device *dev); - void *HW_privdata; - }; - -struct comx_debugflags_struct { - char *name; - int value; - }; - -#define COMX_ROOT_DIR_NAME "comx" - -#define FILENAME_HARDWARE "boardtype" -#define FILENAME_HARDWARELIST "boardtypes" -#define FILENAME_PROTOCOL "protocol" -#define FILENAME_PROTOCOLLIST "protocols" -#define FILENAME_DEBUG "debug" -#define FILENAME_CLOCK "clock" -#define FILENAME_STATUS "status" -#define FILENAME_IO "io" -#define FILENAME_IRQ "irq" -#define FILENAME_KEEPALIVE "keepalive" -#define FILENAME_LINEUPDELAY "lineup_delay" -#define FILENAME_CHANNEL "channel" -#define FILENAME_FIRMWARE "firmware" -#define FILENAME_MEMADDR "memaddr" -#define FILENAME_TWIN "twin" -#define FILENAME_T1 "t1" -#define FILENAME_T2 "t2" -#define FILENAME_N2 "n2" -#define FILENAME_WINDOW "window" -#define FILENAME_MODE "mode" -#define FILENAME_DLCI "dlci" -#define FILENAME_MASTER "master" -#ifdef CONFIG_COMX_DEBUG_RAW -#define FILENAME_RAW "raw" -#endif - -#define PROTONAME_NONE "none" -#define HWNAME_NONE "none" -#define KEEPALIVE_OFF "off" - -#define FRAME_ACCEPTED 0 /* sending and xmitter busy */ -#define FRAME_DROPPED 1 -#define FRAME_ERROR 2 /* xmitter error */ -#define FRAME_QUEUED 3 /* sending but more can come */ - -#define LINE_UP 1 /* Modem UP */ -#define PROTO_UP 2 -#define PROTO_LOOP 4 - -#define HW_OPEN 1 -#define LINE_OPEN 2 -#define FW_LOADED 4 -#define IRQ_ALLOCATED 8 - -#define DEBUG_COMX_RX 2 -#define DEBUG_COMX_TX 4 -#define DEBUG_HW_TX 16 -#define DEBUG_HW_RX 32 -#define DEBUG_HDLC_KEEPALIVE 64 -#define DEBUG_COMX_PPP 128 -#define DEBUG_COMX_LAPB 256 -#define DEBUG_COMX_DLCI 512 - -#define DEBUG_PAGESIZE 3072 -#define DEFAULT_DEBUG_SIZE 4096 -#define DEFAULT_LINEUP_DELAY 1 -#define FILE_PAGESIZE 3072 - -#ifndef COMX_PPP_MAJOR -#define COMX_PPP_MAJOR 88 -#endif - - -#define COMX_CHANNEL(dev) ((struct comx_channel*)dev->priv) - -#define TWIN(dev) (COMX_CHANNEL(dev)->twin) - - -#ifndef byte -typedef u8 byte; -#endif -#ifndef word -typedef u16 word; -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -extern struct proc_dir_entry * comx_root_dir; - -extern int comx_register_hardware(struct comx_hardware *comx_hw); -extern int comx_unregister_hardware(char *name); -extern int comx_register_protocol(struct comx_protocol *comx_line); -extern int comx_unregister_protocol(char *name); - -extern int comx_rx(struct net_device *dev, struct sk_buff *skb); -extern void comx_status(struct net_device *dev, int status); -extern void comx_lineup_func(unsigned long d); - -extern int comx_debug(struct net_device *dev, char *fmt, ...); -extern int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg); -extern int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len, - char *msg); -extern int comx_strcasecmp(const char *cs, const char *ct); - -extern struct inode_operations comx_normal_inode_ops; diff --git a/drivers/net/wan/comxhw.h b/drivers/net/wan/comxhw.h deleted file mode 100644 index 15230dc1f..000000000 --- a/drivers/net/wan/comxhw.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Defines for comxhw.c - * - * Original authors: Arpad Bakay , - * Peter Bajan , - * Previous maintainer: Tivadar Szemethy - * Current maintainer: Gergely Madarasz - * - * Copyright (C) 1995-1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#define LOCOMX_IO_EXTENT 8 -#define COMX_IO_EXTENT 4 -#define HICOMX_IO_EXTENT 16 - -#define COMX_MAX_TX_SIZE 1600 -#define COMX_MAX_RX_SIZE 2048 - -#define COMX_JAIL_OFFSET 0xffff -#define COMX_JAIL_VALUE 0xfe -#define COMX_MEMORY_SIZE 65536 -#define HICOMX_MEMORY_SIZE 16384 -#define COMX_MEM_MIN 0xa0000 -#define COMX_MEM_MAX 0xf0000 - -#define COMX_DEFAULT_IO 0x360 -#define COMX_DEFAULT_IRQ 10 -#define COMX_DEFAULT_MEMADDR 0xd0000 -#define HICOMX_DEFAULT_IO 0x320 -#define HICOMX_DEFAULT_IRQ 10 -#define HICOMX_DEFAULT_MEMADDR 0xd0000 -#define LOCOMX_DEFAULT_IO 0x368 -#define LOCOMX_DEFAULT_IRQ 7 - -#define MAX_CHANNELNO 2 - -#define COMX_CHANNEL_OFFSET 0x2000 - -#define COMX_ENABLE_BOARD_IT 0x40 -#define COMX_BOARD_RESET 0x20 -#define COMX_ENABLE_BOARD_MEM 0x10 -#define COMX_DISABLE_BOARD_MEM 0 -#define COMX_DISABLE_ALL 0x00 - -#define HICOMX_DISABLE_ALL 0x00 -#define HICOMX_ENABLE_BOARD_MEM 0x02 -#define HICOMX_DISABLE_BOARD_MEM 0x0 -#define HICOMX_BOARD_RESET 0x01 -#define HICOMX_PRG_MEM 4 -#define HICOMX_DATA_MEM 0 -#define HICOMX_ID_BYTE 0x55 - -#define CMX_ID_BYTE 0x31 -#define COMX_CLOCK_CONST 8000 - -#define LINKUP_READY 3 - -#define OFF_FW_L1_ID 0x01e /* ID bytes */ -#define OFF_FW_L2_ID 0x1006 -#define FW_L1_ID_1 0xab -#define FW_L1_ID_2_COMX 0xc0 -#define FW_L1_ID_2_HICOMX 0xc1 -#define FW_L2_ID_1 0xab - -#define OFF_A_L2_CMD 0x130 /* command register for L2 */ -#define OFF_A_L2_CMDPAR 0x131 /* command parameter byte */ -#define OFF_A_L1_STATB 0x122 /* stat. block for L1 */ -#define OFF_A_L1_ABOREC 0x122 /* receive ABORT counter */ -#define OFF_A_L1_OVERRUN 0x123 /* receive overrun counter */ -#define OFF_A_L1_CRCREC 0x124 /* CRC error counter */ -#define OFF_A_L1_BUFFOVR 0x125 /* buffer overrun counter */ -#define OFF_A_L1_PBUFOVR 0x126 /* priority buffer overrun counter */ -#define OFF_A_L1_MODSTAT 0x127 /* current state of modem ctrl lines */ -#define OFF_A_L1_STATE 0x127 /* end of stat. block for L1 */ -#define OFF_A_L1_TXPC 0x128 /* Tx counter for the PC */ -#define OFF_A_L1_TXZ80 0x129 /* Tx counter for the Z80 */ -#define OFF_A_L1_RXPC 0x12a /* Rx counter for the PC */ -#define OFF_A_L1_RXZ80 0x12b /* Rx counter for the Z80 */ -#define OFF_A_L1_REPENA 0x12c /* IT rep disable */ -#define OFF_A_L1_CHNR 0x12d /* L1 channel logical number */ -#define OFF_A_L1_CLKINI 0x12e /* Timer Const */ -#define OFF_A_L2_LINKUP 0x132 /* Linkup byte */ -#define OFF_A_L2_DAV 0x134 /* Rx DAV */ -#define OFF_A_L2_RxBUFP 0x136 /* Rx buff relative to membase */ -#define OFF_A_L2_TxEMPTY 0x138 /* Tx Empty */ -#define OFF_A_L2_TxBUFP 0x13a /* Tx Buf */ -#define OFF_A_L2_NBUFFS 0x144 /* Number of buffers to fetch */ - -#define OFF_A_L2_SABMREC 0x164 /* LAPB no. of SABMs received */ -#define OFF_A_L2_SABMSENT 0x165 /* LAPB no. of SABMs sent */ -#define OFF_A_L2_REJREC 0x166 /* LAPB no. of REJs received */ -#define OFF_A_L2_REJSENT 0x167 /* LAPB no. of REJs sent */ -#define OFF_A_L2_FRMRREC 0x168 /* LAPB no. of FRMRs received */ -#define OFF_A_L2_FRMRSENT 0x169 /* LAPB no. of FRMRs sent */ -#define OFF_A_L2_PROTERR 0x16A /* LAPB no. of protocol errors rec'd */ -#define OFF_A_L2_LONGREC 0x16B /* LAPB no. of long frames */ -#define OFF_A_L2_INVNR 0x16C /* LAPB no. of invalid N(R)s rec'd */ -#define OFF_A_L2_UNDEFFR 0x16D /* LAPB no. of invalid frames */ - -#define OFF_A_L2_T1 0x174 /* T1 timer */ -#define OFF_A_L2_ADDR 0x176 /* DCE = 1, DTE = 3 */ - -#define COMX_CMD_INIT 1 -#define COMX_CMD_EXIT 2 -#define COMX_CMD_OPEN 16 -#define COMX_CMD_CLOSE 17 - diff --git a/drivers/net/wan/falc-lh.h b/drivers/net/wan/falc-lh.h deleted file mode 100644 index e30726c82..000000000 --- a/drivers/net/wan/falc-lh.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Defines for comx-hw-slicecom.c - FALC-LH specific - * - * Author: Bartok Istvan - * Last modified: Mon Feb 7 20:00:38 CET 2000 - * - * :set tabstop=6 - */ - -/* - * Control register offsets on the LBI (page 90) - * use it like: - * lbi[ MODE ] = 0x34; - */ - -#define MODE 0x03 -#define IPC 0x08 -#define IMR0 0x14 /* Interrupt Mask Register 0 */ -#define IMR1 0x15 -#define IMR2 0x16 -#define IMR3 0x17 -#define IMR4 0x18 -#define IMR5 0x19 -#define FMR0 0x1a /* Framer Mode Register 0 */ -#define FMR1 0x1b -#define FMR2 0x1c -#define XSW 0x1e -#define XSP 0x1f -#define XC0 0x20 -#define XC1 0x21 -#define RC0 0x22 -#define RC1 0x23 -#define XPM0 0x24 -#define XPM1 0x25 -#define XPM2 0x26 -#define TSWM 0x27 -#define IDLE 0x29 /* Idle Code */ -#define LIM0 0x34 -#define LIM1 0x35 -#define PCD 0x36 -#define PCR 0x37 -#define LIM2 0x38 - -/* - * Status registers on the LBI (page 134) - * these are read-only, use it like: - * if( lbi[ FRS0 ] ) ... - */ - -#define FRS0 0x4c /* Framer Receive Status register 0 */ -#define FRS1 0x4d /* Framer Receive Status register 1 */ -#define FECL 0x50 /* Framing Error Counter low byte */ /* Counts FAS word receive errors */ -#define FECH 0x51 /* high byte */ -#define CVCL 0x52 /* Code Violation Counter low byte */ /* Counts bipolar and HDB3 code violations */ -#define CVCH 0x53 /* high byte */ -#define CEC1L 0x54 /* CRC4 Error Counter 1 low byte */ /* Counts CRC4 errors in the incoming stream */ -#define CEC1H 0x55 /* high byte */ -#define EBCL 0x56 /* E Bit error Counter low byte */ /* E-bits: the remote end sends them, when */ -#define EBCH 0x57 /* high byte */ /* it detected a CRC4-error */ -#define ISR0 0x68 /* Interrupt Status Register 0 */ -#define ISR1 0x69 /* Interrupt Status Register 1 */ -#define ISR2 0x6a /* Interrupt Status Register 2 */ -#define ISR3 0x6b /* Interrupt Status Register 3 */ -#define ISR5 0x6c /* Interrupt Status Register 5 */ -#define GIS 0x6e /* Global Interrupt Status Register */ -#define VSTR 0x6f /* version information */ - -/* - * Bit fields - */ - -#define FRS0_LOS (1 << 7) -#define FRS0_AIS (1 << 6) -#define FRS0_LFA (1 << 5) -#define FRS0_RRA (1 << 4) -#define FRS0_AUXP (1 << 3) -#define FRS0_NMF (1 << 2) -#define FRS0_LMFA (1 << 1) - -#define FRS1_XLS (1 << 1) -#define FRS1_XLO (1) - -#define ISR2_FAR (1 << 7) -#define ISR2_LFA (1 << 6) -#define ISR2_MFAR (1 << 5) -#define ISR2_T400MS (1 << 4) -#define ISR2_AIS (1 << 3) -#define ISR2_LOS (1 << 2) -#define ISR2_RAR (1 << 1) -#define ISR2_RA (1) - -#define ISR3_ES (1 << 7) -#define ISR3_SEC (1 << 6) -#define ISR3_LMFA16 (1 << 5) -#define ISR3_AIS16 (1 << 4) -#define ISR3_RA16 (1 << 3) -#define ISR3_API (1 << 2) -#define ISR3_RSN (1 << 1) -#define ISR3_RSP (1) - -#define ISR5_XSP (1 << 7) -#define ISR5_XSN (1 << 6) diff --git a/drivers/net/wan/hscx.h b/drivers/net/wan/hscx.h deleted file mode 100644 index 675b7b1f1..000000000 --- a/drivers/net/wan/hscx.h +++ /dev/null @@ -1,103 +0,0 @@ -#define HSCX_MTU 1600 - -#define HSCX_ISTA 0x00 -#define HSCX_MASK 0x00 -#define HSCX_STAR 0x01 -#define HSCX_CMDR 0x01 -#define HSCX_MODE 0x02 -#define HSCX_TIMR 0x03 -#define HSCX_EXIR 0x04 -#define HSCX_XAD1 0x04 -#define HSCX_RBCL 0x05 -#define HSCX_SAD2 0x05 -#define HSCX_RAH1 0x06 -#define HSCX_RSTA 0x07 -#define HSCX_RAH2 0x07 -#define HSCX_RAL1 0x08 -#define HSCX_RCHR 0x09 -#define HSCX_RAL2 0x09 -#define HSCX_XBCL 0x0a -#define HSCX_BGR 0x0b -#define HSCX_CCR2 0x0c -#define HSCX_RBCH 0x0d -#define HSCX_XBCH 0x0d -#define HSCX_VSTR 0x0e -#define HSCX_RLCR 0x0e -#define HSCX_CCR1 0x0f -#define HSCX_FIFO 0x1e - -#define HSCX_HSCX_CHOFFS 0x400 -#define HSCX_SEROFFS 0x1000 - -#define HSCX_RME 0x80 -#define HSCX_RPF 0x40 -#define HSCX_RSC 0x20 -#define HSCX_XPR 0x10 -#define HSCX_TIN 0x08 -#define HSCX_ICA 0x04 -#define HSCX_EXA 0x02 -#define HSCX_EXB 0x01 - -#define HSCX_XMR 0x80 -#define HSCX_XDU 0x40 -#define HSCX_EXE 0x40 -#define HSCX_PCE 0x20 -#define HSCX_RFO 0x10 -#define HSCX_CSC 0x08 -#define HSCX_RFS 0x04 - -#define HSCX_XDOV 0x80 -#define HSCX_XFW 0x40 -#define HSCX_XRNR 0x20 -#define HSCX_RRNR 0x10 -#define HSCX_RLI 0x08 -#define HSCX_CEC 0x04 -#define HSCX_CTS 0x02 -#define HSCX_WFA 0x01 - -#define HSCX_RMC 0x80 -#define HSCX_RHR 0x40 -#define HSCX_RNR 0x20 -#define HSCX_XREP 0x20 -#define HSCX_STI 0x10 -#define HSCX_XTF 0x08 -#define HSCX_XIF 0x04 -#define HSCX_XME 0x02 -#define HSCX_XRES 0x01 - -#define HSCX_AUTO 0x00 -#define HSCX_NONAUTO 0x40 -#define HSCX_TRANS 0x80 -#define HSCX_XTRANS 0xc0 -#define HSCX_ADM16 0x20 -#define HSCX_ADM8 0x00 -#define HSCX_TMD_EXT 0x00 -#define HSCX_TMD_INT 0x10 -#define HSCX_RAC 0x08 -#define HSCX_RTS 0x04 -#define HSCX_TLP 0x01 - -#define HSCX_VFR 0x80 -#define HSCX_RDO 0x40 -#define HSCX_CRC 0x20 -#define HSCX_RAB 0x10 - -#define HSCX_CIE 0x04 -#define HSCX_RIE 0x02 - -#define HSCX_DMA 0x80 -#define HSCX_NRM 0x40 -#define HSCX_CAS 0x20 -#define HSCX_XC 0x10 - -#define HSCX_OV 0x10 - -#define HSCX_CD 0x80 - -#define HSCX_RC 0x80 - -#define HSCX_PU 0x80 -#define HSCX_NRZ 0x00 -#define HSCX_NRZI 0x40 -#define HSCX_ODS 0x10 -#define HSCX_ITF 0x08 diff --git a/drivers/net/wan/mixcom.h b/drivers/net/wan/mixcom.h deleted file mode 100644 index 1815eef75..000000000 --- a/drivers/net/wan/mixcom.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Defines for the mixcom board - * - * Author: Gergely Madarasz - * - * Copyright (C) 1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#define MIXCOM_IO_EXTENT 0x20 - -#define MIXCOM_DEFAULT_IO 0x180 -#define MIXCOM_DEFAULT_IRQ 5 - -#define MIXCOM_ID 0x11 -#define MIXCOM_SERIAL_OFFSET 0x1000 -#define MIXCOM_CHANNEL_OFFSET 0x400 -#define MIXCOM_IT_OFFSET 0xc14 -#define MIXCOM_STATUS_OFFSET 0xc14 -#define MIXCOM_ID_OFFSET 0xc10 -#define MIXCOM_ON 0x1 -#define MIXCOM_OFF 0x0 - -/* Status register bits */ - -#define MIXCOM_CTSB 0x1 -#define MIXCOM_CTSA 0x2 -#define MIXCOM_CHANNELNO 0x20 -#define MIXCOM_POWERFAIL 0x40 -#define MIXCOM_BOOT 0x80 diff --git a/drivers/net/wan/munich32x.h b/drivers/net/wan/munich32x.h deleted file mode 100644 index 8f151f2ed..000000000 --- a/drivers/net/wan/munich32x.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Defines for comx-hw-slicecom.c - MUNICH32X specific - * - * Author: Bartok Istvan - * Last modified: Tue Jan 11 14:27:36 CET 2000 - * - * :set tabstop=6 - */ - -#define TXBUFFER_SIZE 1536 /* Max mennyit tud a kartya hardver atvenni */ -#define RXBUFFER_SIZE (TXBUFFER_SIZE+4) /* For Rx reasons it must be a multiple of 4, and =>4 (page 265) */ - /* +4 .. see page 265, bit FE */ - /* TOD: a MODE1-be nem is ezt teszem, hanem a TXBUFFER-t, lehet hogy nem is kell? */ - -//#define PCI_VENDOR_ID_SIEMENS 0x110a -#define PCI_DEVICE_ID_SIEMENS_MUNICH32X 0x2101 - -/* - * PCI config space registers (page 120) - */ - -#define MUNICH_PCI_PCIRES 0x4c /* 0xe0000 resets the chip */ - - -/* - * MUNICH slave register offsets relative to base_address[0] (PCI BAR1) (page 181): - * offsets are in bytes, registers are u32's, so we need a >>2 for indexing - * the int[] by byte offsets. Use it like: - * - * bar1[ STAT ] = ~0L; or - * x = bar1[ STAT ]; - */ - -#define CONF (0x00 >> 2) -#define CMD (0x04 >> 2) -#define STAT (0x08 >> 2) -#define STACK (0x08 >> 2) -#define IMASK (0x0c >> 2) -#define PIQBA (0x14 >> 2) -#define PIQL (0x18 >> 2) -#define MODE1 (0x20 >> 2) -#define MODE2 (0x24 >> 2) -#define CCBA (0x28 >> 2) -#define TXPOLL (0x2c >> 2) -#define TIQBA (0x30 >> 2) -#define TIQL (0x34 >> 2) -#define RIQBA (0x38 >> 2) -#define RIQL (0x3c >> 2) -#define LCONF (0x40 >> 2) /* LBI Configuration Register */ -#define LCCBA (0x44 >> 2) /* LBI Configuration Control Block */ /* DE: lehet hogy nem is kell? */ -#define LTIQBA (0x50 >> 2) /* DE: lehet hogy nem is kell? page 210: LBI DMA Controller intq - nem hasznalunk DMA-t.. */ -#define LTIQL (0x54 >> 2) /* DE: lehet hogy nem is kell? */ -#define LRIQBA (0x58 >> 2) /* DE: lehet hogy nem is kell? */ -#define LRIQL (0x5c >> 2) /* DE: lehet hogy nem is kell? */ -#define LREG0 (0x60 >> 2) /* LBI Indirect External Configuration register 0 */ -#define LREG1 (0x64 >> 2) -#define LREG2 (0x68 >> 2) -#define LREG3 (0x6c >> 2) -#define LREG4 (0x70 >> 2) -#define LREG5 (0x74 >> 2) -#define LREG6 (0x78 >> 2) /* LBI Indirect External Configuration register 6 */ -#define LSTAT (0x7c >> 2) /* LBI Status Register */ -#define GPDIR (0x80 >> 2) /* General Purpose Bus DIRection - 0..input, 1..output */ -#define GPDATA (0x84 >> 2) /* General Purpose Bus DATA */ - - -/* - * MUNICH commands: (they go into register CMD) - */ - -#define CMD_ARPCM 0x01 /* Action Request Serial PCM Core */ -#define CMD_ARLBI 0x02 /* Action Request LBI */ - - -/* - * MUNICH event bits in the STAT, STACK, IMASK registers (page 188,189) - */ - -#define STAT_PTI (1 << 15) -#define STAT_PRI (1 << 14) -#define STAT_LTI (1 << 13) -#define STAT_LRI (1 << 12) -#define STAT_IOMI (1 << 11) -#define STAT_SSCI (1 << 10) -#define STAT_LBII (1 << 9) -#define STAT_MBI (1 << 8) - -#define STAT_TI (1 << 6) -#define STAT_TSPA (1 << 5) -#define STAT_RSPA (1 << 4) -#define STAT_LBIF (1 << 3) -#define STAT_LBIA (1 << 2) -#define STAT_PCMF (1 << 1) -#define STAT_PCMA (1) - -/* - * We do not handle these (and do not touch their STAT bits) in the interrupt loop - */ - -#define STAT_NOT_HANDLED_BY_INTERRUPT (STAT_PCMF | STAT_PCMA) - - -/* - * MUNICH MODE1/MODE2 slave register fields (page 193,196) - * these are not all masks, MODE1_XX_YY are my magic values! - */ - -#define MODE1_PCM_E1 (1 << 31) /* E1, 2.048 Mbit/sec */ -#define MODE1_TBS_4 (1 << 24) /* TBS = 4 .. no Tx bit shift */ -#define MODE1_RBS_4 (1 << 18) /* RBS = 4 .. no Rx bit shift */ -#define MODE1_REN (1 << 15) /* Rx Enable */ -#define MODE1_MFL_MY TXBUFFER_SIZE /* Maximum Frame Length */ -#define MODE1_MAGIC (MODE1_PCM_E1 | MODE1_TBS_4 | MODE1_RBS_4 | MODE1_REN | MODE1_MFL_MY) - -#define MODE2_HPOLL (1 << 8) /* Hold Poll */ -#define MODE2_SPOLL (1 << 7) /* Slow Poll */ -#define MODE2_TSF (1) /* real magic - discovered by probing :) */ -// #define MODE2_MAGIC (MODE2_TSF) -#define MODE2_MAGIC (MODE2_SPOLL | MODE2_TSF) - - -/* - * LCONF bits (page 205) - * these are not all masks, LCONF_XX_YY are my magic values! - */ - -#define LCONF_IPA (1 << 31) /* Interrupt Pass. Use 1 for FALC54 */ -#define LCONF_DCA (1 << 30) /* Disregard the int's for Channel A - DMSM does not try to handle them */ -#define LCONF_DCB (1 << 29) /* Disregard the int's for Channel B */ -#define LCONF_EBCRES (1 << 22) /* Reset LBI External Bus Controller, 0..reset, 1..normal operation */ -#define LCONF_LBIRES (1 << 21) /* Reset LBI DMSM, 0..reset, 1..normal operation */ -#define LCONF_BTYP_16DEMUX (1 << 7) /* 16-bit demultiplexed bus */ -#define LCONF_ABM (1 << 4) /* Arbitration Master */ - -/* writing LCONF_MAGIC1 followed by a LCONF_MAGIC2 into LCONF resets the EBC and DMSM: */ - -#define LCONF_MAGIC1 (LCONF_BTYP_16DEMUX | LCONF_ABM | LCONF_IPA | LCONF_DCA | LCONF_DCB) -#define LCONF_MAGIC2 (LCONF_MAGIC1 | LCONF_EBCRES | LCONF_LBIRES) - - -/* - * LREGx magic values if a FALC54 is on the LBI (page 217) - */ - -#define LREG0_MAGIC 0x00000264 -#define LREG1_MAGIC 0x6e6a6b66 -#define LREG2_MAGIC 0x00000264 -#define LREG3_MAGIC 0x6e686966 -#define LREG4_MAGIC 0x00000000 -#define LREG5_MAGIC ( (7<<27) | (3<<24) | (1<<21) | (7<<3) | (2<<9) ) - - -/* - * PCM Action Specification fields (munich_ccb_t.action_spec) - */ - -#define CCB_ACTIONSPEC_IN (1 << 15) /* init */ -#define CCB_ACTIONSPEC_ICO (1 << 14) /* init only this channel */ -#define CCB_ACTIONSPEC_RES (1 << 6) /* reset all channels */ -#define CCB_ACTIONSPEC_LOC (1 << 5) -#define CCB_ACTIONSPEC_LOOP (1 << 4) -#define CCB_ACTIONSPEC_LOOPI (1 << 3) -#define CCB_ACTIONSPEC_IA (1 << 2) - - -/* - * Interrupt Information bits in the TIQ, RIQ - */ - -#define PCM_INT_HI (1 << 12) -#define PCM_INT_FI (1 << 11) -#define PCM_INT_IFC (1 << 10) -#define PCM_INT_SF (1 << 9) -#define PCM_INT_ERR (1 << 8) -#define PCM_INT_FO (1 << 7) -#define PCM_INT_FE2 (1 << 6) - -#define PCM_INT_CHANNEL( info ) (info & 0x1F) - - -/* - * Rx status info in the rx_desc_t.status - */ - -#define RX_STATUS_SF (1 << 6) -#define RX_STATUS_LOSS (1 << 5) -#define RX_STATUS_CRCO (1 << 4) -#define RX_STATUS_NOB (1 << 3) -#define RX_STATUS_LFD (1 << 2) -#define RX_STATUS_RA (1 << 1) -#define RX_STATUS_ROF 1 diff --git a/drivers/net/wan/wanxlfw.inc b/drivers/net/wan/wanxlfw.inc deleted file mode 100644 index 73da688f9..000000000 --- a/drivers/net/wan/wanxlfw.inc +++ /dev/null @@ -1,158 +0,0 @@ -static u8 firmware[]={ -0x60,0x00,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xB9,0x40,0x00,0x00,0x00,0x00,0x00, -0x10,0x14,0x42,0x80,0x4A,0xB0,0x09,0xB0,0x00,0x00,0x10,0x04,0x67,0x00,0x00,0x0E, -0x06,0xB0,0x40,0x00,0x00,0x00,0x09,0xB0,0x00,0x00,0x10,0x04,0x58,0x80,0x0C,0x80, -0x00,0x00,0x00,0x10,0x66,0x00,0xFF,0xDE,0x21,0xFC,0x00,0x00,0x16,0xBC,0x00,0x6C, -0x21,0xFC,0x00,0x00,0x17,0x5E,0x01,0x00,0x21,0xFC,0x00,0x00,0x16,0xDE,0x01,0x78, -0x21,0xFC,0x00,0x00,0x16,0xFE,0x01,0x74,0x21,0xFC,0x00,0x00,0x17,0x1E,0x01,0x70, -0x21,0xFC,0x00,0x00,0x17,0x3E,0x01,0x6C,0x21,0xFC,0x00,0x00,0x18,0x4C,0x02,0x00, -0x23,0xFC,0x78,0x00,0x00,0x00,0xFF,0xFC,0x15,0x48,0x33,0xFC,0x04,0x80,0xFF,0xFC, -0x10,0x26,0x33,0xFC,0x01,0x10,0xFF,0xFC,0x10,0x2A,0x23,0xFC,0x00,0xD4,0x9F,0x40, -0xFF,0xFC,0x15,0x40,0x23,0xFC,0x00,0x00,0x05,0x43,0xFF,0xF9,0x01,0x00,0x23,0xFC, -0x00,0x00,0x05,0x43,0xFF,0xF9,0x01,0x14,0x23,0xFC,0x00,0x00,0x00,0x00,0xFF,0xF9, -0x01,0x10,0x23,0xFC,0x00,0x00,0x00,0x08,0xFF,0xF9,0x01,0x24,0x23,0xFC,0x00,0x00, -0x01,0x01,0xFF,0xF9,0x01,0x28,0x00,0xB9,0x00,0x0F,0x03,0x00,0xFF,0xF9,0x00,0xE8, -0x23,0xFC,0x00,0x00,0x00,0x01,0xFF,0xF9,0x00,0xD4,0x61,0x00,0x06,0x74,0x33,0xFC, -0xFF,0xFF,0xFF,0xFC,0x15,0x52,0x42,0x79,0xFF,0xFC,0x15,0x50,0x42,0x79,0xFF,0xFC, -0x15,0x64,0x2E,0x3A,0x08,0x50,0x42,0xB9,0x00,0x00,0x19,0x54,0x4A,0x87,0x66,0x00, -0x00,0x0E,0x4E,0x72,0x22,0x00,0x46,0xFC,0x27,0x00,0x60,0x00,0xFF,0xE6,0x42,0x80, -0x42,0x86,0x08,0x07,0x00,0x04,0x67,0x00,0x00,0x0A,0x08,0x87,0x00,0x00,0x61,0x00, -0x02,0xA0,0x08,0x07,0x00,0x00,0x67,0x00,0x00,0x06,0x61,0x00,0x00,0x36,0x08,0x07, -0x00,0x08,0x67,0x00,0x00,0x06,0x61,0x00,0x02,0xB8,0x08,0x07,0x00,0x0C,0x67,0x00, -0x00,0x0A,0x61,0x00,0x04,0x94,0x61,0x00,0x03,0x60,0xE2,0x8F,0x58,0x80,0x0C,0x80, -0x00,0x00,0x00,0x10,0x66,0x00,0xFF,0xBC,0x23,0xC6,0xFF,0xF9,0x00,0xE4,0x60,0x00, -0xFF,0x92,0x20,0x70,0x09,0xB0,0x00,0x00,0x10,0x04,0x4A,0xA8,0x00,0x00,0x66,0x00, -0x02,0x4E,0x21,0x7C,0x00,0x00,0x00,0x01,0x00,0x00,0x42,0xB0,0x09,0xB0,0x00,0x00, -0x19,0x58,0x42,0xB0,0x09,0xB0,0x00,0x00,0x19,0x68,0x42,0xB0,0x09,0xB0,0x00,0x00, -0x19,0x78,0x42,0xB0,0x09,0xB0,0x00,0x00,0x19,0x88,0x22,0x39,0xFF,0xFC,0x16,0xEC, -0xC2,0xB0,0x09,0xB0,0x00,0x00,0x18,0xF2,0x0C,0xA8,0x00,0x00,0x00,0x04,0x00,0x18, -0x66,0x00,0x00,0x0E,0x82,0xB0,0x09,0xB0,0x00,0x00,0x18,0xE2,0x60,0x00,0x00,0x0A, -0x82,0xB0,0x09,0xB0,0x00,0x00,0x18,0xD2,0x23,0xC1,0xFF,0xFC,0x16,0xEC,0x00,0x70, -0x10,0x00,0x09,0xB0,0x00,0x00,0x19,0xAA,0x61,0x00,0x05,0x76,0x22,0x30,0x09,0xB0, -0x00,0x00,0x18,0x92,0x22,0x70,0x09,0xB0,0x00,0x00,0x18,0x72,0x74,0x08,0x26,0x3C, -0x18,0x00,0x00,0x00,0x0C,0xA8,0x00,0x00,0x00,0x01,0x00,0x10,0x67,0x00,0x00,0x06, -0x08,0xC3,0x00,0x1A,0x22,0xC3,0x22,0xC1,0x06,0x81,0x00,0x00,0x05,0xFC,0x51,0xCA, -0xFF,0xF4,0x08,0xC3,0x00,0x1D,0x22,0xC3,0x22,0xC1,0x74,0x1C,0x22,0xFC,0x90,0x00, -0x00,0x00,0x22,0xC1,0x06,0x81,0x00,0x00,0x05,0xFC,0x51,0xCA,0xFF,0xF0,0x22,0xFC, -0xB0,0x00,0x00,0x00,0x22,0xC1,0x22,0x70,0x09,0xB0,0x00,0x00,0x18,0x62,0x24,0x70, -0x09,0xB0,0x00,0x00,0x18,0x52,0x25,0x7C,0x00,0x00,0xFF,0xFF,0x00,0x10,0x25,0x7C, -0x00,0x00,0x00,0x00,0x00,0x14,0x22,0x30,0x09,0xB0,0x00,0x00,0x18,0x72,0x33,0x41, -0x00,0x02,0x06,0x81,0x00,0x00,0x00,0x50,0x33,0x41,0x00,0x00,0x13,0x7C,0x00,0x08, -0x00,0x04,0x13,0x7C,0x00,0x08,0x00,0x05,0x0C,0xA8,0x00,0x00,0x00,0x05,0x00,0x10, -0x66,0x00,0x00,0x2A,0x42,0x6A,0x00,0x08,0x23,0x7C,0x00,0x00,0xF0,0xB8,0x00,0x34, -0x23,0x7C,0x00,0x00,0xFF,0xFF,0x00,0x38,0x33,0x7C,0x05,0xFA,0x00,0x46,0x31,0xBC, -0x00,0x02,0x09,0xB0,0x00,0x00,0x19,0x9C,0x60,0x00,0x00,0xBC,0x0C,0xA8,0x00,0x00, -0x00,0x07,0x00,0x10,0x66,0x00,0x00,0x2C,0x35,0x7C,0x08,0x00,0x00,0x08,0x23,0x7C, -0xDE,0xBB,0x20,0xE3,0x00,0x34,0x23,0x7C,0xFF,0xFF,0xFF,0xFF,0x00,0x38,0x33,0x7C, -0x05,0xFC,0x00,0x46,0x31,0xBC,0x00,0x04,0x09,0xB0,0x00,0x00,0x19,0x9C,0x60,0x00, -0x00,0x86,0x0C,0xA8,0x00,0x00,0x00,0x04,0x00,0x10,0x66,0x00,0x00,0x26,0x42,0x6A, -0x00,0x08,0x23,0x7C,0x00,0x00,0xF0,0xB8,0x00,0x34,0x42,0xA9,0x00,0x38,0x33,0x7C, -0x05,0xFA,0x00,0x46,0x31,0xBC,0x00,0x02,0x09,0xB0,0x00,0x00,0x19,0x9C,0x60,0x00, -0x00,0x56,0x0C,0xA8,0x00,0x00,0x00,0x06,0x00,0x10,0x66,0x00,0x00,0x28,0x35,0x7C, -0x08,0x00,0x00,0x08,0x23,0x7C,0xDE,0xBB,0x20,0xE3,0x00,0x34,0x42,0xA9,0x00,0x38, -0x33,0x7C,0x05,0xFC,0x00,0x46,0x31,0xBC,0x00,0x04,0x09,0xB0,0x00,0x00,0x19,0x9C, -0x60,0x00,0x00,0x24,0x42,0x6A,0x00,0x08,0x23,0x7C,0x00,0x00,0xF0,0xB8,0x00,0x34, -0x23,0x7C,0x00,0x00,0xFF,0xFF,0x00,0x38,0x33,0x7C,0x05,0xF8,0x00,0x46,0x42,0x70, -0x09,0xB0,0x00,0x00,0x19,0x9C,0x25,0x7C,0x00,0x00,0x00,0x03,0x00,0x04,0x0C,0xA8, -0x00,0x00,0x00,0x02,0x00,0x14,0x66,0x00,0x00,0x0E,0x25,0x7C,0x10,0x04,0x09,0x00, -0x00,0x00,0x60,0x00,0x00,0x0A,0x25,0x7C,0x10,0x04,0x00,0x00,0x00,0x00,0x33,0x7C, -0x05,0xFC,0x00,0x06,0x22,0x00,0xE9,0x89,0x00,0x81,0x00,0x00,0x00,0x01,0x33,0xC1, -0xFF,0xFC,0x15,0xC0,0x08,0x39,0x00,0x00,0xFF,0xFC,0x15,0xC0,0x66,0x00,0xFF,0xF6, -0x35,0x7C,0x00,0x1F,0x00,0x14,0x00,0xAA,0x00,0x00,0x00,0x30,0x00,0x00,0x4E,0x75, -0x20,0x70,0x09,0xB0,0x00,0x00,0x18,0x52,0x42,0x68,0x00,0x14,0x02,0xA8,0xFF,0xFF, -0xFF,0xCF,0x00,0x00,0x02,0x70,0xEF,0xFF,0x09,0xB0,0x00,0x00,0x19,0xAA,0x61,0x00, -0x03,0x70,0x22,0x30,0x09,0xB0,0x00,0x00,0x10,0x04,0x42,0xB0,0x19,0x90,0x4E,0x75, -0x0C,0xB0,0x00,0x00,0x00,0x0A,0x09,0xB0,0x00,0x00,0x19,0x78,0x67,0x00,0x00,0xA8, -0x22,0x30,0x09,0xB0,0x00,0x00,0x19,0x68,0x24,0x01,0x4C,0x3C,0x20,0x00,0x00,0x00, -0x00,0x0C,0xD4,0xB0,0x09,0xB0,0x00,0x00,0x10,0x04,0x06,0x82,0x00,0x00,0x00,0x1C, -0x0C,0xB0,0x00,0x00,0x00,0x10,0x29,0x90,0x66,0x00,0x00,0x7C,0x20,0x70,0x29,0xA0, -0x00,0x04,0xE7,0x89,0xD2,0xB0,0x09,0xB0,0x00,0x00,0x18,0x72,0x22,0x70,0x19,0xA0, -0x00,0x04,0x24,0x30,0x29,0xA0,0x00,0x08,0x31,0x82,0x19,0xA0,0x00,0x02,0x56,0x82, -0x02,0x82,0xFF,0xFF,0xFF,0xFC,0x23,0xC8,0xFF,0xF9,0x01,0x04,0x23,0xC9,0xFF,0xF9, -0x01,0x08,0x23,0xC2,0xFF,0xF9,0x01,0x0C,0x23,0xFC,0x00,0x00,0x01,0x03,0xFF,0xF9, -0x01,0x28,0x61,0x00,0x01,0xF6,0x08,0xF0,0x00,0x1F,0x19,0x90,0x22,0x30,0x09,0xB0, -0x00,0x00,0x19,0x68,0x52,0x81,0x0C,0x81,0x00,0x00,0x00,0x0A,0x66,0x00,0x00,0x04, -0x42,0x81,0x21,0x81,0x09,0xB0,0x00,0x00,0x19,0x68,0x52,0xB0,0x09,0xB0,0x00,0x00, -0x19,0x78,0x60,0x00,0xFF,0x4C,0x4E,0x75,0x22,0x30,0x09,0xB0,0x00,0x00,0x19,0x88, -0xE7,0x89,0xD2,0xB0,0x09,0xB0,0x00,0x00,0x18,0x82,0x34,0x30,0x19,0x90,0x08,0x02, -0x00,0x0F,0x66,0x00,0x01,0x12,0x08,0x02,0x00,0x01,0x66,0x00,0x00,0xE6,0x4A,0x70, -0x09,0xB0,0x00,0x00,0x19,0x9C,0x66,0x00,0x00,0x06,0x08,0x82,0x00,0x02,0x02,0x42, -0x0C,0xBC,0x0C,0x42,0x0C,0x00,0x66,0x00,0x00,0xDC,0x42,0x83,0x36,0x30,0x19,0xA0, -0x00,0x02,0x96,0x70,0x09,0xB0,0x00,0x00,0x19,0x9C,0x0C,0x43,0x05,0xF8,0x6E,0x00, -0x00,0xC4,0x24,0x3A,0x04,0x84,0x4C,0x3C,0x20,0x00,0x00,0x00,0x00,0x0C,0xD4,0xBA, -0xFA,0xF4,0x0C,0xB0,0x00,0x00,0x00,0x00,0x29,0x90,0x66,0x00,0x00,0x96,0x21,0x83, -0x29,0xA0,0x00,0x08,0x20,0x70,0x19,0xA0,0x00,0x04,0x22,0x70,0x29,0xA0,0x00,0x04, -0x4A,0x89,0x67,0x00,0x00,0x2A,0x56,0x83,0x02,0x83,0xFF,0xFF,0xFF,0xFC,0x23,0xC8, -0xFF,0xF9,0x01,0x1C,0x23,0xC9,0xFF,0xF9,0x01,0x18,0x23,0xC3,0xFF,0xF9,0x01,0x20, -0x23,0xFC,0x00,0x00,0x03,0x01,0xFF,0xF9,0x01,0x28,0x61,0x00,0x01,0x2C,0x21,0xB0, -0x09,0xB0,0x00,0x00,0x18,0xC2,0x29,0x90,0x08,0xC6,0x00,0x04,0x24,0x3A,0x04,0x1A, -0x52,0x82,0x0C,0x82,0x00,0x00,0x00,0x28,0x66,0x00,0x00,0x04,0x42,0x82,0x23,0xC2, -0x00,0x00,0x19,0x98,0x02,0x70,0xF0,0x00,0x19,0x90,0x08,0xF0,0x00,0x1F,0x19,0x90, -0x22,0x30,0x09,0xB0,0x00,0x00,0x19,0x88,0x52,0x81,0x0C,0x81,0x00,0x00,0x00,0x1E, -0x66,0x00,0x00,0x04,0x42,0x81,0x21,0x81,0x09,0xB0,0x00,0x00,0x19,0x88,0x60,0x00, -0xFE,0xF8,0x24,0x30,0x09,0xB0,0x00,0x00,0x10,0x04,0x52,0xB0,0x29,0xA0,0x00,0x08, -0x60,0x00,0xFF,0xC2,0x24,0x30,0x09,0xB0,0x00,0x00,0x10,0x04,0x52,0xB0,0x29,0xA0, -0x00,0x0C,0x60,0x00,0xFF,0xB0,0x4E,0x75,0x4A,0xB0,0x09,0xB0,0x00,0x00,0x19,0x78, -0x67,0x00,0x00,0x86,0x22,0x30,0x09,0xB0,0x00,0x00,0x19,0x58,0x24,0x01,0xE7,0x89, -0xD2,0xB0,0x09,0xB0,0x00,0x00,0x18,0x72,0x36,0x30,0x19,0x90,0x08,0x03,0x00,0x0F, -0x66,0x00,0x00,0x66,0x8C,0xB0,0x09,0xB0,0x00,0x00,0x18,0xA2,0x53,0xB0,0x09,0xB0, -0x00,0x00,0x19,0x78,0x22,0x30,0x09,0xB0,0x00,0x00,0x19,0x58,0x52,0x81,0x0C,0x81, -0x00,0x00,0x00,0x0A,0x66,0x00,0x00,0x04,0x42,0x81,0x21,0x81,0x09,0xB0,0x00,0x00, -0x19,0x58,0x4C,0x3C,0x20,0x00,0x00,0x00,0x00,0x0C,0xD4,0xB0,0x09,0xB0,0x00,0x00, -0x10,0x04,0x06,0x82,0x00,0x00,0x00,0x1C,0x08,0x03,0x00,0x01,0x66,0x00,0x00,0x0E, -0x21,0xBC,0x00,0x00,0x00,0x20,0x29,0x90,0x60,0x00,0xFF,0x7E,0x21,0xBC,0x00,0x00, -0x00,0x30,0x29,0x90,0x60,0x00,0xFF,0x72,0x4E,0x75,0x2F,0x00,0x40,0xE7,0x20,0x39, -0xFF,0xF9,0x01,0x28,0x08,0x00,0x00,0x04,0x66,0x00,0x00,0x2C,0x4E,0x72,0x22,0x00, -0x46,0xFC,0x27,0x00,0x60,0x00,0xFF,0xE8,0x2F,0x00,0x40,0xE7,0x20,0x39,0xFF,0xF9, -0x01,0x28,0x08,0x00,0x00,0x0C,0x66,0x00,0x00,0x0E,0x4E,0x72,0x22,0x00,0x46,0xFC, -0x27,0x00,0x60,0x00,0xFF,0xE8,0x46,0xDF,0x20,0x1F,0x4E,0x75,0x2F,0x00,0x20,0x39, -0xFF,0xF9,0x00,0xE0,0x23,0xC0,0xFF,0xF9,0x00,0xE0,0x81,0xB9,0x00,0x00,0x19,0x54, -0x23,0xFC,0x00,0x00,0x09,0x09,0xFF,0xF9,0x01,0x28,0x20,0x1F,0x4E,0x73,0x00,0xB9, -0x00,0x00,0x00,0x00,0xFF,0xFC,0x16,0x10,0x00,0xB9,0x00,0x00,0x10,0x00,0x00,0x00, -0x19,0x54,0x23,0xFC,0x40,0x00,0x00,0x00,0xFF,0xFC,0x15,0x4C,0x4E,0x73,0x00,0xB9, -0x00,0x00,0x00,0x00,0xFF,0xFC,0x16,0x30,0x00,0xB9,0x00,0x00,0x20,0x00,0x00,0x00, -0x19,0x54,0x23,0xFC,0x20,0x00,0x00,0x00,0xFF,0xFC,0x15,0x4C,0x4E,0x73,0x00,0xB9, -0x00,0x00,0x00,0x00,0xFF,0xFC,0x16,0x50,0x00,0xB9,0x00,0x00,0x40,0x00,0x00,0x00, -0x19,0x54,0x23,0xFC,0x10,0x00,0x00,0x00,0xFF,0xFC,0x15,0x4C,0x4E,0x73,0x00,0xB9, -0x00,0x00,0x00,0x00,0xFF,0xFC,0x16,0x70,0x00,0xB9,0x00,0x00,0x80,0x00,0x00,0x00, -0x19,0x54,0x23,0xFC,0x08,0x00,0x00,0x00,0xFF,0xFC,0x15,0x4C,0x4E,0x73,0x4E,0x73, -0x2F,0x00,0x2F,0x01,0x2F,0x02,0x2F,0x08,0x2F,0x09,0x42,0x80,0x20,0x7C,0xFF,0xFB, -0x00,0x00,0x32,0x10,0x02,0x81,0x00,0x00,0x00,0xE7,0x0C,0x41,0x00,0x42,0x66,0x00, -0x00,0x0A,0x32,0x3C,0x0E,0x08,0x60,0x00,0x00,0x3E,0x0C,0x41,0x00,0x63,0x66,0x00, -0x00,0x0A,0x32,0x3C,0x04,0x08,0x60,0x00,0x00,0x2E,0x0C,0x41,0x00,0x84,0x66,0x00, -0x00,0x0A,0x32,0x3C,0x02,0x08,0x60,0x00,0x00,0x1E,0x0C,0x41,0x00,0xA5,0x66,0x00, -0x00,0x0A,0x32,0x3C,0x0D,0x08,0x60,0x00,0x00,0x0E,0x32,0x3C,0x00,0x08,0x34,0x3C, -0x80,0xE7,0x60,0x00,0x00,0x14,0x34,0x30,0x09,0xB0,0x00,0x00,0x19,0xAA,0x02,0x42, -0x30,0x00,0x82,0x42,0x34,0x3C,0x80,0xFF,0xB2,0x70,0x09,0xB0,0x00,0x00,0x19,0xAC, -0x67,0x00,0x00,0x0C,0x31,0x81,0x09,0xB0,0x00,0x00,0x19,0xAC,0x30,0x81,0x32,0x39, -0xFF,0xFC,0x15,0x66,0xC2,0x70,0x09,0xB0,0x00,0x00,0x19,0x02,0x67,0x00,0x00,0x0C, -0x32,0x10,0x02,0x41,0xFF,0xF7,0x60,0x00,0x00,0x08,0x32,0x10,0x00,0x41,0x00,0x08, -0xC2,0x42,0x22,0x70,0x09,0xB0,0x00,0x00,0x10,0x04,0xB2,0xA9,0x00,0x04,0x67,0x00, -0x00,0x12,0x23,0x41,0x00,0x04,0x23,0xF0,0x09,0xB0,0x00,0x00,0x18,0xB2,0xFF,0xF9, -0x00,0xE4,0x54,0x88,0x58,0x80,0x0C,0x80,0x00,0x00,0x00,0x10,0x66,0x00,0xFF,0x34, -0x22,0x5F,0x20,0x5F,0x24,0x1F,0x22,0x1F,0x20,0x1F,0x4E,0x75,0x61,0x00,0xFF,0x12, -0x4E,0x73,0xFF,0xFC,0x16,0x00,0xFF,0xFC,0x16,0x20,0xFF,0xFC,0x16,0x40,0xFF,0xFC, -0x16,0x60,0xFF,0xFC,0x0C,0x00,0xFF,0xFC,0x0D,0x00,0xFF,0xFC,0x0E,0x00,0xFF,0xFC, -0x0F,0x00,0xFF,0xFC,0x00,0x00,0xFF,0xFC,0x01,0x40,0xFF,0xFC,0x02,0x80,0xFF,0xFC, -0x03,0xC0,0xFF,0xFC,0x00,0x50,0xFF,0xFC,0x01,0x90,0xFF,0xFC,0x02,0xD0,0xFF,0xFC, -0x04,0x10,0x00,0x00,0x40,0x00,0x00,0x01,0x2F,0x60,0x00,0x02,0x1E,0xC0,0x00,0x03, -0x0E,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00, -0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x00,0x00, -0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x12,0x00,0x00, -0x00,0x13,0x00,0x00,0x00,0x2C,0x00,0x00,0x3E,0x00,0x00,0x2C,0x00,0x00,0x3E,0x00, -0x00,0x00,0x00,0x00,0x00,0x2D,0x00,0x00,0x3F,0x00,0x00,0x2D,0x00,0x00,0x3F,0x00, -0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00, -0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00, -0x77,0x61,0x6E,0x58,0x4C,0x20,0x66,0x69,0x72,0x6D,0x77,0x61,0x72,0x65,0x0A,0x43, -0x6F,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x43,0x29,0x20,0x32,0x30,0x30, -0x33,0x20,0x4B,0x72,0x7A,0x79,0x73,0x7A,0x74,0x6F,0x66,0x20,0x48,0x61,0x6C,0x61, -0x73,0x61,0x20,0x3C,0x6B,0x68,0x63,0x40,0x70,0x6D,0x2E,0x77,0x61,0x77,0x2E,0x70, -0x6C,0x3E,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 57ef2ac72..c9f0e0cb3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -897,7 +897,7 @@ typedef struct aironet_ioctl { unsigned short command; // What to do unsigned short len; // Len of data unsigned short ridnum; // rid number - unsigned char __user *data; // d-data + unsigned char *data; // d-data } aironet_ioctl; static char *swversion = "2.1"; @@ -4272,12 +4272,12 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) */ static ssize_t proc_read( struct file *file, - char __user *buffer, + char *buffer, size_t len, loff_t *offset); static ssize_t proc_write( struct file *file, - const char __user *buffer, + const char *buffer, size_t len, loff_t *offset ); static int proc_close( struct inode *inode, struct file *file ); @@ -4482,26 +4482,23 @@ static int takedown_proc_entry( struct net_device *dev, * to supply the data. */ static ssize_t proc_read( struct file *file, - char __user *buffer, + char *buffer, size_t len, loff_t *offset ) { - loff_t pos = *offset; + int i; + int pos; struct proc_data *priv = (struct proc_data*)file->private_data; - if (!priv->rbuffer) - return -EINVAL; + if( !priv->rbuffer ) return -EINVAL; - if (pos < 0) - return -EINVAL; - if (pos >= priv->readlen) - return 0; - if (len > priv->readlen - pos) - len = priv->readlen - pos; - if (copy_to_user(buffer, priv->rbuffer + pos, len)) - return -EFAULT; - *offset = pos + len; - return len; + pos = *offset; + for( i = 0; i+pos < priv->readlen && i < len; i++ ) { + if (put_user( priv->rbuffer[i+pos], buffer+i )) + return -EFAULT; + } + *offset += i; + return i; } /* @@ -4509,26 +4506,28 @@ static ssize_t proc_read( struct file *file, * to supply the data. */ static ssize_t proc_write( struct file *file, - const char __user *buffer, + const char *buffer, size_t len, loff_t *offset ) { - loff_t pos = *offset; + int i; + int pos; struct proc_data *priv = (struct proc_data*)file->private_data; - if (!priv->wbuffer) + if ( !priv->wbuffer ) { return -EINVAL; + } - if (pos < 0) - return -EINVAL; - if (pos >= priv->maxwritelen) - return 0; - if (len > priv->maxwritelen - pos) - len = priv->maxwritelen - pos; - if (copy_from_user(priv->wbuffer + pos, buffer, len)) - return -EFAULT; - *offset = pos + len; - return len; + pos = *offset; + + for( i = 0; i + pos < priv->maxwritelen && + i < len; i++ ) { + if (get_user( priv->wbuffer[i+pos], buffer + i )) + return -EFAULT; + } + if ( i+pos > priv->writelen ) priv->writelen = i+file->f_pos; + *offset += i; + return i; } static int proc_status_open( struct inode *inode, struct file *file ) { diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h new file mode 100644 index 000000000..ab6f83746 --- /dev/null +++ b/drivers/net/wireless/prism54/prismcompat.h @@ -0,0 +1,46 @@ +/* + * (C) 2004 Margit Schubert-While + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Compatibility header file to aid support of different kernel versions + */ + +#ifdef PRISM54_COMPAT24 +#include "prismcompat24.h" +#else /* PRISM54_COMPAT24 */ + +#ifndef _PRISM_COMPAT_H +#define _PRISM_COMPAT_H + +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error Firmware Loading is not configured in the kernel ! +#endif + +#define prism54_synchronize_irq(irq) synchronize_irq(irq) + +#define PRISM_FW_PDEV &priv->pdev->dev + +#endif /* _PRISM_COMPAT_H */ +#endif /* PRISM54_COMPAT24 */ diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 6e4965e66..b3f33a1bb 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -6248,13 +6248,10 @@ 1676 NetXtreme BCM5750 Gigabit Ethernet 1677 NetXtreme BCM5751 Gigabit Ethernet 167c NetXtreme BCM5750M Gigabit Ethernet - 167d NetXtreme BCM5751M Gigabit Ethernet - 167e NetXtreme BCM5751F Gigabit Ethernet 1696 NetXtreme BCM5782 Gigabit Ethernet 103c 12bc HP d530 CMT (DG746A) 14e4 000d NetXtreme BCM5782 1000Base-T 169c NetXtreme BCM5788 Gigabit Ethernet - 169d NetXtreme BCM5789 Gigabit Ethernet 16a6 NetXtreme BCM5702X Gigabit Ethernet 0e11 00bb NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T) 1028 0126 BCM5702 1000Base-T diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 701a83be3..1284d3d0a 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -164,7 +164,7 @@ pci_find_subsys(unsigned int vendor, unsigned int device, struct list_head *n; struct pci_dev *dev; - WARN_ON(in_interrupt()); + BUG_ON(in_interrupt()); spin_lock(&pci_bus_lock); n = from ? from->global_list.next : pci_devices.next; diff --git a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h deleted file mode 100644 index d2defe598..000000000 --- a/drivers/pcmcia/sa1100.h +++ /dev/null @@ -1,164 +0,0 @@ -/*====================================================================== - - Device driver for the PCMCIA control functionality of StrongARM - SA-1100 microprocessors. - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is John G. Dorsey - . Portions created by John G. Dorsey are - Copyright (C) 1999 John G. Dorsey. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#if !defined(_PCMCIA_SA1100_H) -# define _PCMCIA_SA1100_H - -#include -#include -#include -#include -#include "cs_internal.h" -#include "sa1100_generic.h" - -/* MECR: Expansion Memory Configuration Register - * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) - * - * MECR layout is: - * - * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0> - * - * (This layout is actually true only for the SA-1110; the FASTn bits are - * reserved on the SA-1100.) - */ - -#define MECR_SOCKET_0_SHIFT (0) -#define MECR_SOCKET_1_SHIFT (16) - -#define MECR_BS_MASK (0x1f) -#define MECR_FAST_MODE_MASK (0x01) - -#define MECR_BSIO_SHIFT (0) -#define MECR_BSA_SHIFT (5) -#define MECR_BSM_SHIFT (10) -#define MECR_FAST_SHIFT (15) - -#define MECR_SET(mecr, sock, shift, mask, bs) \ -((mecr)=((mecr)&~(((mask)<<(shift))<<\ - ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\ - (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))) - -#define MECR_GET(mecr, sock, shift, mask) \ -((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\ - (shift))&(mask)) - -#define MECR_BSIO_SET(mecr, sock, bs) \ -MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs)) - -#define MECR_BSIO_GET(mecr, sock) \ -MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK) - -#define MECR_BSA_SET(mecr, sock, bs) \ -MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs)) - -#define MECR_BSA_GET(mecr, sock) \ -MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK) - -#define MECR_BSM_SET(mecr, sock, bs) \ -MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs)) - -#define MECR_BSM_GET(mecr, sock) \ -MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK) - -#define MECR_FAST_SET(mecr, sock, fast) \ -MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast)) - -#define MECR_FAST_GET(mecr, sock) \ -MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK) - - -/* This function implements the BS value calculation for setting the MECR - * using integer arithmetic: - */ -static inline unsigned int sa1100_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns, - unsigned int cpu_clock_khz){ - unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000; - return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1); -} - -/* This function returns the (approxmiate) command assertion period, in - * nanoseconds, for a given CPU clock frequency and MECR BS value: - */ -static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, - unsigned int pcmcia_mecr_bs){ - return (((10000000 * 2) / cpu_clock_khz) * (3 * (pcmcia_mecr_bs + 1))) / 10; -} - - -/* SA-1100 PCMCIA Memory and I/O timing - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * The SA-1110 Developer's Manual, section 10.2.5, says the following: - * - * "To calculate the recommended BS_xx value for each address space: - * divide the command width time (the greater of twIOWR and twIORD, - * or the greater of twWE and twOE) by processor cycle time; divide - * by 2; divide again by 3 (number of BCLK's per command assertion); - * round up to the next whole number; and subtract 1." - * - * The PC Card Standard, Release 7, section 4.13.4, says that twIORD - * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has - * a minimum value of 165ns, as well. Section 4.7.2 (describing - * common and attribute memory write timing) says that twWE has a - * minimum value of 150ns for a 250ns cycle time (for 5V operation; - * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V - * operation, also section 4.7.4). Section 4.7.3 says that taOE - * has a maximum value of 150ns for a 300ns cycle time (for 5V - * operation), or 300ns for a 600ns cycle time (for 3.3V operation). - * - * When configuring memory maps, Card Services appears to adopt the policy - * that a memory access time of "0" means "use the default." The default - * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute - * and memory command width time is 150ns; the PCMCIA 3.3V attribute and - * memory command width time is 300ns. - */ -#define SA1100_PCMCIA_IO_ACCESS (165) -#define SA1100_PCMCIA_5V_MEM_ACCESS (150) -#define SA1100_PCMCIA_3V_MEM_ACCESS (300) - - -/* The socket driver actually works nicely in interrupt-driven form, - * so the (relatively infrequent) polling is "just to be sure." - */ -#define SA1100_PCMCIA_POLL_PERIOD (2*HZ) - -struct pcmcia_low_level; - -/* I/O pins replacing memory pins - * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) - * - * These signals change meaning when going from memory-only to - * memory-or-I/O interface: - */ -#define iostschg bvd1 -#define iospkr bvd2 - -#endif /* !defined(_PCMCIA_SA1100_H) */ diff --git a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c deleted file mode 100644 index d7249c033..000000000 --- a/drivers/pcmcia/sa11xx_core.c +++ /dev/null @@ -1,971 +0,0 @@ -/*====================================================================== - - Device driver for the PCMCIA control functionality of StrongARM - SA-1100 microprocessors. - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is John G. Dorsey - . Portions created by John G. Dorsey are - Copyright (C) 1999 John G. Dorsey. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ -/* - * Please see linux/Documentation/arm/SA1100/PCMCIA for more information - * on the low-level kernel interface. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "sa11xx_core.h" -#include "sa1100.h" - -#ifdef DEBUG -static int pc_debug; - -module_param(pc_debug, int, 0644); - -#define debug(skt, lvl, fmt, arg...) do { \ - if (pc_debug > (lvl)) \ - printk(KERN_DEBUG "skt%u: %s: " fmt, \ - (skt)->nr, __func__ , ## arg); \ -} while (0) - -#else -#define debug(skt, lvl, fmt, arg...) do { } while (0) -#endif - -#define to_sa1100_socket(x) container_of(x, struct sa1100_pcmcia_socket, socket) - -/* - * sa1100_pcmcia_default_mecr_timing - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Calculate MECR clock wait states for given CPU clock - * speed and command wait state. This function can be over- - * written by a board specific version. - * - * The default is to simply calculate the BS values as specified in - * the INTEL SA1100 development manual - * "Expansion Memory (PCMCIA) Configuration Register (MECR)" - * that's section 10.2.5 in _my_ version of the manual ;) - */ -static unsigned int -sa1100_pcmcia_default_mecr_timing(struct sa1100_pcmcia_socket *skt, - unsigned int cpu_speed, - unsigned int cmd_time) -{ - return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); -} - -static unsigned short -calc_speed(unsigned short *spds, int num, unsigned short dflt) -{ - unsigned short speed = 0; - int i; - - for (i = 0; i < num; i++) - if (speed < spds[i]) - speed = spds[i]; - if (speed == 0) - speed = dflt; - - return speed; -} - -/* sa1100_pcmcia_set_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * set MECR value for socket based on this sockets - * io, mem and attribute space access speed. - * Call board specific BS value calculation to allow boards - * to tweak the BS values. - */ -static int -sa1100_pcmcia_set_mecr(struct sa1100_pcmcia_socket *skt, unsigned int cpu_clock) -{ - u32 mecr, old_mecr; - unsigned long flags; - unsigned short speed; - unsigned int bs_io, bs_mem, bs_attr; - - speed = calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS); - bs_io = skt->ops->socket_get_timing(skt, cpu_clock, speed); - - speed = calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); - bs_mem = skt->ops->socket_get_timing(skt, cpu_clock, speed); - - speed = calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); - bs_attr = skt->ops->socket_get_timing(skt, cpu_clock, speed); - - local_irq_save(flags); - - old_mecr = mecr = MECR; - MECR_FAST_SET(mecr, skt->nr, 0); - MECR_BSIO_SET(mecr, skt->nr, bs_io); - MECR_BSA_SET(mecr, skt->nr, bs_attr); - MECR_BSM_SET(mecr, skt->nr, bs_mem); - if (old_mecr != mecr) - MECR = mecr; - - local_irq_restore(flags); - - debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n", - MECR_FAST_GET(mecr, skt->nr), - MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), - MECR_BSIO_GET(mecr, skt->nr)); - - return 0; -} - -static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt) -{ - struct pcmcia_state state; - unsigned int stat; - - memset(&state, 0, sizeof(struct pcmcia_state)); - - skt->ops->socket_state(skt, &state); - - stat = state.detect ? SS_DETECT : 0; - stat |= state.ready ? SS_READY : 0; - stat |= state.wrprot ? SS_WRPROT : 0; - stat |= state.vs_3v ? SS_3VCARD : 0; - stat |= state.vs_Xv ? SS_XVCARD : 0; - - /* The power status of individual sockets is not available - * explicitly from the hardware, so we just remember the state - * and regurgitate it upon request: - */ - stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - - if (skt->cs_state.flags & SS_IOCARD) - stat |= state.bvd1 ? SS_STSCHG : 0; - else { - if (state.bvd1 == 0) - stat |= SS_BATDEAD; - else if (state.bvd2 == 0) - stat |= SS_BATWARN; - } - return stat; -} - -/* - * sa1100_pcmcia_config_skt - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Convert PCMCIA socket state to our socket configure structure. - */ -static int -sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state) -{ - int ret; - - ret = skt->ops->configure_socket(skt, state); - if (ret == 0) { - /* - * This really needs a better solution. The IRQ - * may or may not be claimed by the driver. - */ - if (skt->irq_state != 1 && state->io_irq) { - skt->irq_state = 1; - set_irq_type(skt->irq, IRQT_FALLING); - } else if (skt->irq_state == 1 && state->io_irq == 0) { - skt->irq_state = 0; - set_irq_type(skt->irq, IRQT_NOEDGE); - } - - skt->cs_state = *state; - } - - if (ret < 0) - printk(KERN_ERR "sa1100_pcmcia: unable to configure " - "socket %d\n", skt->nr); - - return ret; -} - -/* sa1100_pcmcia_sock_init() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * (Re-)Initialise the socket, turning on status interrupts - * and PCMCIA bus. This must wait for power to stabilise - * so that the card status signals report correctly. - * - * Returns: 0 - */ -static int sa1100_pcmcia_sock_init(struct pcmcia_socket *sock) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - - debug(skt, 2, "initializing socket\n"); - - skt->ops->socket_init(skt); - return 0; -} - - -/* - * sa1100_pcmcia_suspend() - * ^^^^^^^^^^^^^^^^^^^^^^^ - * - * Remove power on the socket, disable IRQs from the card. - * Turn off status interrupts, and disable the PCMCIA bus. - * - * Returns: 0 - */ -static int sa1100_pcmcia_suspend(struct pcmcia_socket *sock) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - int ret; - - debug(skt, 2, "suspending socket\n"); - - ret = sa1100_pcmcia_config_skt(skt, &dead_socket); - if (ret == 0) - skt->ops->socket_suspend(skt); - - return ret; -} - -static spinlock_t status_lock = SPIN_LOCK_UNLOCKED; - -/* sa1100_check_status() - * ^^^^^^^^^^^^^^^^^^^^^ - */ -static void sa1100_check_status(struct sa1100_pcmcia_socket *skt) -{ - unsigned int events; - - debug(skt, 4, "entering PCMCIA monitoring thread\n"); - - do { - unsigned int status; - unsigned long flags; - - status = sa1100_pcmcia_skt_state(skt); - - spin_lock_irqsave(&status_lock, flags); - events = (status ^ skt->status) & skt->cs_state.csc_mask; - skt->status = status; - spin_unlock_irqrestore(&status_lock, flags); - - debug(skt, 4, "events: %s%s%s%s%s%s\n", - events == 0 ? "" : "", - events & SS_DETECT ? "DETECT " : "", - events & SS_READY ? "READY " : "", - events & SS_BATDEAD ? "BATDEAD " : "", - events & SS_BATWARN ? "BATWARN " : "", - events & SS_STSCHG ? "STSCHG " : ""); - - if (events) - pcmcia_parse_events(&skt->socket, events); - } while (events); -} - -/* sa1100_pcmcia_poll_event() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Let's poll for events in addition to IRQs since IRQ only is unreliable... - */ -static void sa1100_pcmcia_poll_event(unsigned long dummy) -{ - struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy; - debug(skt, 4, "polling for events\n"); - - mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD); - - sa1100_check_status(skt); -} - - -/* sa1100_pcmcia_interrupt() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * Service routine for socket driver interrupts (requested by the - * low-level PCMCIA init() operation via sa1100_pcmcia_thread()). - * The actual interrupt-servicing work is performed by - * sa1100_pcmcia_thread(), largely because the Card Services event- - * handling code performs scheduling operations which cannot be - * executed from within an interrupt context. - */ -static irqreturn_t sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) -{ - struct sa1100_pcmcia_socket *skt = dev; - - debug(skt, 3, "servicing IRQ %d\n", irq); - - sa1100_check_status(skt); - - return IRQ_HANDLED; -} - - -/* sa1100_pcmcia_get_status() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_status() operation for the in-kernel PCMCIA - * service (formerly SS_GetStatus in Card Services). Essentially just - * fills in bits in `status' according to internal driver state or - * the value of the voltage detect chipselect register. - * - * As a debugging note, during card startup, the PCMCIA core issues - * three set_socket() commands in a row the first with RESET deasserted, - * the second with RESET asserted, and the last with RESET deasserted - * again. Following the third set_socket(), a get_status() command will - * be issued. The kernel is looking for the SS_READY flag (see - * setup_socket(), reset_socket(), and unreset_socket() in cs.c). - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - - skt->status = sa1100_pcmcia_skt_state(skt); - *status = skt->status; - - return 0; -} - - -/* sa1100_pcmcia_get_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_socket() operation for the in-kernel PCMCIA - * service (formerly SS_GetSocket in Card Services). Not a very - * exciting routine. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - - debug(skt, 2, "\n"); - - *state = skt->cs_state; - - return 0; -} - -/* sa1100_pcmcia_set_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_socket() operation for the in-kernel PCMCIA - * service (formerly SS_SetSocket in Card Services). We more or - * less punt all of this work and let the kernel handle the details - * of power configuration, reset, &c. We also record the value of - * `state' in order to regurgitate it to the PCMCIA core later. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - - debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", - (state->csc_mask==0)?" ":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?" ":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", - state->Vcc, state->Vpp, state->io_irq); - - return sa1100_pcmcia_config_skt(skt, state); -} /* sa1100_pcmcia_set_socket() */ - - -/* sa1100_pcmcia_set_io_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_io_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetIOMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - unsigned short speed = map->speed; - - debug(skt, 2, "map %u speed %u start 0x%08x stop 0x%08x\n", - map->map, map->speed, map->start, map->stop); - debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", - (map->flags&MAP_PREFETCH)?"PREFETCH ":""); - - if (map->map >= MAX_IO_WIN) { - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; - } - - if (map->flags & MAP_ACTIVE) { - if (speed == 0) - speed = SA1100_PCMCIA_IO_ACCESS; - } else { - speed = 0; - } - - skt->spd_io[map->map] = speed; - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - - if (map->stop == 1) - map->stop = PAGE_SIZE-1; - - map->stop -= map->start; - map->stop += (unsigned long)skt->virt_io; - map->start = (unsigned long)skt->virt_io; - - return 0; -} /* sa1100_pcmcia_set_io_map() */ - - -/* sa1100_pcmcia_set_mem_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_mem_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetMemMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) -{ - struct sa1100_pcmcia_socket *skt = to_sa1100_socket(sock); - struct resource *res; - unsigned short speed = map->speed; - - debug(skt, 2, "map %u speed %u card_start %08x\n", - map->map, map->speed, map->card_start); - debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_ATTRIB)?"ATTRIB ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - - if (map->map >= MAX_WIN) - return -EINVAL; - - if (map->flags & MAP_ACTIVE) { - if (speed == 0) - speed = 300; - } else { - speed = 0; - } - - if (map->flags & MAP_ATTRIB) { - res = &skt->res_attr; - skt->spd_attr[map->map] = speed; - skt->spd_mem[map->map] = 0; - } else { - res = &skt->res_mem; - skt->spd_attr[map->map] = 0; - skt->spd_mem[map->map] = speed; - } - - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - - map->sys_stop -= map->sys_start; - map->sys_stop += res->start + map->card_start; - map->sys_start = res->start + map->card_start; - - return 0; -} - -struct bittbl { - unsigned int mask; - const char *name; -}; - -static struct bittbl status_bits[] = { - { SS_WRPROT, "SS_WRPROT" }, - { SS_BATDEAD, "SS_BATDEAD" }, - { SS_BATWARN, "SS_BATWARN" }, - { SS_READY, "SS_READY" }, - { SS_DETECT, "SS_DETECT" }, - { SS_POWERON, "SS_POWERON" }, - { SS_STSCHG, "SS_STSCHG" }, - { SS_3VCARD, "SS_3VCARD" }, - { SS_XVCARD, "SS_XVCARD" }, -}; - -static struct bittbl conf_bits[] = { - { SS_PWR_AUTO, "SS_PWR_AUTO" }, - { SS_IOCARD, "SS_IOCARD" }, - { SS_RESET, "SS_RESET" }, - { SS_DMA_MODE, "SS_DMA_MODE" }, - { SS_SPKR_ENA, "SS_SPKR_ENA" }, - { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, -}; - -static void -dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) -{ - char *b = *p; - int i; - - b += sprintf(b, "%-9s:", prefix); - for (i = 0; i < sz; i++) - if (val & bits[i].mask) - b += sprintf(b, " %s", bits[i].name); - *b++ = '\n'; - *p = b; -} - -/* show_status() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the /sys/class/pcmcia_socket/??/status file. - * - * Returns: the number of characters added to the buffer - */ -static ssize_t show_status(struct class_device *class_dev, char *buf) -{ - struct sa1100_pcmcia_socket *skt = container_of(class_dev, - struct sa1100_pcmcia_socket, socket.dev); - unsigned int clock = cpufreq_get(0); - unsigned long mecr = MECR; - char *p = buf; - - p+=sprintf(p, "slot : %d\n", skt->nr); - - dump_bits(&p, "status", skt->status, - status_bits, ARRAY_SIZE(status_bits)); - dump_bits(&p, "csc_mask", skt->cs_state.csc_mask, - status_bits, ARRAY_SIZE(status_bits)); - dump_bits(&p, "cs_flags", skt->cs_state.flags, - conf_bits, ARRAY_SIZE(conf_bits)); - - p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); - p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); - p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq); - - p+=sprintf(p, "I/O : %u (%u)\n", - calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS), - sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); - - p+=sprintf(p, "attribute: %u (%u)\n", - calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), - sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); - - p+=sprintf(p, "common : %u (%u)\n", - calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), - sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); - - return p-buf; -} -static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL); - - -static struct pccard_operations sa11xx_pcmcia_operations = { - .init = sa1100_pcmcia_sock_init, - .suspend = sa1100_pcmcia_suspend, - .get_status = sa1100_pcmcia_get_status, - .get_socket = sa1100_pcmcia_get_socket, - .set_socket = sa1100_pcmcia_set_socket, - .set_io_map = sa1100_pcmcia_set_io_map, - .set_mem_map = sa1100_pcmcia_set_mem_map, -}; - -int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) -{ - int i, res = 0; - - for (i = 0; i < nr; i++) { - if (irqs[i].sock != skt->nr) - continue; - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, skt); - if (res) - break; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - if (res) { - printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n", - irqs[i].irq, res); - - while (i--) - if (irqs[i].sock == skt->nr) - free_irq(irqs[i].irq, skt); - } - return res; -} -EXPORT_SYMBOL(sa11xx_request_irqs); - -void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) -{ - int i; - - for (i = 0; i < nr; i++) - if (irqs[i].sock == skt->nr) - free_irq(irqs[i].irq, skt); -} -EXPORT_SYMBOL(sa11xx_free_irqs); - -void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) -{ - int i; - - for (i = 0; i < nr; i++) - if (irqs[i].sock == skt->nr) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); -} -EXPORT_SYMBOL(sa11xx_disable_irqs); - -void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) -{ - int i; - - for (i = 0; i < nr; i++) - if (irqs[i].sock == skt->nr) { - set_irq_type(irqs[i].irq, IRQT_RISING); - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - } -} -EXPORT_SYMBOL(sa11xx_enable_irqs); - -static LIST_HEAD(sa1100_sockets); -static DECLARE_MUTEX(sa1100_sockets_lock); - -static const char *skt_names[] = { - "PCMCIA socket 0", - "PCMCIA socket 1", -}; - -struct skt_dev_info { - int nskt; - struct sa1100_pcmcia_socket skt[0]; -}; - -#define SKT_DEV_INFO_SIZE(n) \ - (sizeof(struct skt_dev_info) + (n)*sizeof(struct sa1100_pcmcia_socket)) - -int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) -{ - struct skt_dev_info *sinfo; - unsigned int cpu_clock; - int ret, i; - - /* - * set default MECR calculation if the board specific - * code did not specify one... - */ - if (!ops->socket_get_timing) - ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; - - down(&sa1100_sockets_lock); - - sinfo = kmalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); - if (!sinfo) { - ret = -ENOMEM; - goto out; - } - - memset(sinfo, 0, SKT_DEV_INFO_SIZE(nr)); - sinfo->nskt = nr; - - cpu_clock = cpufreq_get(0); - - /* - * Initialise the per-socket structure. - */ - for (i = 0; i < nr; i++) { - struct sa1100_pcmcia_socket *skt = &sinfo->skt[i]; - - skt->socket.ops = &sa11xx_pcmcia_operations; - skt->socket.owner = ops->owner; - skt->socket.dev.dev = dev; - - init_timer(&skt->poll_timer); - skt->poll_timer.function = sa1100_pcmcia_poll_event; - skt->poll_timer.data = (unsigned long)skt; - skt->poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; - - skt->nr = first + i; - skt->irq = NO_IRQ; - skt->dev = dev; - skt->ops = ops; - - skt->res_skt.start = _PCMCIA(skt->nr); - skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; - skt->res_skt.name = skt_names[skt->nr]; - skt->res_skt.flags = IORESOURCE_MEM; - - ret = request_resource(&iomem_resource, &skt->res_skt); - if (ret) - goto out_err_1; - - skt->res_io.start = _PCMCIAIO(skt->nr); - skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; - skt->res_io.name = "io"; - skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - - ret = request_resource(&skt->res_skt, &skt->res_io); - if (ret) - goto out_err_2; - - skt->res_mem.start = _PCMCIAMem(skt->nr); - skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; - skt->res_mem.name = "memory"; - skt->res_mem.flags = IORESOURCE_MEM; - - ret = request_resource(&skt->res_skt, &skt->res_mem); - if (ret) - goto out_err_3; - - skt->res_attr.start = _PCMCIAAttr(skt->nr); - skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; - skt->res_attr.name = "attribute"; - skt->res_attr.flags = IORESOURCE_MEM; - - ret = request_resource(&skt->res_skt, &skt->res_attr); - if (ret) - goto out_err_4; - - skt->virt_io = ioremap(skt->res_io.start, 0x10000); - if (skt->virt_io == NULL) { - ret = -ENOMEM; - goto out_err_5; - } - - list_add(&skt->node, &sa1100_sockets); - - /* - * We initialize the MECR to default values here, because - * we are not guaranteed to see a SetIOMap operation at - * runtime. - */ - sa1100_pcmcia_set_mecr(skt, cpu_clock); - - ret = ops->hw_init(skt); - if (ret) - goto out_err_6; - - skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; - skt->socket.irq_mask = 0; - skt->socket.map_size = PAGE_SIZE; - skt->socket.pci_irq = skt->irq; - skt->socket.io_offset = (unsigned long)skt->virt_io; - - skt->status = sa1100_pcmcia_skt_state(skt); - - ret = pcmcia_register_socket(&skt->socket); - if (ret) - goto out_err_7; - - WARN_ON(skt->socket.sock != i); - - add_timer(&skt->poll_timer); - - class_device_create_file(&skt->socket.dev, &class_device_attr_status); - } - - dev_set_drvdata(dev, sinfo); - ret = 0; - goto out; - - do { - struct sa1100_pcmcia_socket *skt = &sinfo->skt[i]; - - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - - out_err_7: - flush_scheduled_work(); - - ops->hw_shutdown(skt); - out_err_6: - list_del(&skt->node); - iounmap(skt->virt_io); - out_err_5: - release_resource(&skt->res_attr); - out_err_4: - release_resource(&skt->res_mem); - out_err_3: - release_resource(&skt->res_io); - out_err_2: - release_resource(&skt->res_skt); - out_err_1: - i--; - } while (i > 0); - - kfree(sinfo); - - out: - up(&sa1100_sockets_lock); - return ret; -} -EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); - -int sa11xx_drv_pcmcia_remove(struct device *dev) -{ - struct skt_dev_info *sinfo = dev_get_drvdata(dev); - int i; - - dev_set_drvdata(dev, NULL); - - down(&sa1100_sockets_lock); - for (i = 0; i < sinfo->nskt; i++) { - struct sa1100_pcmcia_socket *skt = &sinfo->skt[i]; - - del_timer_sync(&skt->poll_timer); - - pcmcia_unregister_socket(&skt->socket); - - flush_scheduled_work(); - - skt->ops->hw_shutdown(skt); - - sa1100_pcmcia_config_skt(skt, &dead_socket); - - list_del(&skt->node); - iounmap(skt->virt_io); - skt->virt_io = NULL; - release_resource(&skt->res_attr); - release_resource(&skt->res_mem); - release_resource(&skt->res_io); - release_resource(&skt->res_skt); - } - up(&sa1100_sockets_lock); - - kfree(sinfo); - - return 0; -} -EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove); - -#ifdef CONFIG_CPU_FREQ - -/* sa1100_pcmcia_update_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due - * to a core clock frequency change) is needed, this routine establishes - * new BS_xx values consistent with the clock speed `clock'. - */ -static void sa1100_pcmcia_update_mecr(unsigned int clock) -{ - struct sa1100_pcmcia_socket *skt; - - down(&sa1100_sockets_lock); - list_for_each_entry(skt, &sa1100_sockets, node) - sa1100_pcmcia_set_mecr(skt, clock); - up(&sa1100_sockets_lock); -} - -/* sa1100_pcmcia_notifier() - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * When changing the processor core clock frequency, it is necessary - * to adjust the MECR timings accordingly. We've recorded the timings - * requested by Card Services, so this is just a matter of finding - * out what our current speed is, and then recomputing the new MECR - * values. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freqs = data; - - switch (val) { - case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) - sa1100_pcmcia_update_mecr(freqs->new); - break; - - case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) - sa1100_pcmcia_update_mecr(freqs->new); - break; - } - - return 0; -} - -static struct notifier_block sa1100_pcmcia_notifier_block = { - .notifier_call = sa1100_pcmcia_notifier -}; - -static int __init sa11xx_pcmcia_init(void) -{ - int ret; - - printk(KERN_INFO "SA11xx PCMCIA\n"); - - ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier (%d)\n", ret); - - return ret; -} -module_init(sa11xx_pcmcia_init); - -static void __exit sa11xx_pcmcia_exit(void) -{ - cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -} - -module_exit(sa11xx_pcmcia_exit); -#endif - -MODULE_AUTHOR("John Dorsey "); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); -MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/pcmcia/sa11xx_core.h b/drivers/pcmcia/sa11xx_core.h deleted file mode 100644 index aadf7c0b6..000000000 --- a/drivers/pcmcia/sa11xx_core.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * linux/include/asm/arch/pcmcia.h - * - * Copyright (C) 2000 John G Dorsey - * - * This file contains definitions for the low-level SA-1100 kernel PCMCIA - * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. - */ -#ifndef _ASM_ARCH_PCMCIA -#define _ASM_ARCH_PCMCIA - -/* include the world */ -#include -#include -#include -#include -#include -#include -#include "cs_internal.h" - -struct device; - -/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only - * has support for two. This shows up in lots of hardwired ways, such - * as the fact that MECR only has enough bits to configure two sockets. - * Since it's so entrenched in the hardware, limiting the software - * in this way doesn't seem too terrible. - */ -#define SA1100_PCMCIA_MAX_SOCK (2) - -struct pcmcia_state { - unsigned detect: 1, - ready: 1, - bvd1: 1, - bvd2: 1, - wrprot: 1, - vs_3v: 1, - vs_Xv: 1; -}; - -/* - * This structure encapsulates per-socket state which we might need to - * use when responding to a Card Services query of some kind. - */ -struct sa1100_pcmcia_socket { - struct pcmcia_socket socket; - - /* - * Info from low level handler - */ - struct device *dev; - unsigned int nr; - unsigned int irq; - - /* - * Core PCMCIA state - */ - struct pcmcia_low_level *ops; - - unsigned int status; - socket_state_t cs_state; - - unsigned short spd_io[MAX_IO_WIN]; - unsigned short spd_mem[MAX_WIN]; - unsigned short spd_attr[MAX_WIN]; - - struct resource res_skt; - struct resource res_io; - struct resource res_mem; - struct resource res_attr; - void *virt_io; - - unsigned int irq_state; - - struct timer_list poll_timer; - struct list_head node; -}; - -struct pcmcia_low_level { - struct module *owner; - - int (*hw_init)(struct sa1100_pcmcia_socket *); - void (*hw_shutdown)(struct sa1100_pcmcia_socket *); - - void (*socket_state)(struct sa1100_pcmcia_socket *, struct pcmcia_state *); - int (*configure_socket)(struct sa1100_pcmcia_socket *, const socket_state_t *); - - /* - * Enable card status IRQs on (re-)initialisation. This can - * be called at initialisation, power management event, or - * pcmcia event. - */ - void (*socket_init)(struct sa1100_pcmcia_socket *); - - /* - * Disable card status IRQs and PCMCIA bus on suspend. - */ - void (*socket_suspend)(struct sa1100_pcmcia_socket *); - - /* - * Calculate MECR timing clock wait states - */ - unsigned int (*socket_get_timing)(struct sa1100_pcmcia_socket *, - unsigned int cpu_speed, unsigned int cmd_time); -}; - -struct pcmcia_irqs { - int sock; - int irq; - const char *str; -}; - -int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); -void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); -void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); -void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); - -extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); -extern int sa11xx_drv_pcmcia_remove(struct device *dev); - -#endif diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index e190f21ed..bf4e08f0e 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -37,20 +37,6 @@ config UNIX98_PTYS Read the instructions in pertaining to pseudo terminals. It's safe to say N. -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on UNIX98_PTYS - default "256" - help - The maximum number of Unix98 PTYs that can be used at any one time. - The default is 256, and should be enough for desktop systems. Server - machines which support incoming telnet/rlogin/ssh connections and/or - serve several X terminals may want to increase this: every incoming - connection and every xterm uses up one PTY. - - When not in use, each additional set of 256 PTYs occupy - approximately 8 KB of kernel memory on 32-bit architectures. - comment "S/390 character device drivers" config TN3270 diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 6997d61dc..9d30ebf0b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.142 $ + * $Revision: 1.141 $ */ #include @@ -37,7 +37,6 @@ * SECTION: exported variables of dasd.c */ debug_info_t *dasd_debug_area; -struct dasd_discipline *dasd_diag_discipline_pointer; MODULE_AUTHOR("Holger Smolinski "); MODULE_DESCRIPTION("Linux on S/390 DASD device driver," @@ -1991,8 +1990,6 @@ dasd_init(void) DBF_EVENT(DBF_EMERG, "%s", "debug area created"); - dasd_diag_discipline_pointer = NULL; - rc = devfs_mk_dir("dasd"); if (rc) goto failed; @@ -2025,7 +2022,6 @@ module_init(dasd_init); module_exit(dasd_exit); EXPORT_SYMBOL(dasd_debug_area); -EXPORT_SYMBOL(dasd_diag_discipline_pointer); EXPORT_SYMBOL(dasd_add_request_head); EXPORT_SYMBOL(dasd_add_request_tail); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 9b667cd5a..08532025b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1289,7 +1289,7 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); - rc = copy_to_user((long __user *) args, (long *) stats, + rc = copy_to_user((long *) args, (long *) stats, sizeof(struct dasd_rssd_perf_stats_t)); } dasd_sfree_request(cqr, cqr->device); @@ -1319,10 +1319,10 @@ dasd_eckd_get_attrib (struct block_device *bdev, int no, long args) private = (struct dasd_eckd_private *) device->private; attrib = private->attrib; - - rc = copy_to_user((long __user *) args, (long *) &attrib, + + rc = copy_to_user((long *) args, (long *) &attrib, sizeof (struct attrib_data_t)); - + return rc; } @@ -1346,7 +1346,7 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) if (device == NULL) return -ENODEV; - if (copy_from_user(&attrib, (void __user *) args, + if (copy_from_user(&attrib, (void *) args, sizeof (struct attrib_data_t))) { return -EFAULT; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index f99652855..ed8507e79 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/css.c * driver for channel subsystem - * $Revision: 1.77 $ + * $Revision: 1.74 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -166,12 +166,10 @@ css_get_subchannel_status(struct subchannel *sch, int schid) if (sch && sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) return CIO_REVALIDATE; - if (sch && !sch->lpm) - return CIO_NO_PATH; return CIO_OPER; } -static int +static inline int css_evaluate_subchannel(int irq, int slow) { int event, ret, disc; @@ -190,11 +188,7 @@ css_evaluate_subchannel(int irq, int slow) return -EAGAIN; /* Will be done on the slow path. */ } event = css_get_subchannel_status(sch, irq); - CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", - irq, event, sch?(disc?"disconnected":"normal"):"unknown", - slow?"slow":"fast"); switch (event) { - case CIO_NO_PATH: case CIO_GONE: if (!sch) { /* Never used this subchannel. Ignore. */ @@ -202,8 +196,7 @@ css_evaluate_subchannel(int irq, int slow) break; } if (sch->driver && sch->driver->notify && - sch->driver->notify(&sch->dev, event)) { - cio_disable_subchannel(sch); + sch->driver->notify(&sch->dev, CIO_GONE)) { device_set_disconnected(sch); ret = 0; break; @@ -212,7 +205,6 @@ css_evaluate_subchannel(int irq, int slow) * Unregister subchannel. * The device will be killed automatically. */ - cio_disable_subchannel(sch); device_unregister(&sch->dev); /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; @@ -274,44 +266,23 @@ css_rescan_devices(void) } } -struct slow_subchannel { - struct list_head slow_list; - unsigned long schid; -}; - -static LIST_HEAD(slow_subchannels_head); -static spinlock_t slow_subchannel_lock = SPIN_LOCK_UNLOCKED; - static void -css_trigger_slow_path(void) +css_evaluate_slow_subchannel(unsigned long schid) { - CIO_TRACE_EVENT(4, "slowpath"); + css_evaluate_subchannel(schid, 1); +} +void +css_trigger_slow_path(void) +{ if (need_rescan) { need_rescan = 0; css_rescan_devices(); return; } - - spin_lock_irq(&slow_subchannel_lock); - while (!list_empty(&slow_subchannels_head)) { - struct slow_subchannel *slow_sch = - list_entry(slow_subchannels_head.next, - struct slow_subchannel, slow_list); - - list_del_init(slow_subchannels_head.next); - spin_unlock_irq(&slow_subchannel_lock); - css_evaluate_subchannel(slow_sch->schid, 1); - spin_lock_irq(&slow_subchannel_lock); - kfree(slow_sch); - } - spin_unlock_irq(&slow_subchannel_lock); + css_walk_subchannel_slow_list(css_evaluate_slow_subchannel); } -typedef void (*workfunc)(void *); -DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL); -struct workqueue_struct *slow_path_wq; - /* * Rescan for new devices. FIXME: This is slow. * This function is called when we have lost CRWs due to overflows and we have @@ -472,6 +443,14 @@ s390_root_dev_unregister(struct device *dev) device_unregister(dev); } +struct slow_subchannel { + struct list_head slow_list; + unsigned long schid; +}; + +static LIST_HEAD(slow_subchannels_head); +static spinlock_t slow_subchannel_lock = SPIN_LOCK_UNLOCKED; + int css_enqueue_subchannel_slow(unsigned long schid) { @@ -505,7 +484,25 @@ css_clear_subchannel_slow_list(void) spin_unlock_irqrestore(&slow_subchannel_lock, flags); } +void +css_walk_subchannel_slow_list(void (*fn)(unsigned long)) +{ + unsigned long flags; + spin_lock_irqsave(&slow_subchannel_lock, flags); + while (!list_empty(&slow_subchannels_head)) { + struct slow_subchannel *slow_sch = + list_entry(slow_subchannels_head.next, + struct slow_subchannel, slow_list); + + list_del_init(slow_subchannels_head.next); + spin_unlock_irqrestore(&slow_subchannel_lock, flags); + fn(slow_sch->schid); + spin_lock_irqsave(&slow_subchannel_lock, flags); + kfree(slow_sch); + } + spin_unlock_irqrestore(&slow_subchannel_lock, flags); +} int css_slow_subchannels_exist(void) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a921b1fea..1b7a39b68 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.120 $ + * $Revision: 1.117 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -159,11 +159,6 @@ init_ccw_bus_type (void) ret = -ENOMEM; /* FIXME: better errno ? */ goto out_err; } - slow_path_wq = create_singlethread_workqueue("kslowcrw"); - if (!slow_path_wq) { - ret = -ENOMEM; /* FIXME: better errno ? */ - goto out_err; - } if ((ret = bus_register (&ccw_bus_type))) goto out_err; @@ -179,8 +174,6 @@ out_err: destroy_workqueue(ccw_device_work); if (ccw_device_notify_work) destroy_workqueue(ccw_device_notify_work); - if (slow_path_wq) - destroy_workqueue(slow_path_wq); return ret; } @@ -526,8 +519,7 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) cdev = to_ccwdev(dev); if ((cdev->private->state == DEV_STATE_DISCONNECTED) && (cdev->private->devno == devno) && - (!strncmp(cdev->dev.bus_id, sibling->dev.bus_id, - BUS_ID_SIZE))) { + (!strncmp(cdev->dev.bus_id, sibling->dev.bus_id, 4))) { cdev->private->state = DEV_STATE_NOT_OPER; break; } @@ -654,7 +646,9 @@ ccw_device_call_sch_unregister(void *data) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); - device_unregister(&sch->dev); + /* Check if device is registered. */ + if (!list_empty(&sch->dev.node)) + device_unregister(&sch->dev); /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; cio_modify(sch); @@ -683,7 +677,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); INIT_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister, (void *) cdev); - queue_work(slow_path_wq, &cdev->private->kick_work); + queue_work(ccw_device_work, &cdev->private->kick_work); break; case DEV_STATE_BOXED: /* Device did not respond in time. */ diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 508f1a7fb..c131f13d3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -458,6 +458,20 @@ ccw_device_nopath_notify(void *data) } } +void +device_call_nopath_notify(struct subchannel *sch) +{ + struct ccw_device *cdev; + + if (!sch->dev.driver_data) + return; + cdev = sch->dev.driver_data; + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_nopath_notify, (void *)cdev); + queue_work(ccw_device_notify_work, &cdev->private->kick_work); +} + + void ccw_device_verify_done(struct ccw_device *cdev, int err) { @@ -1071,103 +1085,103 @@ ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event) * device statemachine */ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { - [DEV_STATE_NOT_OPER] = { - [DEV_EVENT_NOTOPER] = ccw_device_nop, - [DEV_EVENT_INTERRUPT] = ccw_device_bug, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_NOT_OPER] { + [DEV_EVENT_NOTOPER] ccw_device_nop, + [DEV_EVENT_INTERRUPT] ccw_device_bug, + [DEV_EVENT_TIMEOUT] ccw_device_nop, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_SENSE_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_SENSE_PGID] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_sense_pgid_irq, + [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_SENSE_ID] = { - [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_SENSE_ID] { + [DEV_EVENT_NOTOPER] ccw_device_recog_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_sense_id_irq, + [DEV_EVENT_TIMEOUT] ccw_device_recog_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_OFFLINE] { + [DEV_EVENT_NOTOPER] ccw_device_offline_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_offline_irq, + [DEV_EVENT_TIMEOUT] ccw_device_nop, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_VERIFY] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_verify_irq, + [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_ONLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, - [DEV_EVENT_VERIFY] = ccw_device_online_verify, + [DEV_STATE_ONLINE] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_irq, + [DEV_EVENT_TIMEOUT] ccw_device_online_timeout, + [DEV_EVENT_VERIFY] ccw_device_online_verify, }, - [DEV_STATE_W4SENSE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_online_verify, + [DEV_STATE_W4SENSE] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_w4sense, + [DEV_EVENT_TIMEOUT] ccw_device_nop, + [DEV_EVENT_VERIFY] ccw_device_online_verify, }, - [DEV_STATE_DISBAND_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_DISBAND_PGID] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_disband_irq, + [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_BOXED] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, - [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_BOXED] { + [DEV_EVENT_NOTOPER] ccw_device_offline_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_stlck_done, + [DEV_EVENT_TIMEOUT] ccw_device_stlck_done, + [DEV_EVENT_VERIFY] ccw_device_nop, }, /* states to wait for i/o completion before doing something */ - [DEV_STATE_CLEAR_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_CLEAR_VERIFY] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_clear_verify, + [DEV_EVENT_TIMEOUT] ccw_device_nop, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_TIMEOUT_KILL] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME + [DEV_STATE_TIMEOUT_KILL] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_killing_irq, + [DEV_EVENT_TIMEOUT] ccw_device_killing_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, //FIXME }, - [DEV_STATE_WAIT4IO] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout, - [DEV_EVENT_VERIFY] = ccw_device_wait4io_verify, + [DEV_STATE_WAIT4IO] { + [DEV_EVENT_NOTOPER] ccw_device_online_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_wait4io_irq, + [DEV_EVENT_TIMEOUT] ccw_device_wait4io_timeout, + [DEV_EVENT_VERIFY] ccw_device_wait4io_verify, }, - [DEV_STATE_QUIESCE] = { - [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done, - [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done, - [DEV_EVENT_TIMEOUT] = ccw_device_quiesce_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_QUIESCE] { + [DEV_EVENT_NOTOPER] ccw_device_quiesce_done, + [DEV_EVENT_INTERRUPT] ccw_device_quiesce_done, + [DEV_EVENT_TIMEOUT] ccw_device_quiesce_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, /* special states for devices gone not operational */ - [DEV_STATE_DISCONNECTED] = { - [DEV_EVENT_NOTOPER] = ccw_device_nop, - [DEV_EVENT_INTERRUPT] = ccw_device_start_id, - [DEV_EVENT_TIMEOUT] = ccw_device_bug, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_DISCONNECTED] { + [DEV_EVENT_NOTOPER] ccw_device_nop, + [DEV_EVENT_INTERRUPT] ccw_device_start_id, + [DEV_EVENT_TIMEOUT] ccw_device_bug, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_DISCONNECTED_SENSE_ID] = { - [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper, - [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_STATE_DISCONNECTED_SENSE_ID] { + [DEV_EVENT_NOTOPER] ccw_device_recog_notoper, + [DEV_EVENT_INTERRUPT] ccw_device_sense_id_irq, + [DEV_EVENT_TIMEOUT] ccw_device_recog_timeout, + [DEV_EVENT_VERIFY] ccw_device_nop, }, - [DEV_STATE_CMFCHANGE] = { - [DEV_EVENT_NOTOPER] = ccw_device_change_cmfstate, - [DEV_EVENT_INTERRUPT] = ccw_device_change_cmfstate, - [DEV_EVENT_TIMEOUT] = ccw_device_change_cmfstate, - [DEV_EVENT_VERIFY] = ccw_device_change_cmfstate, + [DEV_STATE_CMFCHANGE] { + [DEV_EVENT_NOTOPER] ccw_device_change_cmfstate, + [DEV_EVENT_INTERRUPT] ccw_device_change_cmfstate, + [DEV_EVENT_TIMEOUT] ccw_device_change_cmfstate, + [DEV_EVENT_VERIFY] ccw_device_change_cmfstate, }, }; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index f4c9779d2..614f18aaf 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1301,7 +1301,7 @@ next: } kfree(irq_ptr->qdr); - kfree(irq_ptr); + kfree(irq_ptr->actual_alloc); /* This frees irq_ptr itself. */ } static void @@ -2565,6 +2565,8 @@ qdio_initialize(struct qdio_initialize *init_data) int qdio_allocate(struct qdio_initialize *init_data) { + char *mem; + unsigned off; struct qdio_irq *irq_ptr; char dbf_text[15]; @@ -2586,17 +2588,21 @@ qdio_allocate(struct qdio_initialize *init_data) qdio_allocate_do_dbf(init_data); /* create irq */ - irq_ptr=kmalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA); + mem = kmalloc(sizeof(struct qdio_irq) + 0xff, GFP_KERNEL | GFP_DMA); QDIO_DBF_TEXT0(0,setup,"irq_ptr:"); QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); - if (!irq_ptr) { + if (!mem) { QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n"); return -ENOMEM; } + irq_ptr = (struct qdio_irq *) mem; + if ((off = ((unsigned long) mem) & 0xff) != 0) + irq_ptr = (struct qdio_irq *)(mem + 0x100 - off); memset(irq_ptr,0,sizeof(struct qdio_irq)); + irq_ptr->actual_alloc = mem; init_MUTEX(&irq_ptr->setting_up_sema); diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 0922d4dac..f6a41c1e3 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -644,5 +644,7 @@ struct qdio_irq { struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct semaphore setting_up_sema; + + char *actual_alloc; }; #endif diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index 36790af32..8dd8becea 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -1,5 +1,5 @@ /* - * $Id: iucv.c,v 1.33 2004/05/24 10:19:18 braunu Exp $ + * $Id: iucv.c,v 1.32 2004/05/18 09:28:43 braunu Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.33 $ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.32 $ * */ @@ -352,7 +352,7 @@ do { \ static void iucv_banner(void) { - char vbuf[] = "$Revision: 1.33 $"; + char vbuf[] = "$Revision: 1.32 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -2368,8 +2368,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf) iucv_debug(2, "found a matching handler"); break; - } else - h = NULL; + } } spin_unlock_irqrestore (&iucv_lock, flags); if (h) { diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 570a93b67..2b3753d55 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.54 2004/05/28 08:04:14 braunu Exp $ + * $Id: netiucv.c,v 1.53 2004/05/07 14:29:37 mschwide Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.54 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.53 $ * */ @@ -60,6 +60,7 @@ #include #include #include +#include #include "iucv.h" #include "fsm.h" @@ -166,10 +167,10 @@ static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) } static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static __u8 iucvMagic[16] = { - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 -}; +//static __u8 iucvMagic[16] = { +// 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, +// 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 +//}; /** * This mask means the 16-byte IUCV "magic" and the origin userid must @@ -768,10 +769,18 @@ conn_action_start(fsm_instance *fi, int event, void *arg) struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_connection *conn = ev->conn; __u16 msglimit; - int rc; + int rc, len; + __u8 iucvMagic[16] = { + 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 + }; pr_debug("%s() called\n", __FUNCTION__); + len = (IFNAMSIZ < sizeof(conn->netdev->name)) ? + IFNAMSIZ : sizeof(conn->netdev->name); + memcpy(iucvMagic, conn->netdev->name, len); + ASCEBC (iucvMagic, len); if (conn->handle == 0) { conn->handle = iucv_register_program(iucvMagic, conn->userid, mask, @@ -1949,7 +1958,7 @@ static struct device_driver netiucv_driver = { static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.54 $"; + char vbuf[] = "$Revision: 1.53 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 96c4243a2..a299fa1db 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -23,7 +23,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.110 $" +#define VERSION_QETH_H "$Revision: 1.108 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" @@ -91,14 +91,10 @@ debug_event(qeth_dbf_##name,level,(void*)(addr),len); \ } while (0) -extern DEFINE_PER_CPU(char[256], qeth_dbf_txt_buf); - -#define QETH_DBF_TEXT_(name,level,text...) \ - do { \ - char* dbf_txt_buf = get_cpu_var(qeth_dbf_txt_buf); \ - sprintf(dbf_txt_buf, text); \ - debug_text_event(qeth_dbf_##name,level,dbf_txt_buf); \ - put_cpu_var(qeth_dbf_txt_buf); \ +#define QETH_DBF_TEXT_(name,level,text...) \ + do { \ + sprintf(qeth_dbf_text_buf, text); \ + debug_text_event(qeth_dbf_##name,level,qeth_dbf_text_buf);\ } while (0) #define QETH_DBF_SPRINTF(name,level,text...) \ @@ -380,6 +376,11 @@ enum qeth_qdio_buffer_states { * outbound: filled by driver; owned by hardware in order to be sent */ QETH_QDIO_BUF_PRIMED, + /* + * inbound only: an error condition has been detected for a buffer + * the buffer will be discarded (not read out) + */ + QETH_QDIO_BUF_ERROR, }; enum qeth_qdio_info_states { @@ -418,7 +419,7 @@ struct qeth_qdio_q { struct qeth_qdio_out_buffer { struct qdio_buffer *buffer; - atomic_t state; + volatile enum qeth_qdio_buffer_states state; volatile int next_element_to_fill; struct sk_buff_head skb_list; }; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8aefa28c2..ceab62acf 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.121 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.112 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier * - * $Revision: 1.121 $ $Date: 2004/06/11 16:32:15 $ + * $Revision: 1.112 $ $Date: 2004/05/19 09:28:21 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ qeth_eyecatcher(void) #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.121 $" +#define VERSION_QETH_C "$Revision: 1.112 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -91,8 +91,7 @@ static debug_info_t *qeth_dbf_control = NULL; static debug_info_t *qeth_dbf_trace = NULL; static debug_info_t *qeth_dbf_sense = NULL; static debug_info_t *qeth_dbf_qerr = NULL; - -DEFINE_PER_CPU(char[256], qeth_dbf_txt_buf); +static char qeth_dbf_text_buf[255]; /** * some more definitions and declarations @@ -2345,17 +2344,13 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) } static inline void -qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, +qeth_clear_output_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf) { int i; struct sk_buff *skb; - /* is PCI flag set on buffer? */ - if (buf->buffer->element[0].flags & 0x40) - atomic_dec(&queue->set_pci_flags_count); - - for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i){ + for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i){ buf->buffer->element[i].length = 0; buf->buffer->element[i].addr = NULL; buf->buffer->element[i].flags = 0; @@ -2365,7 +2360,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, } } buf->next_element_to_fill = 0; - atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); + buf->state = QETH_QDIO_BUF_EMPTY; } static inline void @@ -2582,17 +2577,8 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, QETH_DBF_TEXT(trace, 2, "flushbuf"); QETH_DBF_TEXT_(trace, 2, " err%d", rc); queue->card->stats.tx_errors += count; - /* ok, since do_QDIO went wrong the buffers have not been given - * to the hardware. they still belong to us, so we can clear - * them and reuse then, i.e. set back next_buf_to_fill*/ - for (i = index; i < index + count; ++i) { - buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - qeth_clear_output_buffer(queue, buf); - } - queue->next_buf_to_fill = index; return; } - atomic_add(count, &queue->used_buffers); #ifdef CONFIG_QETH_PERF_STATS queue->card->perf_stats.bufs_sent += count; #endif @@ -2630,11 +2616,11 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) queue->do_pack = 0; /* flush packing buffers */ buffer = &queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == - QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - atomic_set(&buffer->state,QETH_QDIO_BUF_PRIMED); + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); + if (buffer->next_element_to_fill > 0) { + buffer->state = QETH_QDIO_BUF_PRIMED; flush_count++; + atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; @@ -2648,17 +2634,17 @@ static inline void qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int) { struct qeth_qdio_out_buffer *buffer; - int index; - index = queue->next_buf_to_fill; - buffer = &queue->bufs[index]; - if((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)){ + buffer = &queue->bufs[queue->next_buf_to_fill]; + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); + if (buffer->next_element_to_fill > 0){ /* it's a packing buffer */ - atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + buffer->state = QETH_QDIO_BUF_PRIMED; + atomic_inc(&queue->used_buffers); + qeth_flush_buffers(queue, under_int, queue->next_buf_to_fill, + 1); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; - qeth_flush_buffers(queue, under_int, index, 1); } } @@ -2701,9 +2687,13 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, qeth_schedule_recovery(card); return; } - qeth_clear_output_buffer(queue, buffer); + /* is PCI flag set on buffer? */ + if (buffer->buffer->element[0].flags & 0x40) + atomic_dec(&queue->set_pci_flags_count); + + qeth_clear_output_buffer(card, buffer); + atomic_dec(&queue->used_buffers); } - atomic_sub(count, &queue->used_buffers); netif_wake_queue(card->dev); #ifdef CONFIG_QETH_PERF_STATS @@ -2896,8 +2886,8 @@ qeth_free_qdio_buffers(struct qeth_card *card) /* free outbound qdio_qs */ for (i = 0; i < card->qdio.no_out_queues; ++i){ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) - qeth_clear_output_buffer(card->qdio.out_qs[i], - &card->qdio.out_qs[i]->bufs[j]); + qeth_clear_output_buffer(card, &card->qdio. + out_qs[i]->bufs[j]); kfree(card->qdio.out_qs[i]); } kfree(card->qdio.out_qs); @@ -2914,8 +2904,8 @@ qeth_clear_qdio_buffers(struct qeth_card *card) for (i = 0; i < card->qdio.no_out_queues; ++i) if (card->qdio.out_qs[i]){ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) - qeth_clear_output_buffer(card->qdio.out_qs[i], - &card->qdio.out_qs[i]->bufs[j]); + qeth_clear_output_buffer(card, &card->qdio. + out_qs[i]->bufs[j]); } } @@ -2967,8 +2957,8 @@ qeth_init_qdio_queues(struct qeth_card *card) memset(card->qdio.out_qs[i]->qdio_bufs, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j){ - qeth_clear_output_buffer(card->qdio.out_qs[i], - &card->qdio.out_qs[i]->bufs[j]); + qeth_clear_output_buffer(card, &card->qdio. + out_qs[i]->bufs[j]); } card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->next_buf_to_fill = 0; @@ -3680,7 +3670,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf if (!queue->do_pack) { QETH_DBF_TEXT(trace, 6, "fillbfnp"); /* set state to PRIMED -> will be flushed */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); + buf->state = QETH_QDIO_BUF_PRIMED; } else { QETH_DBF_TEXT(trace, 6, "fillbfpa"); #ifdef CONFIG_QETH_PERF_STATS @@ -3692,7 +3682,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf * packed buffer if full -> set state PRIMED * -> will be flushed */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); + buf->state = QETH_QDIO_BUF_PRIMED; } } return 0; @@ -3705,27 +3695,32 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, { struct qeth_qdio_out_buffer *buffer; int index; + int rc = 0; QETH_DBF_TEXT(trace, 6, "dosndpfa"); spin_lock(&queue->lock); - index = queue->next_buf_to_fill; - buffer = &queue->bufs[queue->next_buf_to_fill]; - /* - * check if buffer is empty to make sure that we do not 'overtake' - * ourselves and try to fill a buffer that is already primed - */ - if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { + /* do we have empty buffers? */ + if (atomic_read(&queue->used_buffers) >= (QDIO_MAX_BUFFERS_PER_Q - 1)){ card->stats.tx_dropped++; + rc = -EBUSY; spin_unlock(&queue->lock); - return -EBUSY; + goto out; } + index = queue->next_buf_to_fill; + buffer = &queue->bufs[queue->next_buf_to_fill]; + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + atomic_inc(&queue->used_buffers); + spin_unlock(&queue->lock); + + /* go on sending ... */ + netif_wake_queue(skb->dev); qeth_fill_buffer(queue, buffer, (char *)hdr, skb); qeth_flush_buffers(queue, 0, index, 1); - spin_unlock(&queue->lock); - return 0; +out: + return rc; } static inline int @@ -3741,43 +3736,35 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, QETH_DBF_TEXT(trace, 6, "dosndpkt"); spin_lock(&queue->lock); - start_index = queue->next_buf_to_fill; - buffer = &queue->bufs[queue->next_buf_to_fill]; - /* - * check if buffer is empty to make sure that we do not 'overtake' - * ourselves and try to fill a buffer that is already primed - */ - if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ + /* do we have empty buffers? */ + if (atomic_read(&queue->used_buffers) >= (QDIO_MAX_BUFFERS_PER_Q - 2)){ card->stats.tx_dropped++; - spin_unlock(&queue->lock); - return -EBUSY; + rc = -EBUSY; + goto out; } + start_index = queue->next_buf_to_fill; + buffer = &queue->bufs[queue->next_buf_to_fill]; + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); if (queue->do_pack){ /* does packet fit in current buffer? */ - if((QETH_MAX_BUFFER_ELEMENTS(card) - - buffer->next_element_to_fill) < elements_needed){ + if((QETH_MAX_BUFFER_ELEMENTS(card) - buffer->next_element_to_fill) + < elements_needed){ /* ... no -> set state PRIMED */ - atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + buffer->state = QETH_QDIO_BUF_PRIMED; flush_count++; + atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; buffer = &queue->bufs[queue->next_buf_to_fill]; - /* we did a step forward, so check buffer state again */ - if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ - card->stats.tx_dropped++; - qeth_flush_buffers(queue, 0, start_index, 1); - spin_unlock(&queue->lock); - /* return EBUSY because we sent old packet, not - * the current one */ - return -EBUSY; - } } } + qeth_fill_buffer(queue, buffer, (char *)hdr, skb); - if (atomic_read(&buffer->state) == QETH_QDIO_BUF_PRIMED){ + if (buffer->state == QETH_QDIO_BUF_PRIMED){ /* next time fill the next buffer */ flush_count++; + atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; } @@ -3789,8 +3776,9 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, if (!atomic_read(&queue->set_pci_flags_count)) qeth_flush_buffers_on_no_pci(queue, 0); - +out: spin_unlock(&queue->lock); + return rc; } @@ -4090,43 +4078,21 @@ out_error: static int qeth_send_ipa_arp_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, - int len, int (*reply_cb)(struct qeth_card *, - struct qeth_reply *, - unsigned long), + int len, int (*reply_cb) + (struct qeth_card *, + struct qeth_reply*, unsigned long), void *reply_param) { - QETH_DBF_TEXT(trace,4,"sendarp"); - - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); - return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, - reply_cb, reply_param); -} - -static int -qeth_send_ipa_snmp_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, - int len, int (*reply_cb)(struct qeth_card *, - struct qeth_reply *, - unsigned long), - void *reply_param) -{ - u16 s1, s2; + int rc; - QETH_DBF_TEXT(trace,4,"sendsnmp"); + QETH_DBF_TEXT(trace,4,"sendarp"); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); - /* adjust PDU length fields in IPA_PDU_HEADER */ - s1 = (u32) IPA_PDU_HEADER_SIZE + len; - s2 = (u32) len; - memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); - memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); - memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); - memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); - return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, - reply_cb, reply_param); + rc = qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, + reply_cb, reply_param); + return rc; } static struct qeth_cmd_buffer * @@ -4169,7 +4135,8 @@ qeth_arp_query(struct qeth_card *card, char *udata) rc = qeth_send_ipa_arp_cmd(card, iob, QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, - qeth_arp_query_cb, (void *)&qinfo); + qeth_arp_query_cb, + (void *)&qinfo); if (rc) { tmp = rc; PRINT_WARN("Error while querying ARP cache on %s: %s " @@ -4215,10 +4182,9 @@ qeth_snmp_command_cb(struct qeth_card *card, struct qeth_reply *reply, } data_len = *((__u16*)QETH_IPA_PDU_LEN_PDU1(data)); if (cmd->data.setadapterparms.hdr.seq_no == 1) - data_len -= (__u16)((char *)&snmp->data - (char *)cmd); - else data_len -= (__u16)((char*)&snmp->request - (char *)cmd); - + else + data_len -= (__u16)((char *)&snmp->data - (char *)cmd); /* check if there is enough room in userspace */ if ((qinfo->udata_len - qinfo->udata_offset) < data_len) { QETH_DBF_TEXT_(trace, 4, "scer3%i", -ENOMEM); @@ -4227,17 +4193,15 @@ qeth_snmp_command_cb(struct qeth_card *card, struct qeth_reply *reply, } QETH_DBF_TEXT_(trace, 4, "snore%i", cmd->data.setadapterparms.hdr.used_total); - QETH_DBF_TEXT_(trace, 4, "sseqn%i", cmd->data.setadapterparms.hdr.seq_no); + QETH_DBF_TEXT_(trace, 4, "sseqn%i", cmd->data.setassparms.hdr.seq_no); /*copy entries to user buffer*/ if (cmd->data.setadapterparms.hdr.seq_no == 1) { memcpy(qinfo->udata + qinfo->udata_offset, - (char *)snmp, - data_len + offsetof(struct qeth_snmp_cmd,data)); + (char *)snmp,offsetof(struct qeth_snmp_cmd,data)); qinfo->udata_offset += offsetof(struct qeth_snmp_cmd, data); - } else { - memcpy(qinfo->udata + qinfo->udata_offset, - (char *)&snmp->request, data_len); } + memcpy(qinfo->udata + qinfo->udata_offset, + (char *)&snmp->data, data_len); qinfo->udata_offset += data_len; /* check if all replies received ... */ QETH_DBF_TEXT_(trace, 4, "srtot%i", @@ -4248,6 +4212,7 @@ qeth_snmp_command_cb(struct qeth_card *card, struct qeth_reply *reply, cmd->data.setadapterparms.hdr.used_total) return 1; return 0; + } static struct qeth_cmd_buffer * @@ -4279,8 +4244,7 @@ qeth_snmp_command(struct qeth_card *card, char *udata) { struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd; - struct qeth_snmp_ureq *ureq; - int req_len; + struct qeth_snmp_ureq ureq; struct qeth_arp_query_info qinfo = {0, }; int rc = 0; @@ -4293,39 +4257,30 @@ qeth_snmp_command(struct qeth_card *card, char *udata) "on %s!\n", card->info.if_name); return -EOPNOTSUPP; } - /* skip 4 bytes (data_len struct member) to get req_len */ - if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int))) + if (copy_from_user(&ureq, udata, sizeof(struct qeth_snmp_ureq))) return -EFAULT; - ureq = kmalloc(req_len, GFP_KERNEL); - if (!ureq) { - QETH_DBF_TEXT(trace, 2, "snmpnome"); - return -ENOMEM; - } - if (copy_from_user(ureq, udata, req_len)){ - kfree(ureq); - return -EFAULT; - } - qinfo.udata_len = ureq->hdr.data_len; - if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL))){ - kfree(ureq); + qinfo.udata_len = ureq.hdr.data_len; + if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL))) return -ENOMEM; - } memset(qinfo.udata, 0, qinfo.udata_len); qinfo.udata_offset = sizeof(struct qeth_snmp_ureq_hdr); iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, - QETH_SNMP_SETADP_CMDLENGTH + req_len); + QETH_SNMP_SETADP_CMDLENGTH+ureq.hdr.req_len); cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len); - rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, - qeth_snmp_command_cb, (void *)&qinfo); + memcpy(&cmd->data.setadapterparms.data.snmp, &ureq.cmd, + sizeof(struct qeth_snmp_cmd)); + rc = qeth_send_ipa_arp_cmd(card, iob, + QETH_SETADP_BASE_LEN + QETH_ARP_DATA_SIZE + + ureq.hdr.req_len, qeth_snmp_command_cb, + (void *)&qinfo); if (rc) PRINT_WARN("SNMP command failed on %s: (0x%x)\n", card->info.if_name, rc); else copy_to_user(udata, qinfo.udata, qinfo.udata_len); - kfree(ureq); + kfree(qinfo.udata); return rc; } @@ -4521,17 +4476,13 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data); break; case SIOC_QETH_GET_CARD_TYPE: - if ((card->info.type == QETH_CARD_TYPE_OSAE) && - !card->info.guestlan) - return 1; - return 0; break; case SIOCGMIIPHY: - mii_data = if_mii(rq); + mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data; mii_data->phy_id = 0; break; case SIOCGMIIREG: - mii_data = if_mii(rq); + mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data; if (mii_data->phy_id != 0) rc = -EINVAL; else @@ -4546,7 +4497,7 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = -EPERM; break; } - mii_data = if_mii(rq); + mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data; if (mii_data->phy_id != 0) rc = -EINVAL; else diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 910c5f566..5178a6cc2 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.32 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.30 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.32 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.30 $"; /*****************************************************************************/ /* */ @@ -1447,16 +1447,14 @@ qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf, { int rc; int signum; - char *tmp, *tmp2; + char *tmp; tmp = strsep((char **) &buf, "\n"); - if (!strncmp(tmp, "unregister", 10)){ - if ((rc = qeth_notifier_unregister(current))) - return rc; - return count; + if (!strcmp(tmp, "unregister")){ + return qeth_notifier_unregister(current); } - signum = simple_strtoul(tmp, &tmp2, 10); + signum = simple_strtoul(buf, &tmp, 10); if ((signum < 0) || (signum > 32)){ PRINT_WARN("Signal number %d is out of range\n", signum); return -EINVAL; @@ -1467,7 +1465,7 @@ qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf, return count; } -static DRIVER_ATTR(notifier_register, 0200, 0, +static DRIVER_ATTR(notifier_register, 0644, 0, qeth_driver_notifier_register_store); int diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c new file mode 100644 index 000000000..9f75c87c3 --- /dev/null +++ b/drivers/scsi/3w-9xxx.c @@ -0,0 +1,2153 @@ +/* + 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. + + Written By: Adam Radford + + Copyright (C) 2004 Applied Micro Circuits Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Bugs/Comments/Suggestions should be mailed to: + linuxraid@amcc.com + + For more information, goto: + http://www.amcc.com + + Note: This version of the driver does not contain a bundled firmware + image. + + History + ------- + 2.26.02.000 - Driver cleanup for kernel submission. + 2.26.02.001 - Replace schedule_timeout() calls with msleep(). +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "3w-9xxx.h" + +/* Globals */ +static const char *twa_driver_version="2.26.02.001"; +static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; +static unsigned int twa_device_extension_count; +static int twa_major = -1; +extern struct timezone sys_tz; + +/* Module parameters */ +MODULE_AUTHOR ("AMCC"); +MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver"); +MODULE_LICENSE("GPL"); + +/* Function prototypes */ +static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header); +static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id); +static char *twa_aen_severity_lookup(unsigned char severity_code); +static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id); +static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int twa_chrdev_open(struct inode *inode, struct file *file); +static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host); +static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id); +static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id); +static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, + u32 set_features, unsigned short current_fw_srl, + unsigned short current_fw_arch_id, + unsigned short current_fw_branch, + unsigned short current_fw_build, + unsigned short *fw_on_ctlr_srl, + unsigned short *fw_on_ctlr_arch_id, + unsigned short *fw_on_ctlr_branch, + unsigned short *fw_on_ctlr_build, + u32 *init_connect_result); +static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length); +static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds); +static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds); +static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal); +static int twa_reset_device_extension(TW_Device_Extension *tw_dev); +static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); +static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg); +static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); +static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code); +static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id); + +/* Functions */ + +/* Show some statistics about the card */ +static ssize_t twa_show_stats(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(class_dev); + TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; + unsigned long flags = 0; + ssize_t len; + + spin_lock_irqsave(tw_dev->host->host_lock, flags); + len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Current pending commands: %4d\n" + "Max pending commands: %4d\n" + "Last sgl length: %4d\n" + "Max sgl length: %4d\n" + "Last sector count: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "SCSI Aborts/Timeouts: %4d\n" + "AEN's: %4d\n", + twa_driver_version, + tw_dev->posted_request_count, + tw_dev->max_posted_request_count, + tw_dev->pending_request_count, + tw_dev->max_pending_request_count, + tw_dev->sgl_entries, + tw_dev->max_sgl_entries, + tw_dev->sector_count, + tw_dev->max_sector_count, + tw_dev->num_resets, + tw_dev->num_aborts, + tw_dev->aen_count); + spin_unlock_irqrestore(tw_dev->host->host_lock, flags); + return len; +} /* End twa_show_stats() */ + +/* This function will set a devices queue depth */ +static ssize_t twa_store_queue_depth(struct device *dev, const char *buf, size_t count) +{ + int queue_depth; + struct scsi_device *sdev = to_scsi_device(dev); + + queue_depth = simple_strtoul(buf, NULL, 0); + if (queue_depth > TW_Q_LENGTH-2) + return -EINVAL; + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); + + return count; +} /* End twa_store_queue_depth() */ + +/* Create sysfs 'queue_depth' entry */ +static struct device_attribute twa_queue_depth_attr = { + .attr = { + .name = "queue_depth", + .mode = S_IRUSR | S_IWUSR, + }, + .store = twa_store_queue_depth +}; + +/* Device attributes initializer */ +static struct device_attribute *twa_dev_attrs[] = { + &twa_queue_depth_attr, + NULL, +}; + +/* Create sysfs 'stats' entry */ +static struct class_device_attribute twa_host_stats_attr = { + .attr = { + .name = "stats", + .mode = S_IRUGO, + }, + .show = twa_show_stats +}; + +/* Host attributes initializer */ +static struct class_device_attribute *twa_host_attrs[] = { + &twa_host_stats_attr, + NULL, +}; + +/* File operations struct for character device */ +static struct file_operations twa_fops = { + .owner = THIS_MODULE, + .ioctl = twa_chrdev_ioctl, + .open = twa_chrdev_open, + .release = NULL +}; + +/* This function will complete an aen request from the isr */ +static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) +{ + TW_Command_Full *full_command_packet; + TW_Command *command_packet; + TW_Command_Apache_Header *header; + unsigned short aen; + int retval = 1; + + header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; + tw_dev->posted_request_count--; + aen = header->status_block.error; + full_command_packet = tw_dev->command_packet_virt[request_id]; + command_packet = &full_command_packet->command.oldcommand; + + /* First check for internal completion of set param for time sync */ + if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) { + /* Keep reading the queue in case there are more aen's */ + if (twa_aen_read_queue(tw_dev, request_id)) + goto out2; + else { + retval = 0; + goto out; + } + } + + switch (aen) { + case TW_AEN_QUEUE_EMPTY: + /* Quit reading the queue if this is the last one */ + break; + case TW_AEN_SYNC_TIME_WITH_HOST: + twa_aen_sync_time(tw_dev, request_id); + retval = 0; + goto out; + default: + twa_aen_queue_event(tw_dev, header); + + /* If there are more aen's, keep reading the queue */ + if (twa_aen_read_queue(tw_dev, request_id)) + goto out2; + else { + retval = 0; + goto out; + } + } + retval = 0; +out2: + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); +out: + return retval; +} /* End twa_aen_complete() */ + +/* This function will drain aen queue */ +static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) +{ + int request_id = 0; + char cdb[TW_MAX_CDB_LEN]; + TW_SG_Apache sglist[1]; + int finished = 0, count = 0; + TW_Command_Full *full_command_packet; + TW_Command_Apache_Header *header; + unsigned short aen; + int first_reset = 0, queue = 0, retval = 1; + + if (no_check_reset) + first_reset = 0; + else + first_reset = 1; + + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + + /* Initialize cdb */ + memset(&cdb, 0, TW_MAX_CDB_LEN); + cdb[0] = REQUEST_SENSE; /* opcode */ + cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ + + /* Initialize sglist */ + memset(&sglist, 0, sizeof(TW_SG_Apache)); + sglist[0].length = TW_SECTOR_SIZE; + sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + + if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); + goto out; + } + + /* Mark internal command */ + tw_dev->srb[request_id] = NULL; + + do { + /* Send command to the board */ + if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense"); + goto out; + } + + /* Now poll for completion */ + if (twa_poll_response(tw_dev, request_id, 30)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue"); + tw_dev->posted_request_count--; + goto out; + } + + tw_dev->posted_request_count--; + header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; + aen = header->status_block.error; + queue = 0; + count++; + + switch (aen) { + case TW_AEN_QUEUE_EMPTY: + if (first_reset != 1) + goto out; + else + finished = 1; + break; + case TW_AEN_SOFT_RESET: + if (first_reset == 0) + first_reset = 1; + else + queue = 1; + break; + case TW_AEN_SYNC_TIME_WITH_HOST: + break; + default: + queue = 1; + } + + /* Now queue an event info */ + if (queue) + twa_aen_queue_event(tw_dev, header); + } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); + + if (count == TW_MAX_AEN_DRAIN) + goto out; + + retval = 0; +out: + tw_dev->state[request_id] = TW_S_INITIAL; + return retval; +} /* End twa_aen_drain_queue() */ + +/* This function will queue an event */ +static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) +{ + u32 local_time; + struct timeval time; + TW_Event *event; + unsigned short aen; + char host[16]; + + tw_dev->aen_count++; + + /* Fill out event info */ + event = tw_dev->event_queue[tw_dev->error_index]; + + /* Check for clobber */ + host[0] = '\0'; + if (tw_dev->host) { + sprintf(host, " scsi%d:", tw_dev->host->host_no); + if (event->retrieved == TW_AEN_NOT_RETRIEVED) + tw_dev->aen_clobber = 1; + } + + aen = header->status_block.error; + memset(event, 0, sizeof(TW_Event)); + + event->severity = TW_SEV_OUT(header->status_block.severity__reserved); + do_gettimeofday(&time); + local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + event->time_stamp_sec = local_time; + event->aen_code = aen; + event->retrieved = TW_AEN_NOT_RETRIEVED; + event->sequence_id = tw_dev->error_sequence_id; + tw_dev->error_sequence_id++; + + header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; + event->parameter_len = strlen(header->err_specific_desc); + memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len); + if (event->severity != TW_AEN_SEVERITY_DEBUG) + printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", + host, + twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)), + TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, + twa_string_lookup(twa_aen_table, aen), + header->err_specific_desc); + else + tw_dev->aen_count--; + + if ((tw_dev->error_index + 1) == TW_Q_LENGTH) + tw_dev->event_queue_wrapped = 1; + tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; +} /* End twa_aen_queue_event() */ + +/* This function will read the aen queue from the isr */ +static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) +{ + char cdb[TW_MAX_CDB_LEN]; + TW_SG_Apache sglist[1]; + TW_Command_Full *full_command_packet; + int retval = 1; + + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + + /* Initialize cdb */ + memset(&cdb, 0, TW_MAX_CDB_LEN); + cdb[0] = REQUEST_SENSE; /* opcode */ + cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ + + /* Initialize sglist */ + memset(&sglist, 0, sizeof(TW_SG_Apache)); + sglist[0].length = TW_SECTOR_SIZE; + sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + + /* Mark internal command */ + tw_dev->srb[request_id] = NULL; + + /* Now post the command packet */ + if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue"); + goto out; + } + retval = 0; +out: + return retval; +} /* End twa_aen_read_queue() */ + +/* This function will look up an AEN severity string */ +static char *twa_aen_severity_lookup(unsigned char severity_code) +{ + char *retval = NULL; + + if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || + (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) + goto out; + + retval = twa_aen_severity_table[severity_code]; +out: + return retval; +} /* End twa_aen_severity_lookup() */ + +/* This function will sync firmware time with the host time */ +static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) +{ + u32 schedulertime; + struct timeval utc; + TW_Command_Full *full_command_packet; + TW_Command *command_packet; + TW_Param_Apache *param; + u32 local_time; + + /* Fill out the command packet */ + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + command_packet = &full_command_packet->command.oldcommand; + command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); + command_packet->request_id = request_id; + command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id]; + command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; + command_packet->size = TW_COMMAND_SIZE; + command_packet->byte6_offset.parameter_count = 1; + + /* Setup the param */ + param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; + memset(param, 0, TW_SECTOR_SIZE); + param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */ + param->parameter_id = 0x3; /* SchedulerTime */ + param->parameter_size_bytes = 4; + + /* Convert system time in UTC to local time seconds since last + Sunday 12:00AM */ + do_gettimeofday(&utc); + local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); + schedulertime = local_time - (3 * 86400); + schedulertime = schedulertime % 604800; + + memcpy(param->data, &schedulertime, sizeof(u32)); + + /* Mark internal command */ + tw_dev->srb[request_id] = NULL; + + /* Now post the command */ + twa_post_command_packet(tw_dev, request_id, 1); +} /* End twa_aen_sync_time() */ + +/* This function will allocate memory and check if it is correctly aligned */ +static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) +{ + int i; + dma_addr_t dma_handle; + unsigned long *cpu_addr; + int retval = 1; + + cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); + if (!cpu_addr) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); + goto out; + } + + if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); + pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); + goto out; + } + + memset(cpu_addr, 0, size*TW_Q_LENGTH); + + for (i = 0; i < TW_Q_LENGTH; i++) { + switch(which) { + case 0: + tw_dev->command_packet_phys[i] = dma_handle+(i*size); + tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); + break; + case 1: + tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); + tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); + break; + } + } + retval = 0; +out: + return retval; +} /* End twa_allocate_memory() */ + +/* This function will check the status register for unexpected bits */ +static int twa_check_bits(u32 status_reg_value) +{ + int retval = 1; + + if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) + goto out; + if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) + goto out; + + retval = 0; +out: + return retval; +} /* End twa_check_bits() */ + +/* This function will check the srl and decide if we are compatible */ +static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) +{ + int retval = 1; + unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; + unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; + u32 init_connect_result = 0; + + if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, + TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL, + TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH, + TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl, + &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, + &fw_on_ctlr_build, &init_connect_result)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL"); + goto out; + } + + tw_dev->working_srl = TW_CURRENT_FW_SRL; + tw_dev->working_branch = TW_CURRENT_FW_BRANCH; + tw_dev->working_build = TW_CURRENT_FW_BUILD; + + /* Try base mode compatibility */ + if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { + if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, + TW_EXTENDED_INIT_CONNECT, + TW_BASE_FW_SRL, TW_9000_ARCH_ID, + TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD, + &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, + &fw_on_ctlr_branch, &fw_on_ctlr_build, + &init_connect_result)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL"); + goto out; + } + if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { + if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware"); + } else { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver"); + } + goto out; + } + tw_dev->working_srl = TW_BASE_FW_SRL; + tw_dev->working_branch = TW_BASE_FW_BRANCH; + tw_dev->working_build = TW_BASE_FW_BUILD; + } + retval = 0; +out: + return retval; +} /* End twa_check_srl() */ + +/* This function handles ioctl for the character device */ +static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + long timeout; + unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; + dma_addr_t dma_handle; + int request_id = 0; + unsigned int sequence_id = 0; + unsigned char event_index, start_index; + TW_Ioctl_Driver_Command driver_command; + TW_Ioctl_Buf_Apache *tw_ioctl; + TW_Lock *tw_lock; + TW_Command_Full *full_command_packet; + TW_Compatibility_Info *tw_compat_info; + TW_Event *event; + struct timeval current_time; + u32 current_time_ms; + TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)]; + int retval = TW_IOCTL_ERROR_OS_EFAULT; + + /* Only let one of these through at a time */ + if (down_interruptible(&tw_dev->ioctl_sem)) { + retval = TW_IOCTL_ERROR_OS_EINTR; + goto out; + } + + /* First copy down the driver command */ + if (copy_from_user(&driver_command, (void *)arg, sizeof(TW_Ioctl_Driver_Command))) + goto out2; + + /* Check data buffer size */ + if (driver_command.buffer_length > TW_MAX_SECTORS * 512) { + retval = TW_IOCTL_ERROR_OS_EINVAL; + goto out2; + } + + /* Hardware can only do multiple of 512 byte transfers */ + data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; + + /* Now allocate ioctl buf memory */ + cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle); + if (!cpu_addr) { + retval = TW_IOCTL_ERROR_OS_ENOMEM; + goto out2; + } + + tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; + + /* Now copy down the entire ioctl */ + if (copy_from_user(tw_ioctl, (void *)arg, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) + goto out3; + + /* See which ioctl we are doing */ + switch (cmd) { + case TW_IOCTL_FIRMWARE_PASS_THROUGH: + spin_lock_irqsave(tw_dev->host->host_lock, flags); + twa_get_request_id(tw_dev, &request_id); + + /* Flag internal command */ + tw_dev->srb[request_id] = 0; + + /* Flag chrdev ioctl */ + tw_dev->chrdev_request_id = request_id; + + full_command_packet = &tw_ioctl->firmware_command; + + /* Load request id and sglist for both command types */ + twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); + + memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); + + /* Now post the command packet to the controller */ + twa_post_command_packet(tw_dev, request_id, 1); + spin_unlock_irqrestore(tw_dev->host->host_lock, flags); + + timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; + + /* Now wait for command to complete */ + timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); + + /* Check if we timed out, got a signal, or didn't get + an interrupt */ + if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) { + /* Now we need to reset the board */ + if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) { + retval = timeout; + } else { + printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", + tw_dev->host->host_no, TW_DRIVER, 0xc, + cmd); + retval = TW_IOCTL_ERROR_OS_EIO; + } + spin_lock_irqsave(tw_dev->host->host_lock, flags); + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + tw_dev->posted_request_count--; + twa_reset_device_extension(tw_dev); + spin_unlock_irqrestore(tw_dev->host->host_lock, flags); + goto out3; + } + + /* Now copy in the command packet response */ + memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); + + /* Now complete the io */ + spin_lock_irqsave(tw_dev->host->host_lock, flags); + tw_dev->posted_request_count--; + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + spin_unlock_irqrestore(tw_dev->host->host_lock, flags); + break; + case TW_IOCTL_GET_COMPATIBILITY_INFO: + tw_ioctl->driver_command.status = 0; + /* Copy compatiblity struct into ioctl data buffer */ + tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; + strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version)); + tw_compat_info->working_srl = tw_dev->working_srl; + tw_compat_info->working_branch = tw_dev->working_branch; + tw_compat_info->working_build = tw_dev->working_build; + break; + case TW_IOCTL_GET_LAST_EVENT: + if (tw_dev->event_queue_wrapped) { + if (tw_dev->aen_clobber) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; + tw_dev->aen_clobber = 0; + } else + tw_ioctl->driver_command.status = 0; + } else { + if (!tw_dev->error_index) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + tw_ioctl->driver_command.status = 0; + } + event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH; + memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); + tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; + break; + case TW_IOCTL_GET_FIRST_EVENT: + if (tw_dev->event_queue_wrapped) { + if (tw_dev->aen_clobber) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; + tw_dev->aen_clobber = 0; + } else + tw_ioctl->driver_command.status = 0; + event_index = tw_dev->error_index; + } else { + if (!tw_dev->error_index) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + tw_ioctl->driver_command.status = 0; + event_index = 0; + } + memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); + tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; + break; + case TW_IOCTL_GET_NEXT_EVENT: + event = (TW_Event *)tw_ioctl->data_buffer; + sequence_id = event->sequence_id; + tw_ioctl->driver_command.status = 0; + + if (tw_dev->event_queue_wrapped) { + if (tw_dev->aen_clobber) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; + tw_dev->aen_clobber = 0; + } + start_index = tw_dev->error_index; + } else { + if (!tw_dev->error_index) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + start_index = 0; + } + event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH; + + if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) { + if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) + tw_dev->aen_clobber = 1; + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); + tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; + break; + case TW_IOCTL_GET_PREVIOUS_EVENT: + event = (TW_Event *)tw_ioctl->data_buffer; + sequence_id = event->sequence_id; + tw_ioctl->driver_command.status = 0; + + if (tw_dev->event_queue_wrapped) { + if (tw_dev->aen_clobber) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; + tw_dev->aen_clobber = 0; + } + start_index = tw_dev->error_index; + } else { + if (!tw_dev->error_index) { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + start_index = 0; + } + event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH; + + if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) { + if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) + tw_dev->aen_clobber = 1; + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; + break; + } + memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); + tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; + break; + case TW_IOCTL_GET_LOCK: + tw_lock = (TW_Lock *)tw_ioctl->data_buffer; + do_gettimeofday(¤t_time); + current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); + + if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) { + tw_dev->ioctl_sem_lock = 1; + tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec; + tw_ioctl->driver_command.status = 0; + tw_lock->time_remaining_msec = tw_lock->timeout_msec; + } else { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED; + tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms; + } + break; + case TW_IOCTL_RELEASE_LOCK: + if (tw_dev->ioctl_sem_lock == 1) { + tw_dev->ioctl_sem_lock = 0; + tw_ioctl->driver_command.status = 0; + } else { + tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED; + } + break; + default: + retval = TW_IOCTL_ERROR_OS_ENOTTY; + goto out3; + } + + /* Now copy the entire response to userspace */ + if (copy_to_user((void *)arg, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) + retval = 0; +out3: + /* Now free ioctl buf memory */ + pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); +out2: + up(&tw_dev->ioctl_sem); +out: + return retval; +} /* End twa_chrdev_ioctl() */ + +/* This function handles open for the character device */ +static int twa_chrdev_open(struct inode *inode, struct file *file) +{ + unsigned int minor_number; + int retval = TW_IOCTL_ERROR_OS_ENODEV; + + minor_number = iminor(inode); + if (minor_number >= twa_device_extension_count) + goto out; + retval = 0; +out: + return retval; +} /* End twa_chrdev_open() */ + +/* This function will print readable messages from status register errors */ +static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) +{ + int retval = 1; + + /* Check for various error conditions and handle them appropriately */ + if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing"); + writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); + } + + if (status_reg_value & TW_STATUS_PCI_ABORT) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing"); + writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev)); + pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); + } + + if (status_reg_value & TW_STATUS_QUEUE_ERROR) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); + writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); + } + + if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing"); + writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); + } + + if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { + if (tw_dev->reset_print == 0) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing"); + tw_dev->reset_print = 1; + } + goto out; + } + retval = 0; +out: + return retval; +} /* End twa_decode_bits() */ + +/* This function will empty the response queue */ +static int twa_empty_response_queue(TW_Device_Extension *tw_dev) +{ + u32 status_reg_value, response_que_value; + int count = 0, retval = 1; + + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + + while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { + response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + count++; + } + if (count == TW_MAX_RESPONSE_DRAIN) + goto out; + + retval = 0; +out: + return retval; +} /* End twa_empty_response_queue() */ + +/* This function passes sense keys from firmware to scsi layer */ +static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host) +{ + TW_Command_Full *full_command_packet; + unsigned short error; + int retval = 1; + + full_command_packet = tw_dev->command_packet_virt[request_id]; + /* Don't print error for Logical unit not supported during rollcall */ + error = full_command_packet->header.status_block.error; + if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) { + if (print_host) + printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", + tw_dev->host->host_no, + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, + full_command_packet->header.status_block.error, + twa_string_lookup(twa_error_table, + full_command_packet->header.status_block.error), + full_command_packet->header.err_specific_desc); + else + printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, + full_command_packet->header.status_block.error, + twa_string_lookup(twa_error_table, + full_command_packet->header.status_block.error), + full_command_packet->header.err_specific_desc); + } + + if (copy_sense) { + memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH); + tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); + retval = TW_ISR_DONT_RESULT; + goto out; + } + retval = 0; +out: + return retval; +} /* End twa_fill_sense() */ + +/* This function will free up device extension resources */ +static void twa_free_device_extension(TW_Device_Extension *tw_dev) +{ + if (tw_dev->command_packet_virt[0]) + pci_free_consistent(tw_dev->tw_pci_dev, + sizeof(TW_Command_Full)*TW_Q_LENGTH, + tw_dev->command_packet_virt[0], + tw_dev->command_packet_phys[0]); + + if (tw_dev->generic_buffer_virt[0]) + pci_free_consistent(tw_dev->tw_pci_dev, + TW_SECTOR_SIZE*TW_Q_LENGTH, + tw_dev->generic_buffer_virt[0], + tw_dev->generic_buffer_phys[0]); + + if (tw_dev->event_queue[0]) + kfree(tw_dev->event_queue[0]); +} /* End twa_free_device_extension() */ + +/* This function will free a request id */ +static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id) +{ + tw_dev->free_queue[tw_dev->free_tail] = request_id; + tw_dev->state[request_id] = TW_S_FINISHED; + tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; +} /* End twa_free_request_id() */ + +/* This function will get parameter table entires from the firmware */ +static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) +{ + TW_Command_Full *full_command_packet; + TW_Command *command_packet; + TW_Param_Apache *param; + unsigned long param_value; + void *retval = NULL; + + /* Setup the command packet */ + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + command_packet = &full_command_packet->command.oldcommand; + + command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); + command_packet->size = TW_COMMAND_SIZE; + command_packet->request_id = request_id; + command_packet->byte6_offset.block_count = 1; + + /* Now setup the param */ + param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; + memset(param, 0, TW_SECTOR_SIZE); + param->table_id = table_id | 0x8000; + param->parameter_id = parameter_id; + param->parameter_size_bytes = parameter_size_bytes; + param_value = tw_dev->generic_buffer_phys[request_id]; + + command_packet->byte8_offset.param.sgl[0].address = param_value; + command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; + + /* Post the command packet to the board */ + twa_post_command_packet(tw_dev, request_id, 1); + + /* Poll for completion */ + if (twa_poll_response(tw_dev, request_id, 30)) + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param") + else + retval = (void *)&(param->data[0]); + + tw_dev->posted_request_count--; + tw_dev->state[request_id] = TW_S_INITIAL; + + return retval; +} /* End twa_get_param() */ + +/* This function will assign an available request id */ +static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id) +{ + *request_id = tw_dev->free_queue[tw_dev->free_head]; + tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; + tw_dev->state[*request_id] = TW_S_STARTED; +} /* End twa_get_request_id() */ + +/* This function will send an initconnection command to controller */ +static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, + u32 set_features, unsigned short current_fw_srl, + unsigned short current_fw_arch_id, + unsigned short current_fw_branch, + unsigned short current_fw_build, + unsigned short *fw_on_ctlr_srl, + unsigned short *fw_on_ctlr_arch_id, + unsigned short *fw_on_ctlr_branch, + unsigned short *fw_on_ctlr_build, + u32 *init_connect_result) +{ + TW_Command_Full *full_command_packet; + TW_Initconnect *tw_initconnect; + int request_id = 0, retval = 1; + + /* Initialize InitConnection command packet */ + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + full_command_packet->header.header_desc.size_header = 128; + + tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; + tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); + tw_initconnect->request_id = request_id; + tw_initconnect->message_credits = message_credits; + tw_initconnect->features = set_features; +#if BITS_PER_LONG > 32 + /* Turn on 64-bit sgl support */ + tw_initconnect->features |= 1; +#endif + + if (set_features & TW_EXTENDED_INIT_CONNECT) { + tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; + tw_initconnect->fw_srl = current_fw_srl; + tw_initconnect->fw_arch_id = current_fw_arch_id; + tw_initconnect->fw_branch = current_fw_branch; + tw_initconnect->fw_build = current_fw_build; + } else + tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; + + /* Send command packet to the board */ + twa_post_command_packet(tw_dev, request_id, 1); + + /* Poll for completion */ + if (twa_poll_response(tw_dev, request_id, 30)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection"); + } else { + if (set_features & TW_EXTENDED_INIT_CONNECT) { + *fw_on_ctlr_srl = tw_initconnect->fw_srl; + *fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id; + *fw_on_ctlr_branch = tw_initconnect->fw_branch; + *fw_on_ctlr_build = tw_initconnect->fw_build; + *init_connect_result = tw_initconnect->result; + } + retval = 0; + } + + tw_dev->posted_request_count--; + tw_dev->state[request_id] = TW_S_INITIAL; + + return retval; +} /* End twa_initconnection() */ + +/* This function will initialize the fields of a device extension */ +static int twa_initialize_device_extension(TW_Device_Extension *tw_dev) +{ + int i, retval = 1; + + /* Initialize command packet buffers */ + if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed"); + goto out; + } + + /* Initialize generic buffer */ + if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed"); + goto out; + } + + /* Allocate event info space */ + tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL); + if (!tw_dev->event_queue[0]) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); + goto out; + } + + memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH); + + for (i = 0; i < TW_Q_LENGTH; i++) { + tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); + tw_dev->free_queue[i] = i; + tw_dev->state[i] = TW_S_INITIAL; + } + + tw_dev->pending_head = TW_Q_START; + tw_dev->pending_tail = TW_Q_START; + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_Q_START; + tw_dev->error_sequence_id = 1; + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; + + init_MUTEX(&tw_dev->ioctl_sem); + init_waitqueue_head(&tw_dev->ioctl_wqueue); + + retval = 0; +out: + return retval; +} /* End twa_initialize_device_extension() */ + +/* This function is the interrupt service routine */ +static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + int request_id, error = 0; + u32 status_reg_value; + TW_Response_Queue response_que; + TW_Command_Full *full_command_packet; + TW_Command *command_packet; + TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; + int handled = 0; + + /* Get the per adapter lock */ + spin_lock(tw_dev->host->host_lock); + + /* See if the interrupt matches this instance */ + if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) { + + handled = 1; + + /* Read the registers */ + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + + /* Check if this is our interrupt, otherwise bail */ + if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) + goto twa_interrupt_bail; + + /* Check controller for errors */ + if (twa_check_bits(status_reg_value)) { + if (twa_decode_bits(tw_dev, status_reg_value)) { + TW_CLEAR_ALL_INTERRUPTS(tw_dev); + goto twa_interrupt_bail; + } + } + + /* Handle host interrupt */ + if (status_reg_value & TW_STATUS_HOST_INTERRUPT) + TW_CLEAR_HOST_INTERRUPT(tw_dev); + + /* Handle attention interrupt */ + if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { + TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); + if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { + twa_get_request_id(tw_dev, &request_id); + + error = twa_aen_read_queue(tw_dev, request_id); + if (error) { + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); + } + } + } + + /* Handle command interrupt */ + if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { + TW_MASK_COMMAND_INTERRUPT(tw_dev); + /* Drain as many pending commands as we can */ + while (tw_dev->pending_request_count > 0) { + request_id = tw_dev->pending_queue[tw_dev->pending_head]; + if (tw_dev->state[request_id] != TW_S_PENDING) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending"); + TW_CLEAR_ALL_INTERRUPTS(tw_dev); + goto twa_interrupt_bail; + } + if (twa_post_command_packet(tw_dev, request_id, 1)==0) { + tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH; + tw_dev->pending_request_count--; + } else { + /* If we get here, we will continue re-posting on the next command interrupt */ + break; + } + } + } + + /* Handle response interrupt */ + if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { + + /* Drain the response queue from the board */ + while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { + /* Complete the response */ + response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); + request_id = TW_RESID_OUT(response_que.response_id); + full_command_packet = tw_dev->command_packet_virt[request_id]; + error = 0; + command_packet = &full_command_packet->command.oldcommand; + /* Check for command packet errors */ + if (full_command_packet->command.newcommand.status != 0) { + if (tw_dev->srb[request_id] != 0) { + error = twa_fill_sense(tw_dev, request_id, 1, 1); + } else { + /* Skip ioctl error prints */ + if (request_id != tw_dev->chrdev_request_id) { + error = twa_fill_sense(tw_dev, request_id, 0, 1); + } + } + } + + /* Check for correct state */ + if (tw_dev->state[request_id] != TW_S_POSTED) { + if (tw_dev->srb[request_id] != 0) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted"); + TW_CLEAR_ALL_INTERRUPTS(tw_dev); + goto twa_interrupt_bail; + } + } + + /* Check for internal command completion */ + if (tw_dev->srb[request_id] == 0) { + if (request_id != tw_dev->chrdev_request_id) { + if (twa_aen_complete(tw_dev, request_id)) + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt"); + } else { + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; + wake_up(&tw_dev->ioctl_wqueue); + } + } else { + twa_scsiop_execute_scsi_complete(tw_dev, request_id); + /* If no error command was a success */ + if (error == 0) { + tw_dev->srb[request_id]->result = (DID_OK << 16); + } + + /* If error, command failed */ + if (error == 1) { + /* Ask for a host reset */ + tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + } + + /* Now complete the io */ + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + tw_dev->posted_request_count--; + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + twa_unmap_scsi_data(tw_dev, request_id); + } + + /* Check for valid status after each drain */ + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + if (twa_check_bits(status_reg_value)) { + if (twa_decode_bits(tw_dev, status_reg_value)) { + TW_CLEAR_ALL_INTERRUPTS(tw_dev); + goto twa_interrupt_bail; + } + } + } + } + } +twa_interrupt_bail: + spin_unlock(tw_dev->host->host_lock); + return IRQ_RETVAL(handled); +} /* End twa_interrupt() */ + +/* This function will load the request id and various sgls for ioctls */ +static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) +{ + TW_Command *oldcommand; + TW_Command_Apache *newcommand; + TW_SG_Entry *sgl; + + if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { + newcommand = &full_command_packet->command.newcommand; + newcommand->request_id = request_id; + newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; + newcommand->sg_list[0].length = length; + } else { + oldcommand = &full_command_packet->command.oldcommand; + oldcommand->request_id = request_id; + + if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { + /* Load the sg list */ + sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); + sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; + sgl->length = length; + } + } +} /* End twa_load_sgl() */ + +/* This function will perform a pci-dma mapping for a scatter gather list */ +static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) +{ + int use_sg; + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + struct pci_dev *pdev = tw_dev->tw_pci_dev; + int retval = 0; + + if (cmd->use_sg == 0) + goto out; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL); + + if (use_sg == 0) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); + goto out; + } + + cmd->SCp.phase = TW_PHASE_SGLIST; + cmd->SCp.have_data_in = use_sg; + retval = use_sg; +out: + return retval; +} /* End twa_map_scsi_sg_data() */ + +/* This function will perform a pci-dma map for a single buffer */ +static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id) +{ + dma_addr_t mapping; + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + struct pci_dev *pdev = tw_dev->tw_pci_dev; + int retval = 0; + + if (cmd->request_bufflen == 0) { + retval = 0; + goto out; + } + + mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL); + + if (mapping == 0) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page"); + goto out; + } + + cmd->SCp.phase = TW_PHASE_SINGLE; + cmd->SCp.have_data_in = mapping; + retval = mapping; +out: + return retval; +} /* End twa_map_scsi_single_data() */ + +/* This function will poll for a response interrupt of a request */ +static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) +{ + int retval = 1, found = 0, response_request_id; + TW_Response_Queue response_queue; + TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id]; + + if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) { + response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); + response_request_id = TW_RESID_OUT(response_queue.response_id); + if (request_id != response_request_id) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response"); + goto out; + } + if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { + if (full_command_packet->command.newcommand.status != 0) { + /* bad response */ + twa_fill_sense(tw_dev, request_id, 0, 0); + goto out; + } + found = 1; + } else { + if (full_command_packet->command.oldcommand.status != 0) { + /* bad response */ + twa_fill_sense(tw_dev, request_id, 0, 0); + goto out; + } + found = 1; + } + } + + if (found) + retval = 0; +out: + return retval; +} /* End twa_poll_response() */ + +/* This function will poll the status register for a flag */ +static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) +{ + u32 status_reg_value; + unsigned long before; + int retval = 1; + + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + before = jiffies; + + if (twa_check_bits(status_reg_value)) + twa_decode_bits(tw_dev, status_reg_value); + + while ((status_reg_value & flag) != flag) { + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + + if (twa_check_bits(status_reg_value)) + twa_decode_bits(tw_dev, status_reg_value); + + if (time_after(jiffies, before + HZ * seconds)) + goto out; + + msleep(50); + } + retval = 0; +out: + return retval; +} /* End twa_poll_status() */ + +/* This function will poll the status register for disappearance of a flag */ +static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds) +{ + u32 status_reg_value; + unsigned long before; + int retval = 1; + + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + before = jiffies; + + if (twa_check_bits(status_reg_value)) + twa_decode_bits(tw_dev, status_reg_value); + + while ((status_reg_value & flag) != 0) { + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + if (twa_check_bits(status_reg_value)) + twa_decode_bits(tw_dev, status_reg_value); + + if (time_after(jiffies, before + HZ * seconds)) + goto out; + + msleep(50); + } + retval = 0; +out: + return retval; +} /* End twa_poll_status_gone() */ + +/* This function will attempt to post a command packet to the board */ +static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal) +{ + u32 status_reg_value; + unsigned long command_que_value; + int retval = 1; + + command_que_value = tw_dev->command_packet_phys[request_id]; + status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); + + if (twa_check_bits(status_reg_value)) + twa_decode_bits(tw_dev, status_reg_value); + + if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) { + + /* Only pend internal driver commands */ + if (!internal) { + retval = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + /* Couldn't post the command packet, so we do it later */ + if (tw_dev->state[request_id] != TW_S_PENDING) { + tw_dev->state[request_id] = TW_S_PENDING; + tw_dev->pending_request_count++; + if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { + tw_dev->max_pending_request_count = tw_dev->pending_request_count; + } + tw_dev->pending_queue[tw_dev->pending_tail] = request_id; + tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH; + } + TW_UNMASK_COMMAND_INTERRUPT(tw_dev); + goto out; + } else { + /* We successfully posted the command packet */ +#if BITS_PER_LONG > 32 + writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); +#else + writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); +#endif + tw_dev->state[request_id] = TW_S_POSTED; + tw_dev->posted_request_count++; + if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { + tw_dev->max_posted_request_count = tw_dev->posted_request_count; + } + } + retval = 0; +out: + return retval; +} /* End twa_post_command_packet() */ + +/* This function will reset a device extension */ +static int twa_reset_device_extension(TW_Device_Extension *tw_dev) +{ + int i = 0; + int retval = 1; + + /* Abort all requests that are in progress */ + for (i = 0; i < TW_Q_LENGTH; i++) { + if ((tw_dev->state[i] != TW_S_FINISHED) && + (tw_dev->state[i] != TW_S_INITIAL) && + (tw_dev->state[i] != TW_S_COMPLETED)) { + if (tw_dev->srb[i]) { + tw_dev->srb[i]->result = (DID_RESET << 16); + tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); + twa_unmap_scsi_data(tw_dev, i); + } + } + } + + /* Reset queues and counts */ + for (i = 0; i < TW_Q_LENGTH; i++) { + tw_dev->free_queue[i] = i; + tw_dev->state[i] = TW_S_INITIAL; + } + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_Q_START; + tw_dev->posted_request_count = 0; + tw_dev->pending_request_count = 0; + tw_dev->pending_head = TW_Q_START; + tw_dev->pending_tail = TW_Q_START; + tw_dev->reset_print = 0; + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; + tw_dev->flags = 0; + + TW_DISABLE_INTERRUPTS(tw_dev); + + if (twa_reset_sequence(tw_dev, 1)) + goto out; + + TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); + + retval = 0; +out: + return retval; +} /* End twa_reset_device_extension() */ + +/* This function will reset a controller */ +static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) +{ + int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset; + + while (tries < TW_MAX_RESET_TRIES) { + if (do_soft_reset) + TW_SOFT_RESET(tw_dev); + + /* Make sure controller is in a good state */ + if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence"); + do_soft_reset = 1; + tries++; + continue; + } + + /* Empty response queue */ + if (twa_empty_response_queue(tw_dev)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence"); + do_soft_reset = 1; + tries++; + continue; + } + + flashed = 0; + + /* Check for compatibility/flash */ + if (twa_check_srl(tw_dev, &flashed)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence"); + do_soft_reset = 1; + tries++; + continue; + } else { + if (flashed) { + tries++; + continue; + } + } + + /* Drain the AEN queue */ + if (twa_aen_drain_queue(tw_dev, soft_reset)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence"); + do_soft_reset = 1; + tries++; + continue; + } + + /* If we got here, controller is in a good state */ + retval = 0; + goto out; + } +out: + return retval; +} /* End twa_reset_sequence() */ + +/* This funciton returns unit geometry in cylinders/heads/sectors */ +static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +{ + int heads, sectors, cylinders; + TW_Device_Extension *tw_dev; + + tw_dev = (TW_Device_Extension *)sdev->host->hostdata; + + if (capacity >= 0x200000) { + heads = 255; + sectors = 63; + cylinders = sector_div(capacity, heads * sectors); + } else { + heads = 64; + sectors = 32; + cylinders = sector_div(capacity, heads * sectors); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} /* End twa_scsi_biosparam() */ + +/* This is the new scsi eh abort function */ +static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt) +{ + int i; + TW_Device_Extension *tw_dev = NULL; + int retval = FAILED; + + tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + + spin_unlock_irq(tw_dev->host->host_lock); + + tw_dev->num_aborts++; + + /* If we find any IO's in process, we have to reset the card */ + for (i = 0; i < TW_Q_LENGTH; i++) { + if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) { + printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", + tw_dev->host->host_no, TW_DRIVER, 0x2c, + SCpnt->device->id, SCpnt->cmnd[0]); + if (twa_reset_device_extension(tw_dev)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort"); + goto out; + } + break; + } + } + retval = SUCCESS; +out: + spin_lock_irq(tw_dev->host->host_lock); + return retval; +} /* End twa_scsi_eh_abort() */ + +/* This is the new scsi eh reset function */ +static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) +{ + TW_Device_Extension *tw_dev = NULL; + int retval = FAILED; + + tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + + spin_unlock_irq(tw_dev->host->host_lock); + + tw_dev->num_resets++; + + printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no); + + /* Now reset the card and some of the device extension data */ + if (twa_reset_device_extension(tw_dev)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); + goto out; + } + printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no); + retval = SUCCESS; +out: + spin_lock_irq(tw_dev->host->host_lock); + return retval; +} /* End twa_scsi_eh_reset() */ + +/* This is the main scsi queue function to handle scsi opcodes */ +static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +{ + int request_id, retval; + TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + + /* Save done function into scsi_cmnd struct */ + SCpnt->scsi_done = done; + + /* Get a free request id */ + twa_get_request_id(tw_dev, &request_id); + + /* Save the scsi command for use by the ISR */ + tw_dev->srb[request_id] = SCpnt; + + /* Initialize phase to zero */ + SCpnt->SCp.phase = TW_PHASE_INITIAL; + + retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); + switch (retval) { + case SCSI_MLQUEUE_HOST_BUSY: + twa_free_request_id(tw_dev, request_id); + break; + case 1: + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + SCpnt->result = (DID_ERROR << 16); + done(SCpnt); + } + + return retval; +} /* End twa_scsi_queue() */ + +/* This function hands scsi cdb's to the firmware */ +static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg) +{ + TW_Command_Full *full_command_packet; + TW_Command_Apache *command_packet; + u32 num_sectors = 0x0; + int i, sg_count; + struct scsi_cmnd *srb = NULL; + struct scatterlist *sglist = NULL; + u32 buffaddr = 0x0; + int retval = 1; + + if (tw_dev->srb[request_id]) { + if (tw_dev->srb[request_id]->request_buffer) { + sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; + } + srb = tw_dev->srb[request_id]; + } + + /* Initialize command packet */ + full_command_packet = tw_dev->command_packet_virt[request_id]; + full_command_packet->header.header_desc.size_header = 128; + full_command_packet->header.status_block.error = 0; + full_command_packet->header.status_block.severity__reserved = 0; + + command_packet = &full_command_packet->command.newcommand; + command_packet->status = 0; + command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); + + /* We forced 16 byte cdb use earlier */ + if (!cdb) + memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); + else + memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); + + if (srb) + command_packet->unit = srb->device->id; + else + command_packet->unit = 0; + + command_packet->request_id = request_id; + command_packet->sgl_offset = 16; + + if (!sglistarg) { + /* Map sglist from scsi layer to cmd packet */ + if (tw_dev->srb[request_id]->use_sg == 0) { + if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { + command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; + command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; + } else { + buffaddr = twa_map_scsi_single_data(tw_dev, request_id); + if (buffaddr == 0) + goto out; + + command_packet->sg_list[0].address = buffaddr; + command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen; + } + command_packet->sgl_entries = 1; + + if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi"); + goto out; + } + } + + if (tw_dev->srb[request_id]->use_sg > 0) { + sg_count = twa_map_scsi_sg_data(tw_dev, request_id); + if (sg_count == 0) + goto out; + + for (i = 0; i < sg_count; i++) { + command_packet->sg_list[i].address = sg_dma_address(&sglist[i]); + command_packet->sg_list[i].length = sg_dma_len(&sglist[i]); + if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi"); + goto out; + } + } + command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg; + } + } else { + /* Internal cdb post */ + for (i = 0; i < use_sg; i++) { + command_packet->sg_list[i].address = sglistarg[i].address; + command_packet->sg_list[i].length = sglistarg[i].length; + if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); + goto out; + } + } + command_packet->sgl_entries = use_sg; + } + + if (srb) { + if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) + num_sectors = (u32)srb->cmnd[4]; + + if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) + num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); + } + + /* Update sector statistic */ + tw_dev->sector_count = num_sectors; + if (tw_dev->sector_count > tw_dev->max_sector_count) + tw_dev->max_sector_count = tw_dev->sector_count; + + /* Update SG statistics */ + if (srb) { + tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg; + if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) + tw_dev->max_sgl_entries = tw_dev->sgl_entries; + } + + /* Now post the command to the board */ + if (srb) { + retval = twa_post_command_packet(tw_dev, request_id, 0); + } else { + twa_post_command_packet(tw_dev, request_id, 1); + retval = 0; + } +out: + return retval; +} /* End twa_scsiop_execute_scsi() */ + +/* This function completes an execute scsi operation */ +static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) +{ + /* Copy the response if too small */ + if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { + memcpy(tw_dev->srb[request_id]->request_buffer, + tw_dev->generic_buffer_virt[request_id], + tw_dev->srb[request_id]->request_bufflen); + } +} /* End twa_scsiop_execute_scsi_complete() */ + +/* This function tells the controller to shut down */ +static void __twa_shutdown(TW_Device_Extension *tw_dev) +{ + /* Disable interrupts */ + TW_DISABLE_INTERRUPTS(tw_dev); + + printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no); + + /* Tell the card we are shutting down */ + if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed"); + } else { + printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n"); + } + + /* Clear all interrupts just before exit */ + TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); +} /* End __twa_shutdown() */ + +/* Wrapper for __twa_shutdown */ +static void twa_shutdown(struct device *dev) +{ + struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; + + __twa_shutdown(tw_dev); +} /* End twa_shutdown() */ + +/* This function will look up a string */ +static char *twa_string_lookup(twa_message_type *table, unsigned int code) +{ + int index; + + for (index = 0; ((code != table[index].code) && + (table[index].text != (char *)0)); index++); + return(table[index].text); +} /* End twa_string_lookup() */ + +/* This function will perform a pci-dma unmap */ +static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) +{ + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + struct pci_dev *pdev = tw_dev->tw_pci_dev; + + switch(cmd->SCp.phase) { + case TW_PHASE_SINGLE: + pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL); + break; + case TW_PHASE_SGLIST: + pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL); + break; + } +} /* End twa_unmap_scsi_data() */ + +/* scsi_host_template initializer */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = "3ware 9000 Storage Controller", + .queuecommand = twa_scsi_queue, + .eh_abort_handler = twa_scsi_eh_abort, + .eh_host_reset_handler = twa_scsi_eh_reset, + .bios_param = twa_scsi_biosparam, + .can_queue = TW_Q_LENGTH-2, + .this_id = -1, + .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH, + .max_sectors = TW_MAX_SECTORS, + .cmd_per_lun = TW_MAX_CMDS_PER_LUN, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = twa_host_attrs, + .sdev_attrs = twa_dev_attrs, + .emulated = 1 +}; + +/* This function will probe and initialize a card */ +static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) +{ + struct Scsi_Host *host = NULL; + TW_Device_Extension *tw_dev; + u32 mem_addr; + int retval = -ENODEV; + + retval = pci_enable_device(pdev); + if (retval) { + TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device"); + goto out_disable_device; + } + + pci_set_master(pdev); + + retval = pci_set_dma_mask(pdev, TW_DMA_MASK); + if (retval) { + TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); + goto out_disable_device; + } + + host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); + if (!host) { + TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension"); + retval = -ENOMEM; + goto out_disable_device; + } + tw_dev = (TW_Device_Extension *)host->hostdata; + + memset(tw_dev, 0, sizeof(TW_Device_Extension)); + + /* Save values to device extension */ + tw_dev->host = host; + tw_dev->tw_pci_dev = pdev; + + if (twa_initialize_device_extension(tw_dev)) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); + goto out_free_device_extension; + } + + /* Request IO regions */ + retval = pci_request_regions(pdev, "3w-9xxx"); + if (retval) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region"); + goto out_free_device_extension; + } + + mem_addr = pci_resource_start(pdev, 1); + + /* Save base address */ + tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE); + if (!tw_dev->base_addr) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); + goto out_release_mem_region; + } + + /* Disable interrupts on the card */ + TW_DISABLE_INTERRUPTS(tw_dev); + + /* Initialize the card */ + if (twa_reset_sequence(tw_dev, 0)) + goto out_release_mem_region; + + /* Set host specific parameters */ + host->max_id = TW_MAX_UNITS; + host->max_cmd_len = TW_MAX_CDB_LEN; + + /* Luns and channels aren't supported by adapter */ + host->max_lun = 0; + host->max_channel = 0; + + /* Register the card with the kernel SCSI layer */ + retval = scsi_add_host(host, &pdev->dev); + if (retval) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed"); + goto out_release_mem_region; + } + + pci_set_drvdata(pdev, host); + + printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n", + host->host_no, mem_addr, pdev->irq); + printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", + host->host_no, + (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE, + TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), + (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, + TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), + *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, + TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)); + + /* Now setup the interrupt handler */ + retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev); + if (retval) { + TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ"); + goto out_remove_host; + } + + twa_device_extension_list[twa_device_extension_count] = tw_dev; + twa_device_extension_count++; + + /* Re-enable interrupts on the card */ + TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); + + /* Finally, scan the host */ + scsi_scan_host(host); + + if (twa_major == -1) { + if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0) + TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device"); + } + return 0; + +out_remove_host: + scsi_remove_host(host); +out_release_mem_region: + pci_release_regions(pdev); +out_free_device_extension: + twa_free_device_extension(tw_dev); + scsi_host_put(host); +out_disable_device: + pci_disable_device(pdev); + + return retval; +} /* End twa_probe() */ + +/* This function is called to remove a device */ +static void twa_remove(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; + + scsi_remove_host(tw_dev->host); + + __twa_shutdown(tw_dev); + + /* Free up the IRQ */ + free_irq(tw_dev->tw_pci_dev->irq, tw_dev); + + /* Free up the mem region */ + pci_release_regions(pdev); + + /* Free up device extension resources */ + twa_free_device_extension(tw_dev); + + /* Unregister character device */ + if (twa_major >= 0) { + unregister_chrdev(twa_major, "twa"); + twa_major = -1; + } + + scsi_host_put(tw_dev->host); + pci_disable_device(pdev); + twa_device_extension_count--; +} /* End twa_remove() */ + +/* PCI Devices supported by this driver */ +static struct pci_device_id twa_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, twa_pci_tbl); + +/* pci_driver initializer */ +static struct pci_driver twa_driver = { + .name = "3w-9xxx", + .id_table = twa_pci_tbl, + .probe = twa_probe, + .remove = twa_remove, + .driver = { + .shutdown = twa_shutdown + } +}; + +/* This function is called on driver initialization */ +static int __init twa_init(void) +{ + printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version); + + return pci_module_init(&twa_driver); +} /* End twa_init() */ + +/* This function is called on driver exit */ +static void __exit twa_exit(void) +{ + pci_unregister_driver(&twa_driver); +} /* End twa_exit() */ + +module_init(twa_init); +module_exit(twa_exit); + diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h new file mode 100644 index 000000000..3c91ce6ed --- /dev/null +++ b/drivers/scsi/3w-9xxx.h @@ -0,0 +1,704 @@ +/* + 3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux. + + Written By: Adam Radford + + Copyright (C) 2004 Applied Micro Circuits Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Bugs/Comments/Suggestions should be mailed to: + linuxraid@amcc.com + + For more information, goto: + http://www.amcc.com +*/ + +#ifndef _3W_9XXX_H +#define _3W_9XXX_H + +/* AEN string type */ +typedef struct TAG_twa_message_type { + unsigned int code; + char* text; +} twa_message_type; + +/* AEN strings */ +static twa_message_type twa_aen_table[] = { + {0x0000, "AEN queue empty"}, + {0x0001, "Controller reset occurred"}, + {0x0002, "Degraded unit detected"}, + {0x0003, "Controller error occured"}, + {0x0004, "Background rebuild failed"}, + {0x0005, "Background rebuild done"}, + {0x0006, "Incomplete unit detected"}, + {0x0007, "Background initialize done"}, + {0x0008, "Unclean shutdown detected"}, + {0x0009, "Drive timeout detected"}, + {0x000A, "Drive error detected"}, + {0x000B, "Rebuild started"}, + {0x000C, "Background initialize started"}, + {0x000D, "Entire logical unit was deleted"}, + {0x000E, "Background initialize failed"}, + {0x000F, "SMART attribute exceeded threshold"}, + {0x0010, "Power supply reported AC under range"}, + {0x0011, "Power supply reported DC out of range"}, + {0x0012, "Power supply reported a malfunction"}, + {0x0013, "Power supply predicted malfunction"}, + {0x0014, "Battery charge is below threshold"}, + {0x0015, "Fan speed is below threshold"}, + {0x0016, "Temperature sensor is above threshold"}, + {0x0017, "Power supply was removed"}, + {0x0018, "Power supply was inserted"}, + {0x0019, "Drive was removed from a bay"}, + {0x001A, "Drive was inserted into a bay"}, + {0x001B, "Drive bay cover door was opened"}, + {0x001C, "Drive bay cover door was closed"}, + {0x001D, "Product case was opened"}, + {0x0020, "Prepare for shutdown (power-off)"}, + {0x0021, "Downgrade UDMA mode to lower speed"}, + {0x0022, "Upgrade UDMA mode to higher speed"}, + {0x0023, "Sector repair completed"}, + {0x0024, "Sbuf memory test failed"}, + {0x0025, "Error flushing cached write data to array"}, + {0x0026, "Drive reported data ECC error"}, + {0x0027, "DCB has checksum error"}, + {0x0028, "DCB version is unsupported"}, + {0x0029, "Background verify started"}, + {0x002A, "Background verify failed"}, + {0x002B, "Background verify done"}, + {0x002C, "Bad sector overwritten during rebuild"}, + {0x002D, "Background rebuild error on source drive"}, + {0x002E, "Replace failed because replacement drive too small"}, + {0x002F, "Verify failed because array was never initialized"}, + {0x0030, "Unsupported ATA drive"}, + {0x0031, "Synchronize host/controller time"}, + {0x0032, "Spare capacity is inadequate for some units"}, + {0x0033, "Background migration started"}, + {0x0034, "Background migration failed"}, + {0x0035, "Background migration done"}, + {0x0036, "Verify detected and fixed data/parity mismatch"}, + {0x0037, "SO-DIMM incompatible"}, + {0x0038, "SO-DIMM not detected"}, + {0x0039, "Corrected Sbuf ECC error"}, + {0x003A, "Drive power on reset detected"}, + {0x003B, "Background rebuild paused"}, + {0x003C, "Background initialize paused"}, + {0x003D, "Background verify paused"}, + {0x003E, "Background migration paused"}, + {0x003F, "Corrupt flash file system detected"}, + {0x0040, "Flash file system repaired"}, + {0x0041, "Unit number assignments were lost"}, + {0x0042, "Error during read of primary DCB"}, + {0x0043, "Latent error found in backup DCB"}, + {0x00FC, "Recovered/finished array membership update"}, + {0x00FD, "Handler lockup"}, + {0x00FE, "Retrying PCI transfer"}, + {0x00FF, "AEN queue is full"}, + {0xFFFFFFFF, (char*) 0} +}; + +/* AEN severity table */ +static char *twa_aen_severity_table[] = +{ + "None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0 +}; + +/* Error strings */ +static twa_message_type twa_error_table[] = { + {0x0100, "SGL entry contains zero data"}, + {0x0101, "Invalid command opcode"}, + {0x0102, "SGL entry has unaligned address"}, + {0x0103, "SGL size does not match command"}, + {0x0104, "SGL entry has illegal length"}, + {0x0105, "Command packet is not aligned"}, + {0x0106, "Invalid request ID"}, + {0x0107, "Duplicate request ID"}, + {0x0108, "ID not locked"}, + {0x0109, "LBA out of range"}, + {0x010A, "Logical unit not supported"}, + {0x010B, "Parameter table does not exist"}, + {0x010C, "Parameter index does not exist"}, + {0x010D, "Invalid field in CDB"}, + {0x010E, "Specified port has invalid drive"}, + {0x010F, "Parameter item size mismatch"}, + {0x0110, "Failed memory allocation"}, + {0x0111, "Memory request too large"}, + {0x0112, "Out of memory segments"}, + {0x0113, "Invalid address to deallocate"}, + {0x0114, "Out of memory"}, + {0x0115, "Out of heap"}, + {0x0120, "Double degrade"}, + {0x0121, "Drive not degraded"}, + {0x0122, "Reconstruct error"}, + {0x0123, "Replace not accepted"}, + {0x0124, "Replace drive capacity too small"}, + {0x0125, "Sector count not allowed"}, + {0x0126, "No spares left"}, + {0x0127, "Reconstruct error"}, + {0x0128, "Unit is offline"}, + {0x0129, "Cannot update status to DCB"}, + {0x0130, "Invalid stripe handle"}, + {0x0131, "Handle that was not locked"}, + {0x0132, "Handle that was not empty"}, + {0x0133, "Handle has different owner"}, + {0x0140, "IPR has parent"}, + {0x0150, "Illegal Pbuf address alignment"}, + {0x0151, "Illegal Pbuf transfer length"}, + {0x0152, "Illegal Sbuf address alignment"}, + {0x0153, "Illegal Sbuf transfer length"}, + {0x0160, "Command packet too large"}, + {0x0161, "SGL exceeds maximum length"}, + {0x0162, "SGL has too many entries"}, + {0x0170, "Insufficient resources for rebuilder"}, + {0x0171, "Verify error (data != parity)"}, + {0x0180, "Requested segment not in directory of this DCB"}, + {0x0181, "DCB segment has unsupported version"}, + {0x0182, "DCB segment has checksum error"}, + {0x0183, "DCB support (settings) segment invalid"}, + {0x0184, "DCB UDB (unit descriptor block) segment invalid"}, + {0x0185, "DCB GUID (globally unique identifier) segment invalid"}, + {0x01A0, "Could not clear Sbuf"}, + {0x01C0, "Flash identify failed"}, + {0x01C1, "Flash out of bounds"}, + {0x01C2, "Flash verify error"}, + {0x01C3, "Flash file object not found"}, + {0x01C4, "Flash file already present"}, + {0x01C5, "Flash file system full"}, + {0x01C6, "Flash file not present"}, + {0x01C7, "Flash file size error"}, + {0x01C8, "Bad flash file checksum"}, + {0x01CA, "Corrupt flash file system detected"}, + {0x01D0, "Invalid field in parameter list"}, + {0x01D1, "Parameter list length error"}, + {0x01D2, "Parameter item is not changeable"}, + {0x01D3, "Parameter item is not saveable"}, + {0x0200, "UDMA CRC error"}, + {0x0201, "Internal CRC error"}, + {0x0202, "Data ECC error"}, + {0x0203, "ADP level 1 error"}, + {0x0204, "Port timeout"}, + {0x0205, "Drive power on reset"}, + {0x0206, "ADP level 2 error"}, + {0x0207, "Soft reset failed"}, + {0x0208, "Drive not ready"}, + {0x0209, "Unclassified port error"}, + {0x020A, "Drive aborted command"}, + {0x0210, "Internal CRC error"}, + {0x0211, "PCI abort error"}, + {0x0212, "PCI parity error"}, + {0x0213, "Port handler error"}, + {0x0214, "Token interrupt count error"}, + {0x0215, "Timeout waiting for PCI transfer"}, + {0x0216, "Corrected buffer ECC"}, + {0x0217, "Uncorrected buffer ECC"}, + {0x0230, "Unsupported command during flash recovery"}, + {0x0231, "Next image buffer expected"}, + {0x0232, "Binary image architecture incompatible"}, + {0x0233, "Binary image has no signature"}, + {0x0234, "Binary image has bad checksum"}, + {0x0235, "Image downloaded overflowed buffer"}, + {0x0240, "I2C device not found"}, + {0x0241, "I2C transaction aborted"}, + {0x0242, "SO-DIMM parameter(s) incompatible using defaults"}, + {0x0243, "SO-DIMM unsupported"}, + {0x0248, "SPI transfer status error"}, + {0x0249, "SPI transfer timeout error"}, + {0x0250, "Invalid unit descriptor size in CreateUnit"}, + {0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"}, + {0x0252, "Invalid value in CreateUnit descriptor"}, + {0x0253, "Inadequate disk space to support descriptor in CreateUnit"}, + {0x0254, "Unable to create data channel for this unit descriptor"}, + {0x0255, "CreateUnit descriptor specifies a drive already in use"}, + {0x0256, "Unable to write configuration to all disks during CreateUnit"}, + {0x0257, "CreateUnit does not support this descriptor version"}, + {0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"}, + {0x0259, "Too many descriptors in CreateUnit"}, + {0x025A, "Invalid configuration specified in CreateUnit descriptor"}, + {0x025B, "Invalid LBA offset specified in CreateUnit descriptor"}, + {0x025C, "Invalid stripelet size specified in CreateUnit descriptor"}, + {0x0260, "SMART attribute exceeded threshold"}, + {0xFFFFFFFF, (char*) 0} +}; + +/* Control register bit definitions */ +#define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 +#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 +#define TW_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000 +#define TW_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000 +#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000 +#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000 +#define TW_CONTROL_CLEAR_ERROR_STATUS 0x00000200 +#define TW_CONTROL_ISSUE_SOFT_RESET 0x00000100 +#define TW_CONTROL_ENABLE_INTERRUPTS 0x00000080 +#define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 +#define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 +#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 +#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000 +#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 +#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008 + +/* Status register bit definitions */ +#define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 +#define TW_STATUS_MINOR_VERSION_MASK 0x0F000000 +#define TW_STATUS_PCI_PARITY_ERROR 0x00800000 +#define TW_STATUS_QUEUE_ERROR 0x00400000 +#define TW_STATUS_MICROCONTROLLER_ERROR 0x00200000 +#define TW_STATUS_PCI_ABORT 0x00100000 +#define TW_STATUS_HOST_INTERRUPT 0x00080000 +#define TW_STATUS_ATTENTION_INTERRUPT 0x00040000 +#define TW_STATUS_COMMAND_INTERRUPT 0x00020000 +#define TW_STATUS_RESPONSE_INTERRUPT 0x00010000 +#define TW_STATUS_COMMAND_QUEUE_FULL 0x00008000 +#define TW_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000 +#define TW_STATUS_MICROCONTROLLER_READY 0x00002000 +#define TW_STATUS_COMMAND_QUEUE_EMPTY 0x00001000 +#define TW_STATUS_EXPECTED_BITS 0x00002000 +#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 +#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 +#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 + +/* RESPONSE QUEUE BIT DEFINITIONS */ +#define TW_RESPONSE_ID_MASK 0x00000FF0 + +/* PCI related defines */ +#define TW_DEVICE_NAME "3w-9xxx" +#define TW_NUMDEVICES 1 +#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 +#define TW_PCI_CLEAR_PCI_ABORT 0x2000 + +/* Command packet opcodes used by the driver */ +#define TW_OP_INIT_CONNECTION 0x1 +#define TW_OP_GET_PARAM 0x12 +#define TW_OP_SET_PARAM 0x13 +#define TW_OP_EXECUTE_SCSI 0x10 +#define TW_OP_DOWNLOAD_FIRMWARE 0x16 +#define TW_OP_RESET 0x1C + +/* Asynchronous Event Notification (AEN) codes used by the driver */ +#define TW_AEN_QUEUE_EMPTY 0x0000 +#define TW_AEN_SOFT_RESET 0x0001 +#define TW_AEN_SYNC_TIME_WITH_HOST 0x031 +#define TW_AEN_SEVERITY_ERROR 0x1 +#define TW_AEN_SEVERITY_DEBUG 0x4 +#define TW_AEN_NOT_RETRIEVED 0x1 +#define TW_AEN_RETRIEVED 0x2 + +/* Command state defines */ +#define TW_S_INITIAL 0x1 /* Initial state */ +#define TW_S_STARTED 0x2 /* Id in use */ +#define TW_S_POSTED 0x4 /* Posted to the controller */ +#define TW_S_PENDING 0x8 /* Waiting to be posted in isr */ +#define TW_S_COMPLETED 0x10 /* Completed by isr */ +#define TW_S_FINISHED 0x20 /* I/O completely done */ + +/* Compatibility defines */ +#define TW_9000_ARCH_ID 0x5 +#define TW_CURRENT_FW_SRL 24 +#define TW_CURRENT_FW_BUILD 5 +#define TW_CURRENT_FW_BRANCH 1 + +/* Phase defines */ +#define TW_PHASE_INITIAL 0 +#define TW_PHASE_SINGLE 1 +#define TW_PHASE_SGLIST 2 + +/* Misc defines */ +#define TW_SECTOR_SIZE 512 +#define TW_ALIGNMENT_9000 4 /* 4 bytes */ +#define TW_ALIGNMENT_9000_SGL 0x3 +#define TW_MAX_UNITS 16 +#define TW_INIT_MESSAGE_CREDITS 0x100 +#define TW_INIT_COMMAND_PACKET_SIZE 0x3 +#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 +#define TW_EXTENDED_INIT_CONNECT 0x2 +#define TW_BUNDLED_FW_SAFE_TO_FLASH 0x4 +#define TW_CTLR_FW_RECOMMENDS_FLASH 0x8 +#define TW_CTLR_FW_COMPATIBLE 0x2 +#define TW_BASE_FW_SRL 0x17 +#define TW_BASE_FW_BRANCH 0 +#define TW_BASE_FW_BUILD 1 +#if BITS_PER_LONG > 32 +#define TW_APACHE_MAX_SGL_LENGTH 72 +#define TW_ESCALADE_MAX_SGL_LENGTH 41 +#define TW_APACHE_CMD_PKT_SIZE 5 +#else +#define TW_APACHE_MAX_SGL_LENGTH 109 +#define TW_ESCALADE_MAX_SGL_LENGTH 62 +#define TW_APACHE_CMD_PKT_SIZE 4 +#endif +#define TW_ATA_PASS_SGL_MAX 60 +#define TW_Q_LENGTH 256 +#define TW_Q_START 0 +#define TW_MAX_SLOT 32 +#define TW_MAX_RESET_TRIES 2 +#define TW_MAX_CMDS_PER_LUN 254 +#define TW_MAX_RESPONSE_DRAIN 256 +#define TW_MAX_AEN_DRAIN 40 +#define TW_IN_IOCTL 2 +#define TW_IN_CHRDEV_IOCTL 3 +#define TW_IN_ATTENTION_LOOP 4 +#define TW_MAX_SECTORS 256 +#define TW_AEN_WAIT_TIME 1000 +#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ +#define TW_MAX_CDB_LEN 16 +#define TW_ISR_DONT_COMPLETE 2 +#define TW_ISR_DONT_RESULT 3 +#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ +#define TW_IOCTL_CHRDEV_FREE -1 +#define TW_COMMAND_OFFSET 128 /* 128 bytes */ +#define TW_VERSION_TABLE 0x0402 +#define TW_TIMEKEEP_TABLE 0x040A +#define TW_INFORMATION_TABLE 0x0403 +#define TW_PARAM_FWVER 3 +#define TW_PARAM_FWVER_LENGTH 16 +#define TW_PARAM_BIOSVER 4 +#define TW_PARAM_BIOSVER_LENGTH 16 +#define TW_PARAM_PORTCOUNT 3 +#define TW_PARAM_PORTCOUNT_LENGTH 1 +#define TW_MIN_SGL_LENGTH 0x200 /* 512 bytes */ +#define TW_MAX_SENSE_LENGTH 256 +#define TW_EVENT_SOURCE_AEN 0x1000 +#define TW_EVENT_SOURCE_COMMAND 0x1001 +#define TW_EVENT_SOURCE_PCHIP 0x1002 +#define TW_EVENT_SOURCE_DRIVER 0x1003 +#define TW_IOCTL_GET_COMPATIBILITY_INFO 0x101 +#define TW_IOCTL_GET_LAST_EVENT 0x102 +#define TW_IOCTL_GET_FIRST_EVENT 0x103 +#define TW_IOCTL_GET_NEXT_EVENT 0x104 +#define TW_IOCTL_GET_PREVIOUS_EVENT 0x105 +#define TW_IOCTL_GET_LOCK 0x106 +#define TW_IOCTL_RELEASE_LOCK 0x107 +#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 +#define TW_IOCTL_ERROR_STATUS_NOT_LOCKED 0x1001 // Not locked +#define TW_IOCTL_ERROR_STATUS_LOCKED 0x1002 // Already locked +#define TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS 0x1003 // No more events +#define TW_IOCTL_ERROR_STATUS_AEN_CLOBBER 0x1004 // AEN clobber occurred +#define TW_IOCTL_ERROR_OS_EFAULT -EFAULT // Bad address +#define TW_IOCTL_ERROR_OS_EINTR -EINTR // Interrupted system call +#define TW_IOCTL_ERROR_OS_EINVAL -EINVAL // Invalid argument +#define TW_IOCTL_ERROR_OS_ENOMEM -ENOMEM // Out of memory +#define TW_IOCTL_ERROR_OS_ERESTARTSYS -ERESTARTSYS // Restart system call +#define TW_IOCTL_ERROR_OS_EIO -EIO // I/O error +#define TW_IOCTL_ERROR_OS_ENOTTY -ENOTTY // Not a typewriter +#define TW_IOCTL_ERROR_OS_ENODEV -ENODEV // No such device +#define TW_ALLOCATION_LENGTH 128 +#define TW_SENSE_DATA_LENGTH 18 +#define TW_STATUS_CHECK_CONDITION 2 +#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a +#define TW_ERROR_UNIT_OFFLINE 0x128 +#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3 +#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4 +#define TW_MESSAGE_SOURCE_LINUX_DRIVER 6 +#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER +#define TW_MESSAGE_SOURCE_LINUX_OS 9 +#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS +#if BITS_PER_LONG > 32 +#define TW_COMMAND_SIZE 5 +#define TW_DMA_MASK DMA_64BIT_MASK +#else +#define TW_COMMAND_SIZE 4 +#define TW_DMA_MASK DMA_32BIT_MASK +#endif +#ifndef PCI_DEVICE_ID_3WARE_9000 +#define PCI_DEVICE_ID_3WARE_9000 0x1002 +#endif + +/* Bitmask macros to eliminate bitfields */ + +/* opcode: 5, reserved: 3 */ +#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f)) +#define TW_OP_OUT(x) (x & 0x1f) + +/* opcode: 5, sgloffset: 3 */ +#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) +#define TW_SGL_OUT(x) ((x >> 5) & 0x7) + +/* severity: 3, reserved: 5 */ +#define TW_SEV_OUT(x) (x & 0x7) + +/* reserved_1: 4, response_id: 8, reserved_2: 20 */ +#define TW_RESID_OUT(x) ((x >> 4) & 0xff) + +/* Macros */ +#define TW_CONTROL_REG_ADDR(x) (x->base_addr) +#define TW_STATUS_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x4) +#if BITS_PER_LONG > 32 +#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x20) +#else +#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x8) +#endif +#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0xC) +#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x))) +#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x))) +#define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x))) +#define TW_DISABLE_INTERRUPTS(x) (writel(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) +#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) +#define TW_MASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) +#define TW_UNMASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) +#define TW_SOFT_RESET(x) (writel(TW_CONTROL_ISSUE_SOFT_RESET | \ + TW_CONTROL_CLEAR_HOST_INTERRUPT | \ + TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \ + TW_CONTROL_MASK_COMMAND_INTERRUPT | \ + TW_CONTROL_MASK_RESPONSE_INTERRUPT | \ + TW_CONTROL_CLEAR_ERROR_STATUS | \ + TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) +#define TW_PRINTK(h,a,b,c) { \ +if (h) \ +printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \ +else \ +printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \ +} + +#pragma pack(1) + +/* Scatter Gather List Entry */ +typedef struct TAG_TW_SG_Entry { + unsigned long address; + u32 length; +} TW_SG_Entry; + +/* Command Packet */ +typedef struct TW_Command { + unsigned char opcode__sgloffset; + unsigned char size; + unsigned char request_id; + unsigned char unit__hostid; + /* Second DWORD */ + unsigned char status; + unsigned char flags; + union { + unsigned short block_count; + unsigned short parameter_count; + } byte6_offset; + union { + struct { + u32 lba; + TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; +#if BITS_PER_LONG > 32 + u32 padding[2]; /* pad to 512 bytes */ +#else + u32 padding; +#endif + } io; + struct { + TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; +#if BITS_PER_LONG > 32 + u32 padding[3]; +#else + u32 padding[2]; +#endif + } param; + } byte8_offset; +} TW_Command; + +/* Scatter gather element for 9000+ controllers */ +typedef struct TAG_TW_SG_Apache { + unsigned long address; + u32 length; +} TW_SG_Apache; + +/* Command Packet for 9000+ controllers */ +typedef struct TAG_TW_Command_Apache { + unsigned char opcode__reserved; + unsigned char unit; + unsigned short request_id; + unsigned char status; + unsigned char sgl_offset; + unsigned short sgl_entries; + unsigned char cdb[16]; + TW_SG_Apache sg_list[TW_APACHE_MAX_SGL_LENGTH]; +#if BITS_PER_LONG > 32 + unsigned char padding[8]; +#endif +} TW_Command_Apache; + +/* New command packet header */ +typedef struct TAG_TW_Command_Apache_Header { + unsigned char sense_data[TW_SENSE_DATA_LENGTH]; + struct { + char reserved[4]; + unsigned short error; + unsigned char padding; + unsigned char severity__reserved; + } status_block; + unsigned char err_specific_desc[98]; + struct { + unsigned char size_header; + unsigned short reserved; + unsigned char size_sense; + } header_desc; +} TW_Command_Apache_Header; + +/* This struct is a union of the 2 command packets */ +typedef struct TAG_TW_Command_Full { + TW_Command_Apache_Header header; + union { + TW_Command oldcommand; + TW_Command_Apache newcommand; + } command; +} TW_Command_Full; + +/* Initconnection structure */ +typedef struct TAG_TW_Initconnect { + unsigned char opcode__reserved; + unsigned char size; + unsigned char request_id; + unsigned char res2; + unsigned char status; + unsigned char flags; + unsigned short message_credits; + u32 features; + unsigned short fw_srl; + unsigned short fw_arch_id; + unsigned short fw_branch; + unsigned short fw_build; + u32 result; +} TW_Initconnect; + +/* Event info structure */ +typedef struct TAG_TW_Event +{ + unsigned int sequence_id; + unsigned int time_stamp_sec; + unsigned short aen_code; + unsigned char severity; + unsigned char retrieved; + unsigned char repeat_count; + unsigned char parameter_len; + unsigned char parameter_data[98]; +} TW_Event; + +typedef struct TAG_TW_Ioctl_Driver_Command { + unsigned int control_code; + unsigned int status; + unsigned int unique_id; + unsigned int sequence_id; + unsigned int os_specific; + unsigned int buffer_length; +} TW_Ioctl_Driver_Command; + +typedef struct TAG_TW_Ioctl_Apache { + TW_Ioctl_Driver_Command driver_command; + char padding[488]; + TW_Command_Full firmware_command; + char data_buffer[1]; +} TW_Ioctl_Buf_Apache; + +/* Lock structure for ioctl get/release lock */ +typedef struct TAG_TW_Lock { + unsigned long timeout_msec; + unsigned long time_remaining_msec; + unsigned long force_flag; +} TW_Lock; + +/* GetParam descriptor */ +typedef struct { + unsigned short table_id; + unsigned short parameter_id; + unsigned short parameter_size_bytes; + unsigned short actual_parameter_size_bytes; + unsigned char data[1]; +} TW_Param_Apache, *PTW_Param_Apache; + +/* Response queue */ +typedef union TAG_TW_Response_Queue { + u32 response_id; + u32 value; +} TW_Response_Queue; + +typedef struct TAG_TW_Info { + char *buffer; + int length; + int offset; + int position; +} TW_Info; + +/* Compatibility information structure */ +typedef struct TAG_TW_Compatibility_Info +{ + char driver_version[32]; + unsigned short working_srl; + unsigned short working_branch; + unsigned short working_build; +} TW_Compatibility_Info; + +typedef struct TAG_TW_Device_Extension { + u32 *base_addr; + unsigned long *generic_buffer_virt[TW_Q_LENGTH]; + unsigned long generic_buffer_phys[TW_Q_LENGTH]; + TW_Command_Full *command_packet_virt[TW_Q_LENGTH]; + unsigned long command_packet_phys[TW_Q_LENGTH]; + struct pci_dev *tw_pci_dev; + struct scsi_cmnd *srb[TW_Q_LENGTH]; + unsigned char free_queue[TW_Q_LENGTH]; + unsigned char free_head; + unsigned char free_tail; + unsigned char pending_queue[TW_Q_LENGTH]; + unsigned char pending_head; + unsigned char pending_tail; + int state[TW_Q_LENGTH]; + unsigned int posted_request_count; + unsigned int max_posted_request_count; + unsigned int pending_request_count; + unsigned int max_pending_request_count; + unsigned int max_sgl_entries; + unsigned int sgl_entries; + unsigned int num_aborts; + unsigned int num_resets; + unsigned int sector_count; + unsigned int max_sector_count; + unsigned int aen_count; + struct Scsi_Host *host; + long flags; + int reset_print; + TW_Event *event_queue[TW_Q_LENGTH]; + unsigned char error_index; + unsigned char event_queue_wrapped; + unsigned int error_sequence_id; + int ioctl_sem_lock; + u32 ioctl_msec; + int chrdev_request_id; + wait_queue_head_t ioctl_wqueue; + struct semaphore ioctl_sem; + char aen_clobber; + unsigned short working_srl; + unsigned short working_branch; + unsigned short working_build; +} TW_Device_Extension; + +#pragma pack() + +#endif /* _3W_9XXX_H */ + diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index e7a540d6e..ad6425c6b 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -220,7 +220,7 @@ MODULE_LICENSE("GPL"); #define __3W_C /* let 3w-xxxx.h know it is use */ #include "scsi.h" -#include "hosts.h" +#include #include "3w-xxxx.h" diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index f623d8c39..632488e1a 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -135,7 +135,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index 464c26111..8ead55f75 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -280,7 +280,7 @@ #endif #include "scsi.h" -#include "hosts.h" +#include #include "53c7xx.h" #include #include diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 59cded0a0..e4d60d1d1 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -48,7 +48,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "BusLogic.h" #include "FlashPoint.c" diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4390af7a1..0cd207e9e 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -352,7 +352,7 @@ source "drivers/scsi/aic7xxx/Kconfig.aic79xx" # All the I2O code and drivers do not seem to be 64bit safe. config SCSI_DPT_I2O tristate "Adaptec I2O RAID support " - depends on !64BIT && SCSI && PCI + depends on !64BIT && SCSI help This driver supports all of Adaptec's I2O based RAID controllers as well as the DPT SmartRaid V cards. This is an Adaptec maintained @@ -494,15 +494,9 @@ config SCSI_OMIT_FLASHPOINT substantial, so users of MultiMaster Host Adapters may wish to omit it. -# -# This is marked broken because it uses over 4kB of stack in -# just two routines: -# 2076 CpqTsProcessIMQEntry -# 2052 PeekIMQEntry -# config SCSI_CPQFCTS tristate "Compaq Fibre Channel 64-bit/66Mhz HBA support" - depends on PCI && SCSI && BROKEN + depends on PCI && SCSI help Say Y here to compile in support for the Compaq StorageWorks Fibre Channel 64-bit/66Mhz Host Bus Adapter. diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 22ee2db60..21350295b 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -36,7 +36,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 2abc6e478..3f457dc1b 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -54,7 +54,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include /* ============================================================= */ diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 329f0eea1..8c0fc3fb7 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -100,7 +100,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "53c700.h" #include "NCR_D700.h" diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index c9e3a5fca..6141faabe 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -16,7 +16,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "ncr53c8xx.h" diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index ecaf2d9c5..9928a2fbc 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -16,7 +16,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "a2091.h" diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 23071c15d..f8a89ec25 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -15,7 +15,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "a3000.h" diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 7b53e02fa..c48c59a1f 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -807,7 +807,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "advansys.h" #ifdef CONFIG_PCI #include diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 6a5291b65..6e9d28f8f 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -577,11 +577,11 @@ struct aha152x_scdata { #define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) #define MSGO_I (HOSTDATA(shpnt)->msgo_i) #define MSGOLEN (HOSTDATA(shpnt)->msgo_len) -#define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow")) +#define ADDMSGO(x) (MSGOLEN<256 ? MSGO(MSGOLEN++)=x : aha152x_error(shpnt,"MSGO overflow")) #define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) #define MSGILEN (HOSTDATA(shpnt)->msgi_len) -#define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow")) +#define ADDMSGI(x) (MSGILEN<256 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow")) #define DATA_LEN (HOSTDATA(shpnt)->data_len) diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 030c971f5..3f349a4b0 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -47,7 +47,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "aha1542.h" #define SCSI_BUF_PA(address) isa_virt_to_bus(address) diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 0a2ea05ed..73f33e716 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -56,7 +56,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "aha1740.h" /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 9d73eb357..720910812 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -68,7 +68,7 @@ /* Core SCSI definitions */ #define AIC_LIB_PREFIX ahd #include "scsi.h" -#include "hosts.h" +#include /* Name space conflict with BSD queue macros */ #ifdef LIST_HEAD diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 4315120ce..d8217edc2 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -85,7 +85,7 @@ /* Core SCSI definitions */ #define AIC_LIB_PREFIX ahc #include "scsi.h" -#include "hosts.h" +#include /* Name space conflict with BSD queue macros */ #ifdef LIST_HEAD diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 68a163362..79bfd9efd 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -36,7 +36,7 @@ /* Core SCSI definitions */ #include "scsi.h" -#include "hosts.h" +#include #include "aiclib.h" #include "cam.h" diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 66069115e..def806758 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -239,7 +239,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "aic7xxx_old/aic7xxx.h" #include "aic7xxx_old/sequencer.h" diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 034194e06..5f13546d6 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -25,7 +25,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "53c7xx.h" #include "amiga7xx.h" diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index a6588b0f8..3363c718b 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -424,15 +424,16 @@ static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, int w_flag = 0x10 << drive_dn; int u_speed = 0; int sitre; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; + u16 reg4042, reg44, reg48, reg4a, reg54; + u8 reg55; pci_read_config_word(dev, maslave, ®4042); DPRINTK("reg4042 = 0x%04x\n", reg4042); sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_word(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { @@ -449,19 +450,23 @@ static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, } if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); + pci_write_config_word(dev, 0x48, reg48|u_flag); if (speed == XFER_UDMA_5) { pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); } else { pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } + } else { + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + } } /* move to PCI layer, integrate w/ MSI stuff */ diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index f44a47301..c3d8bc82e 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -102,7 +102,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "atari_scsi.h" #include "NCR5380.h" #include diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index bd7315824..7be2b7210 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -35,7 +35,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "atp870u.h" /* diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 195a45084..4cd9fcf4d 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -28,7 +28,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c index 74ea2b794..c5221d0de 100644 --- a/drivers/scsi/blz2060.c +++ b/drivers/scsi/blz2060.c @@ -28,7 +28,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c index 2b5a80ce3..29c7ed30c 100644 --- a/drivers/scsi/bvme6000.c +++ b/drivers/scsi/bvme6000.c @@ -17,7 +17,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "53c7xx.h" #include "bvme6000.h" diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index e777bb078..508d84f6e 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -12,7 +12,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #define CONST_COMMAND 0x01 #define CONST_STATUS 0x02 diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c index 9855a8587..2bd4bc6c6 100644 --- a/drivers/scsi/cpqfcTScontrol.c +++ b/drivers/scsi/cpqfcTScontrol.c @@ -45,7 +45,7 @@ #include #include "scsi.h" -#include "hosts.h" // Scsi_Host definition for INT handler +#include // Scsi_Host definition for INT handler #include "cpqfcTSchip.h" #include "cpqfcTSstructs.h" @@ -607,7 +607,6 @@ static int PeekIMQEntry( PTACHYON fcChip, ULONG type) if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 ) { TachFCHDR_GCMND* fchs; -#error This is too much stack ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL); @@ -719,7 +718,6 @@ int CpqTsProcessIMQEntry(void *host) ULONG x_ID; ULONG ulBuff, dwStatus; TachFCHDR_GCMND* fchs; -#error This is too much stack ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index 771c206ea..8778aac34 100644 --- a/drivers/scsi/cpqfcTSinit.c +++ b/drivers/scsi/cpqfcTSinit.c @@ -51,7 +51,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #include "cpqfcTSchip.h" #include "cpqfcTSstructs.h" @@ -1266,7 +1266,7 @@ static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd) -// The file "hosts.h" says not to call scsi_done from +// The file says not to call scsi_done from // inside _queuecommand, so we'll do it from the heartbeat timer // (clarification: Turns out it's ok to call scsi_done from queuecommand // for cases that don't go to the hardware like scsi cmds destined diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c index 026b613c3..a5fd7427e 100644 --- a/drivers/scsi/cpqfcTSworker.c +++ b/drivers/scsi/cpqfcTSworker.c @@ -39,7 +39,7 @@ #include #include "scsi.h" -#include "hosts.h" // struct Scsi_Host definition for T handler +#include // struct Scsi_Host definition for T handler #include "cpqfcTSchip.h" #include "cpqfcTSstructs.h" #include "cpqfcTStrigger.h" diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c index 61d50bad4..bdbca85d1 100644 --- a/drivers/scsi/cyberstorm.c +++ b/drivers/scsi/cyberstorm.c @@ -31,7 +31,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c index 0bd553392..845d92598 100644 --- a/drivers/scsi/cyberstormII.c +++ b/drivers/scsi/cyberstormII.c @@ -27,7 +27,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 2a062f15b..d51561baf 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -53,7 +53,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "dc395x.h" #include /* needed for scsicam_bios_param */ #include diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index 737b59825..f4bdec16d 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -29,7 +29,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c index ac3b28743..26e060bb8 100644 --- a/drivers/scsi/dmx3191d.c +++ b/drivers/scsi/dmx3191d.c @@ -34,7 +34,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "dmx3191d.h" diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 261836da2..5139b0631 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -69,7 +69,7 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); #include /* for virt_to_bus, etc. */ #include "scsi.h" -#include "hosts.h" +#include #include "dpt/dptsig.h" #include "dpti.h" diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 820ac1f8b..624c7ee5d 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -84,7 +84,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "dtc.h" #define AUTOPROBE_IRQ #include "NCR5380.h" diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 5235f9ed5..0e245e318 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -495,7 +495,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 28f3e1a02..ea79b5604 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -63,7 +63,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include "eata_generic.h" diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 782c31bec..5237cad18 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "esp.h" @@ -37,17 +36,13 @@ #include #include #include + #ifndef __sparc_v9__ #include #include #endif -#include -#include -#include -#include -#include -#include +#include #define DEBUG_ESP /* #define DEBUG_ESP_HME */ diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h index 85beb4750..295739469 100644 --- a/drivers/scsi/esp.h +++ b/drivers/scsi/esp.h @@ -8,9 +8,22 @@ #ifndef _SPARC_ESP_H #define _SPARC_ESP_H +#include + +/* #include "scsi.h" */ +#include +#include +#include +#include +#include +#include +#include + /* For dvma controller register definitions. */ #include +#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) + /* The ESP SCSI controllers have their register sets in three * "classes": * @@ -73,8 +86,6 @@ struct esp_device { unsigned disconnect:1; }; -struct scsi_cmnd; - /* We get one of these for each ESP probed. */ struct esp { unsigned long eregs; /* ESP controller registers */ diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c index b24ef2eda..356919f0e 100644 --- a/drivers/scsi/fastlane.c +++ b/drivers/scsi/fastlane.c @@ -36,7 +36,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c index 7c1bc8a28..0dad89d4c 100644 --- a/drivers/scsi/fcal.c +++ b/drivers/scsi/fcal.c @@ -21,7 +21,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "../fc4/fcp_impl.h" #include "fcal.h" diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index 4060e2948..9046901d7 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -93,7 +93,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "fd_mcs.h" #define DRIVER_VERSION "v0.2 by ZP Gu" diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 7b53d006c..0fff870e5 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -284,7 +284,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include MODULE_AUTHOR("Rickard E. Faith"); MODULE_DESCRIPTION("Future domain SCSI driver"); diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index f289be23c..02055ff92 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -107,7 +107,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "g_NCR5380.h" #include "NCR5380.h" #include diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 78b3a5120..5047d985b 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -3520,7 +3520,7 @@ static void gdth_readapp_event(gdth_ha_str *ha, GDTH_UNLOCK_HA(ha, flags); } -static void gdth_clear_events(void) +static void gdth_clear_events() { TRACE(("gdth_clear_events()")); @@ -5293,13 +5293,13 @@ static int gdth_close(struct inode *inode, struct file *filep) return 0; } -static int ioc_event(void __user *arg) +static int ioc_event(unsigned long arg) { gdth_ioctl_event evt; gdth_ha_str *ha; ulong flags; - if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) || + if (copy_from_user(&evt, (char *)arg, sizeof(gdth_ioctl_event)) || evt.ionode >= gdth_ctr_count) return -EFAULT; ha = HADATA(gdth_ctr_tab[evt.ionode]); @@ -5324,19 +5324,19 @@ static int ioc_event(void __user *arg) } else { gdth_readapp_event(ha, evt.erase, &evt.event); } - if (copy_to_user(arg, &evt, sizeof(gdth_ioctl_event))) + if (copy_to_user((char *)arg, &evt, sizeof(gdth_ioctl_event))) return -EFAULT; return 0; } -static int ioc_lockdrv(void __user *arg) +static int ioc_lockdrv(unsigned long arg) { gdth_ioctl_lockdrv ldrv; unchar i, j; ulong flags; gdth_ha_str *ha; - if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) || + if (copy_from_user(&ldrv, (char *)arg, sizeof(gdth_ioctl_lockdrv)) || ldrv.ionode >= gdth_ctr_count) return -EFAULT; ha = HADATA(gdth_ctr_tab[ldrv.ionode]); @@ -5362,7 +5362,7 @@ static int ioc_lockdrv(void __user *arg) return 0; } -static int ioc_resetdrv(void __user *arg, char *cmnd) +static int ioc_resetdrv(unsigned long arg, char *cmnd) { gdth_ioctl_reset res; gdth_cmd_str cmd; @@ -5376,7 +5376,7 @@ static int ioc_resetdrv(void __user *arg, char *cmnd) Scsi_Cmnd scp; #endif - if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) || + if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) || res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES) return -EFAULT; hanum = res.ionode; @@ -5418,12 +5418,12 @@ static int ioc_resetdrv(void __user *arg, char *cmnd) gdth_do_cmd(&scp, &cmd, cmnd, 30); res.status = (ushort)scp.SCp.Status; #endif - if (copy_to_user(arg, &res, sizeof(gdth_ioctl_reset))) + if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset))) return -EFAULT; return 0; } -static int ioc_general(void __user *arg, char *cmnd) +static int ioc_general(unsigned long arg, char *cmnd) { gdth_ioctl_general gen; char *buf = NULL; @@ -5438,7 +5438,7 @@ static int ioc_general(void __user *arg, char *cmnd) Scsi_Cmnd scp; #endif - if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) || + if (copy_from_user(&gen, (char *)arg, sizeof(gdth_ioctl_general)) || gen.ionode >= gdth_ctr_count) return -EFAULT; hanum = gen.ionode; @@ -5447,7 +5447,7 @@ static int ioc_general(void __user *arg, char *cmnd) if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, FALSE, &paddr))) return -EFAULT; - if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), + if (copy_from_user(buf, (char *)arg + sizeof(gdth_ioctl_general), gen.data_len + gen.sense_len)) { gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; @@ -5559,12 +5559,12 @@ static int ioc_general(void __user *arg, char *cmnd) gen.info = scp.SCp.Message; #endif - if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, + if (copy_to_user((char *)arg + sizeof(gdth_ioctl_general), buf, gen.data_len + gen.sense_len)) { gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; } - if (copy_to_user(arg, &gen, + if (copy_to_user((char *)arg, &gen, sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) { gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr); return -EFAULT; @@ -5573,7 +5573,7 @@ static int ioc_general(void __user *arg, char *cmnd) return 0; } -static int ioc_hdrlist(void __user *arg, char *cmnd) +static int ioc_hdrlist(unsigned long arg, char *cmnd) { gdth_ioctl_rescan rsc; gdth_cmd_str cmd; @@ -5588,7 +5588,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) Scsi_Cmnd scp; #endif - if (copy_from_user(&rsc, arg, sizeof(gdth_ioctl_rescan)) || + if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) || rsc.ionode >= gdth_ctr_count) return -EFAULT; hanum = rsc.ionode; @@ -5652,12 +5652,12 @@ static int ioc_hdrlist(void __user *arg, char *cmnd) scsi_release_command(scp); #endif - if (copy_to_user(arg, &rsc, sizeof(gdth_ioctl_rescan))) + if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan))) return -EFAULT; return 0; } -static int ioc_rescan(void __user *arg, char *cmnd) +static int ioc_rescan(unsigned long arg, char *cmnd) { gdth_ioctl_rescan rsc; gdth_cmd_str cmd; @@ -5674,7 +5674,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) Scsi_Cmnd scp; #endif - if (copy_from_user(&rsc, arg, sizeof(gdth_ioctl_rescan)) || + if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) || rsc.ionode >= gdth_ctr_count) return -EFAULT; hanum = rsc.ionode; @@ -5852,7 +5852,7 @@ static int ioc_rescan(void __user *arg, char *cmnd) scsi_release_command(scp); #endif - if (copy_to_user(arg, &rsc, sizeof(gdth_ioctl_rescan))) + if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan))) return -EFAULT; return 0; } @@ -5870,7 +5870,6 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, #endif ulong flags; char cmnd[MAX_COMMAND_SIZE]; - void __user *argp = (void __user *)arg; memset(cmnd, 0xff, 12); @@ -5880,7 +5879,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, case GDTIOCTL_CTRCNT: { int cnt = gdth_ctr_count; - if (put_user(cnt, (int __user *)argp)) + if (put_user(cnt, (int *)arg)) return -EFAULT; break; } @@ -5888,7 +5887,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, case GDTIOCTL_DRVERS: { int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION; - if (put_user(ver, (int __user *)argp)) + if (put_user(ver, (int *)arg)) return -EFAULT; break; } @@ -5900,7 +5899,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, osv.version = (unchar)(LINUX_VERSION_CODE >> 16); osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8); osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff); - if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers))) + if (copy_to_user((char *)arg, &osv, sizeof(gdth_ioctl_osvers))) return -EFAULT; break; } @@ -5909,7 +5908,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, { gdth_ioctl_ctrtype ctrt; - if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) || + if (copy_from_user(&ctrt, (char *)arg, sizeof(gdth_ioctl_ctrtype)) || ctrt.ionode >= gdth_ctr_count) return -EFAULT; ha = HADATA(gdth_ctr_tab[ctrt.ionode]); @@ -5931,26 +5930,26 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, } ctrt.info = ha->brd_phys; ctrt.oem_id = ha->oem_id; - if (copy_to_user(argp, &ctrt, sizeof(gdth_ioctl_ctrtype))) + if (copy_to_user((char *)arg, &ctrt, sizeof(gdth_ioctl_ctrtype))) return -EFAULT; break; } case GDTIOCTL_GENERAL: - return ioc_general(argp, cmnd); + return ioc_general(arg, cmnd); case GDTIOCTL_EVENT: - return ioc_event(argp); + return ioc_event(arg); case GDTIOCTL_LOCKDRV: - return ioc_lockdrv(argp); + return ioc_lockdrv(arg); case GDTIOCTL_LOCKCHN: { gdth_ioctl_lockchn lchn; unchar i, j; - if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || + if (copy_from_user(&lchn, (char *)arg, sizeof(gdth_ioctl_lockchn)) || lchn.ionode >= gdth_ctr_count) return -EFAULT; ha = HADATA(gdth_ctr_tab[lchn.ionode]); @@ -5979,17 +5978,17 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, } case GDTIOCTL_RESCAN: - return ioc_rescan(argp, cmnd); + return ioc_rescan(arg, cmnd); case GDTIOCTL_HDRLIST: - return ioc_hdrlist(argp, cmnd); + return ioc_hdrlist(arg, cmnd); case GDTIOCTL_RESET_BUS: { gdth_ioctl_reset res; int hanum, rval; - if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) || + if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) || res.ionode >= gdth_ctr_count) return -EFAULT; hanum = res.ionode; @@ -6026,13 +6025,13 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, rval = gdth_eh_bus_reset(&scp); res.status = (rval == SUCCESS ? S_OK : S_GENERR); #endif - if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset))) + if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset))) return -EFAULT; break; } case GDTIOCTL_RESET_DRV: - return ioc_resetdrv(argp, cmnd); + return ioc_resetdrv(arg, cmnd); default: break; diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index ba5db045e..30cbf73c7 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -16,7 +16,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "gvp11.h" diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index ac68554c6..c27264bed 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -1,2 +1,2 @@ -// #warning "This file is obsolete, please use instead" +#warning "This file is obsolete, please use instead" #include diff --git a/drivers/scsi/i60uscsi.c b/drivers/scsi/i60uscsi.c index 03f6862c4..5f3ed937f 100644 --- a/drivers/scsi/i60uscsi.c +++ b/drivers/scsi/i60uscsi.c @@ -81,7 +81,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "inia100.h" #define JIFFIES_TO_MS(t) ((t) * 1000 / HZ) diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 9503802d2..917dc2ed9 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -45,7 +45,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "ibmmca.h" /* current version of this driver-source: */ diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 9b110a8e2..b4683333c 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -51,7 +51,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #define IDESCSI_DEBUG_LOG 0 @@ -318,13 +318,6 @@ ide_startstop_t idescsi_atapi_error (ide_drive_t *drive, const char *msg, byte s if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; - /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { - rq->errors = 1; - ide_end_drive_cmd(drive, stat, err); - return ide_stopped; - } - if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) /* force an abort */ HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); @@ -341,13 +334,6 @@ ide_startstop_t idescsi_atapi_abort (ide_drive_t *drive, const char *msg) if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; - /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) { - rq->errors = 1; - ide_end_drive_cmd(drive, BUSY_STAT, 0); - return ide_stopped; - } - #if IDESCSI_DEBUG_LOG printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n", ((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number); diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index 4ce6d7675..dc3aebf0e 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h @@ -79,7 +79,7 @@ #include #include -#include "hosts.h" +#include /* batteries not included :-) */ /* diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 7bdf75f25..46d18e36b 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -126,7 +126,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #define IN2000_VERSION "1.33-2.5" #define IN2000_DATE "2002/11/03" diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c index e634b66e8..96fa264b8 100644 --- a/drivers/scsi/ini9100u.c +++ b/drivers/scsi/ini9100u.c @@ -136,7 +136,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "ini9100u.h" #ifdef DEBUG_i91u diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e9c5098ed..2114bbf1e 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2884,6 +2884,7 @@ static int ipr_slave_alloc(struct scsi_device *sdev) (res->cfgte.res_addr.lun == sdev->lun)) { res->sdev = sdev; res->add_to_ml = 0; + res->in_erp = 0; sdev->hostdata = res; res->needs_sync_complete = 1; break; @@ -3435,8 +3436,10 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) SCSI_SENSE_BUFFERSIZE); } - if (res) + if (res) { res->needs_sync_complete = 1; + res->in_erp = 0; + } ipr_unmap_sglist(ioa_cfg, ipr_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); scsi_cmd->scsi_done(scsi_cmd); @@ -3479,6 +3482,12 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) { struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { + ipr_erp_done(ipr_cmd); + return; + } ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); @@ -3756,6 +3765,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, ipr_erp_cancel_all(ipr_cmd); return; } + res->needs_sync_complete = 1; break; case IPR_IOASC_NR_INIT_CMD_REQUIRED: break; @@ -4808,6 +4818,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) ipr_cmd->timer.data = (unsigned long) ipr_cmd; ipr_cmd->timer.expires = jiffies + IPR_OPERATIONAL_TIMEOUT; ipr_cmd->timer.function = (void (*)(unsigned long))ipr_timeout; + ipr_cmd->done = ipr_reset_ioa_job; add_timer(&ipr_cmd->timer); list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 468c80796..eadafebac 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -36,8 +36,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.0.7" -#define IPR_DRIVER_DATE "(May 21, 2004)" +#define IPR_DRIVER_VERSION "2.0.9" +#define IPR_DRIVER_DATE "(May 26, 2004)" /* * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 6f7df0a46..dc110cc80 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -176,7 +176,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "ips.h" #include diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index f158ec0b9..22f74cf70 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -16,7 +16,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 27f5664f9..429c22755 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -50,7 +50,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "lasi700.h" #include "53c700.h" diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 0a42323b3..5b656df5f 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -26,7 +26,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 890484ae6..f343fc704 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -52,7 +52,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "mac_scsi.h" #include "NCR5380.h" diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c index f7b0d5c8c..e64b8ec2f 100644 --- a/drivers/scsi/mca_53c9x.c +++ b/drivers/scsi/mca_53c9x.c @@ -43,7 +43,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 7df9fc663..67e9b683b 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -49,7 +49,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "megaraid.h" @@ -4068,7 +4068,6 @@ mega_support_ext_cdb(adapter_t *adapter) static int mega_del_logdrv(adapter_t *adapter, int logdrv) { - DECLARE_WAIT_QUEUE_HEAD(wq); unsigned long flags; scb_t *scb; int rval; @@ -4086,7 +4085,8 @@ mega_del_logdrv(adapter_t *adapter, int logdrv) while( atomic_read(&adapter->pend_cmds) > 0 || !list_empty(&adapter->pending_list) ) { - sleep_on_timeout( &wq, 1*HZ ); /* sleep for 1s */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1*HZ ); /* sleep for 1s */ } rval = mega_do_del_logdrv(adapter, logdrv); diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index 62ec0569a..e73b33f29 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -11,7 +11,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "mvme147.h" diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c index 05996fb35..b2d8d8ea1 100644 --- a/drivers/scsi/mvme16x.c +++ b/drivers/scsi/mvme16x.c @@ -15,7 +15,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "53c7xx.h" #include "mvme16x.h" diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index bc51dc60d..0c20d75be 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -138,7 +138,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "ncr53c8xx.h" diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 13d5875a2..613b04836 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -44,7 +44,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c index 10c63ad28..cd9e2c66a 100644 --- a/drivers/scsi/oktagon_esp.c +++ b/drivers/scsi/oktagon_esp.c @@ -29,7 +29,7 @@ #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index b26d95ead..caa403438 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -61,7 +61,7 @@ const char * osst_version = "0.99.1"; #define OSST_DEB_MSG KERN_NOTICE #include "scsi.h" -#include "hosts.h" +#include #include #include @@ -154,8 +154,8 @@ static int modes_defined = FALSE; static OSST_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(OSST_buffer *, int); static void normalize_buffer(OSST_buffer *); -static int append_to_buffer(const char __user *, OSST_buffer *, int); -static int from_buffer(OSST_buffer *, char __user *, int); +static int append_to_buffer(const char *, OSST_buffer *, int); +static int from_buffer(OSST_buffer *, char *, int); static int osst_zero_buffer_tail(OSST_buffer *); static int osst_copy_to_buffer(OSST_buffer *, unsigned char *); static int osst_copy_from_buffer(OSST_buffer *, unsigned char *); @@ -3157,13 +3157,13 @@ static void reset_state(OS_Scsi_Tape *STp) /* Entry points to osst */ /* Write command */ -static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos) +static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) { ssize_t total, retval = 0; ssize_t i, do_count, blks, transfer; int write_threshold; int doing_write = 0; - const char __user * b_point; + const char * b_point; Scsi_Request * SRpnt = NULL; ST_mode * STm; ST_partstat * STps; @@ -3486,7 +3486,7 @@ out: /* Read command */ -static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos) +static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { ssize_t total, retval = 0; ssize_t i, transfer; @@ -5189,7 +5189,7 @@ static void normalize_buffer(OSST_buffer *STbuffer) /* Move data from the user buffer to the tape buffer. Returns zero (success) or negative error code. */ -static int append_to_buffer(const char __user *ubp, OSST_buffer *st_bp, int do_count) +static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count) { int i, cnt, res, offset; @@ -5222,7 +5222,7 @@ static int append_to_buffer(const char __user *ubp, OSST_buffer *st_bp, int do_c /* Move data from the tape buffer to the user buffer. Returns zero (success) or negative error code. */ -static int from_buffer(OSST_buffer *st_bp, char __user *ubp, int do_count) +static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count) { int i, cnt, res, offset; diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index fe5b7af58..1c9788e2d 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -125,7 +125,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "pas16.h" #define AUTOPROBE_IRQ #include "NCR5380.h" diff --git a/drivers/scsi/pc980155.c b/drivers/scsi/pc980155.c index 046b5c39a..62b2852fb 100644 --- a/drivers/scsi/pc980155.c +++ b/drivers/scsi/pc980155.c @@ -20,7 +20,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "pc980155.h" diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index 14006bc3d..60ce1cce9 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -54,7 +54,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "pci2000.h" #include "psi_roy.h" diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 2ea7c705f..e395e4203 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -59,7 +59,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "pci2220i.h" #include "psi_dale.h" diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index f1d2af999..42cdba92b 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -47,7 +47,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "aha152x.h" #include diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 344d2b5a2..4f80bcf89 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -44,7 +44,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/pcmcia/qlogic_core.c b/drivers/scsi/pcmcia/qlogic_core.c deleted file mode 100644 index 78abe22b1..000000000 --- a/drivers/scsi/pcmcia/qlogic_core.c +++ /dev/null @@ -1,2 +0,0 @@ -#define PCMCIA 1 -#include "qlogicfas.c" diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 2063882b7..9ea9a108b 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -46,7 +46,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "../qlogicfas408.h" #include diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index f7677c977..7bb0a2e56 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -21,7 +21,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "../fc4/fcp_impl.h" #include "pluto.h" diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index afb614fa8..f6e1a1574 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -86,7 +86,7 @@ #include #include -#include "hosts.h" +#include /* batteries not included :-) */ /* diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index 6bb14acbf..aa505c1ba 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -41,7 +41,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "psi240i.h" #include "psi_chip.h" diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index dd482a9e6..f5a16ab7c 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -357,7 +357,7 @@ #else #include #include "scsi.h" -#include "hosts.h" +#include #include "sd.h" #endif diff --git a/drivers/scsi/qla2xxx/qla_os.h b/drivers/scsi/qla2xxx/qla_os.h index a5d79103f..c3ed2a6bb 100644 --- a/drivers/scsi/qla2xxx/qla_os.h +++ b/drivers/scsi/qla2xxx/qla_os.h @@ -59,7 +59,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 1641932a7..03dbd6707 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -32,7 +32,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "qlogicfas408.h" /* Set the following to 2 to use normal interrupt (active high/totempole- diff --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h deleted file mode 100644 index 6750e8da6..000000000 --- a/drivers/scsi/qlogicfas.h +++ /dev/null @@ -1,124 +0,0 @@ -/* to be used by qlogicfas and qlogic_cs */ -#ifndef __QLOGICFAS_H -#define __QLOGICFAS_H - -/*----------------------------------------------------------------*/ -/* Configuration */ - -/* Set the following to 2 to use normal interrupt (active high/totempole- - tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - drain */ - -#define QL_INT_ACTIVE_HIGH 2 - -/* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable. */ - -#define QL_TURBO_PDMA 1 - -/* This should be 1 to enable parity detection */ - -#define QL_ENABLE_PARITY 1 - -/* This will reset all devices when the driver is initialized (during bootup). - The other linux drivers don't do this, but the DOS drivers do, and after - using DOS or some kind of crash or lockup this will bring things back - without requiring a cold boot. It does take some time to recover from a - reset, so it is slower, and I have seen timeouts so that devices weren't - recognized when this was set. */ - -#define QL_RESET_AT_START 0 - -/* crystal frequency in megahertz (for offset 5 and 9) - Please set this for your card. Most Qlogic cards are 40 Mhz. The - Control Concepts ISA (not VLB) is 24 Mhz */ - -#define XTALFREQ 40 - -/**********/ -/* DANGER! modify these at your own risk */ -/* SLOWCABLE can usually be reset to zero if you have a clean setup and - proper termination. The rest are for synchronous transfers and other - advanced features if your device can transfer faster than 5Mb/sec. - If you are really curious, email me for a quick howto until I have - something official */ -/**********/ - -/*****/ -/* config register 1 (offset 8) options */ -/* This needs to be set to 1 if your cabling is long or noisy */ -#define SLOWCABLE 1 - -/*****/ -/* offset 0xc */ -/* This will set fast (10Mhz) synchronous timing when set to 1 - For this to have an effect, FASTCLK must also be 1 */ -#define FASTSCSI 0 - -/* This when set to 1 will set a faster sync transfer rate */ -#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ - -/*****/ -/* offset 6 */ -/* This is the sync transfer divisor, XTALFREQ/X will be the maximum - achievable data rate (assuming the rest of the system is capable - and set properly) */ -#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ - -/*****/ -/* offset 7 */ -/* This is the count of how many synchronous transfers can take place - i.e. how many reqs can occur before an ack is given. - The maximum value for this is 15, the upper bits can modify - REQ/ACK assertion and deassertion during synchronous transfers - If this is 0, the bus will only transfer asynchronously */ -#define SYNCOFFST 0 -/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles - of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will - cause the deassertion to be early by 1/2 clock. Bits 5&4 control - the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ - -/*----------------------------------------------------------------*/ -#ifdef PCMCIA -#undef QL_INT_ACTIVE_HIGH -#define QL_INT_ACTIVE_HIGH 0 -#endif - -struct qlogicfas_priv; -typedef struct qlogicfas_priv *qlogicfas_priv_t; -struct qlogicfas_priv { - int qbase; /* Port */ - int qinitid; /* initiator ID */ - int qabort; /* Flag to cause an abort */ - int qlirq; /* IRQ being used */ - char qinfo[80]; /* description */ - Scsi_Cmnd *qlcmd; /* current command being processed */ - struct Scsi_Host *shost; /* pointer back to host */ - qlogicfas_priv_t next; /* next private struct */ -}; - -extern int qlcfg5; -extern int qlcfg6; -extern int qlcfg7; -extern int qlcfg8; -extern int qlcfg9; -extern int qlcfgc; - -/* The qlogic card uses two register maps - These macros select which one */ -#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) - -/* following is watchdog timeout in microseconds */ -#define WATCHDOG 5000000 - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at and as a simple profiler) */ - -#if 0 -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif -#endif /* __QLOGICFAS_H */ - diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 32c9cd413..5b6ce0a88 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -56,7 +56,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "qlogicfas408.h" /*----------------------------------------------------------------*/ diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 015fd8d5b..a13200d18 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -64,7 +64,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32))) #define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a))))) diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index ecce3a3d7..1be526c1c 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -36,7 +36,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "qlogicisp.h" /* Configuration section *****************************************************/ diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c49ca7f2f..29522c4f5 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -23,7 +23,6 @@ #include #include #include -#include #include @@ -38,15 +37,7 @@ #include #include -#include -#include -#include -#include -#include -#include -#include - - +#include #define MAX_TARGETS 16 #define MAX_LUNS 8 /* 32 for 1.31 F/W */ diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index a40ff75ca..91dead6ad 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -6,6 +6,19 @@ #ifndef _QLOGICPTI_H #define _QLOGICPTI_H +#include + +/* #include "scsi.h" */ +#include +#include +#include +#include +#include +#include +#include + +#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) + /* Qlogic/SBUS controller registers. */ #define SBUS_CFG1 0x006UL #define SBUS_CTRL 0x008UL @@ -330,8 +343,6 @@ struct pti_queue_entry { char __opaque[QUEUE_ENTRY_LEN]; }; -struct scsi_cmnd; - /* Software state for the driver. */ struct qlogicpti { /* These are the hot elements in the cache, so they come first. */ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index da7dfb3d9..3e7e2cb39 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -43,7 +43,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include @@ -1461,7 +1461,7 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, sdebug_add_host_store) -static void do_create_driverfs_files(void) +static void do_create_driverfs_files() { driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); @@ -1473,7 +1473,7 @@ static void do_create_driverfs_files(void) driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); } -static void do_remove_driverfs_files(void) +static void do_remove_driverfs_files() { driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); @@ -1594,7 +1594,7 @@ static void sdebug_release_adapter(struct device * dev) kfree(sdbg_host); } -static int sdebug_add_adapter(void) +static int sdebug_add_adapter() { int k, devs_per_host; int error = 0; @@ -1657,7 +1657,7 @@ clean: return error; } -static void sdebug_remove_adapter(void) +static void sdebug_remove_adapter() { struct sdebug_host_info * sdbg_host = NULL; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index cb97efc6c..0dedc422c 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -9,7 +9,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "scsi_priv.h" /* @@ -117,8 +117,10 @@ static struct { */ {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, + {"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN}, {"BELKIN", "USB 2 HS-CF", "1.95", BLIST_SPARSELUN}, {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, + {"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN}, {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ @@ -139,6 +141,8 @@ static struct { {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN}, + {"Generic", "USB Storage-SMC", "0090", BLIST_FORCELUN}, {"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN}, {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN}, {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, @@ -151,6 +155,7 @@ static struct { {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"ICSI", "SD Card", "2.7C", BLIST_FORCELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, @@ -171,6 +176,7 @@ static struct { {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, {"SGI", "RAID3", "*", BLIST_SPARSELUN}, {"SGI", "RAID5", "*", BLIST_SPARSELUN}, {"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, @@ -182,6 +188,7 @@ static struct { {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, + {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN}, {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 58ac2319a..05ebb8c86 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,7 +26,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "scsi_priv.h" #include "scsi_logging.h" diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 03390c078..76f0a64bd 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -20,7 +20,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include "scsi_logging.h" diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c index b8cc3ead9..d835a505b 100644 --- a/drivers/scsi/scsi_module.c +++ b/drivers/scsi/scsi_module.c @@ -12,7 +12,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include static int __init init_this_scsi_driver(void) diff --git a/drivers/scsi/scsi_pc98.c b/drivers/scsi/scsi_pc98.c index 13fdfa9f2..319df013a 100644 --- a/drivers/scsi/scsi_pc98.c +++ b/drivers/scsi/scsi_pc98.c @@ -12,7 +12,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include static int pc98_first_bios_param(struct scsi_device *sdev, int *ip) diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index d17702eec..b7ce44480 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -19,7 +19,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9d29d78e1..99a8df70b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -52,7 +52,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 3a73cc7e6..43102408d 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -103,7 +103,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "seagate.h" #include diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 5db8178c3..e0f17f0b4 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -51,7 +51,7 @@ static int sg_version_num = 30531; /* 2 digits for each component */ #include #include "scsi.h" -#include "hosts.h" +#include #include #include #include @@ -241,6 +241,12 @@ sg_open(struct inode *inode, struct file *filp) return -ENXIO; if (sdp->detached) return -ENODEV; + + /* scsi generic is only for non-disk, non-cd, non-tape devices */ + if ( (sdp->device->type == TYPE_DISK) || (sdp->device->type == TYPE_MOD) || (sdp->device->type == TYPE_ROM) + || (sdp->device->type == TYPE_WORM) || ( sdp->device->type == TYPE_TAPE)) + printk(KERN_WARNING "%s: Using deprecated /dev/sg mechanism instead of SG_IO on the actual device\n",current->comm); + /* This driver's module count bumped by fops_get in */ /* Prevent the device driver from vanishing while we sleep */ diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index dd5627cbe..270f2aa88 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -31,7 +31,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" #include "sgiwd93.h" diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 2a833d3e5..7abd5d1cc 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -37,7 +37,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "53c700.h" diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 9c3ddba40..4713c8018 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -47,7 +47,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include /* For the door lock/unlock commands */ diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 3fc83dc73..053488579 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -11,7 +11,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include "sr.h" diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index 2f7894e70..bd7bd5704 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -41,7 +41,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0e2891593..8e1433fa1 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -58,7 +58,7 @@ static char *verstr = "20040403"; #include "scsi.h" -#include "hosts.h" +#include #include #include @@ -176,8 +176,8 @@ static int modes_defined; static ST_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(ST_buffer *, int, int); static void normalize_buffer(ST_buffer *); -static int append_to_buffer(const char __user *, ST_buffer *, int); -static int from_buffer(ST_buffer *, char __user *, int); +static int append_to_buffer(const char *, ST_buffer *, int); +static int from_buffer(ST_buffer *, char *, int); static void move_buffer_data(ST_buffer *, int); static void buf_to_sg(ST_buffer *, unsigned int); @@ -1276,7 +1276,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t } -static int setup_buffering(Scsi_Tape *STp, const char __user *buf, size_t count, int is_read) +static int setup_buffering(Scsi_Tape *STp, const char *buf, size_t count, int is_read) { int i, bufsize, retval = 0; ST_buffer *STbp = STp->buffer; @@ -1348,7 +1348,7 @@ static void release_buffering(Scsi_Tape *STp) /* Write command */ static ssize_t -st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) + st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) { ssize_t total; ssize_t i, do_count, blks, transfer; @@ -1356,7 +1356,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) int undone, retry_eot = 0, scode; int async_write; unsigned char cmd[MAX_COMMAND_SIZE]; - const char __user *b_point; + const char *b_point; Scsi_Request *SRpnt = NULL; Scsi_Tape *STp = filp->private_data; ST_mode *STm; @@ -1817,7 +1817,7 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt) /* Read command */ static ssize_t -st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) + st_read(struct file *filp, char *buf, size_t count, loff_t * ppos) { ssize_t total; ssize_t retval = 0; @@ -3527,7 +3527,7 @@ static void normalize_buffer(ST_buffer * STbuffer) /* Move data from the user buffer to the tape buffer. Returns zero (success) or negative error code. */ -static int append_to_buffer(const char __user *ubp, ST_buffer * st_bp, int do_count) +static int append_to_buffer(const char *ubp, ST_buffer * st_bp, int do_count) { int i, cnt, res, offset; @@ -3558,7 +3558,7 @@ static int append_to_buffer(const char __user *ubp, ST_buffer * st_bp, int do_co /* Move data from the tape buffer to the user buffer. Returns zero (success) or negative error code. */ -static int from_buffer(ST_buffer * st_bp, char __user *ubp, int do_count) +static int from_buffer(ST_buffer * st_bp, char *ubp, int do_count) { int i, cnt, res, offset; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index e8b76276c..f1070c80a 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -75,7 +75,7 @@ #define REAL_DMA #include "scsi.h" -#include "hosts.h" +#include #include "sun3_scsi.h" #include "NCR5380.h" diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index f82831b79..4cf3e2e7d 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -41,7 +41,7 @@ #define REAL_DMA #include "scsi.h" -#include "hosts.h" +#include #include "sun3_scsi.h" #include "NCR5380.h" diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 985a9ef8b..f2b934cd9 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -16,7 +16,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "NCR53C9x.h" #include diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index de21eabe9..9712b58da 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -43,7 +43,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include "sym53c416.h" #define VERSION_STRING "Version 1.0.0-ac" diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index addbdb529..7ef1b8c92 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -118,7 +118,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "t128.h" #define AUTOPROBE_IRQ #include "NCR5380.h" diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index c9c6cbc26..dd51823a5 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -239,7 +239,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index e274843d1..b2f69d7a8 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -423,7 +423,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #include diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 65554c41b..918e7f464 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -145,7 +145,7 @@ #define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ #include "scsi.h" -#include "hosts.h" +#include #include "ultrastor.h" #define FALSE 0 diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 19dba62ce..a54c4145f 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -83,7 +83,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include "wd33c93.h" diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 167733100..042b47af9 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -184,7 +184,7 @@ #include #include "scsi.h" -#include "hosts.h" +#include #include diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 10c7741fa..fa551b91e 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -24,7 +24,7 @@ #include "../parisc/gsc.h" #include "scsi.h" -#include "hosts.h" +#include #include "ncr53c8xx.h" diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h new file mode 100644 index 000000000..2e4f49a0c --- /dev/null +++ b/drivers/usb/class/cdc-acm.h @@ -0,0 +1,115 @@ +/* + * + * Includes for cdc-acm.c + * + * Mainly take from usbnet's cdc-ether part + * + */ + +/* + * CMSPAR, some architectures can't have space and mark parity. + */ + +#ifndef CMSPAR +#define CMSPAR 0 +#endif + +/* + * Major and minor numbers. + */ + +#define ACM_TTY_MAJOR 166 +#define ACM_TTY_MINORS 32 + +/* + * Requests. + */ + +#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) + +#define ACM_REQ_COMMAND 0x00 +#define ACM_REQ_RESPONSE 0x01 +#define ACM_REQ_SET_FEATURE 0x02 +#define ACM_REQ_GET_FEATURE 0x03 +#define ACM_REQ_CLEAR_FEATURE 0x04 + +#define ACM_REQ_SET_LINE 0x20 +#define ACM_REQ_GET_LINE 0x21 +#define ACM_REQ_SET_CONTROL 0x22 +#define ACM_REQ_SEND_BREAK 0x23 + +/* + * IRQs. + */ + +#define ACM_IRQ_NETWORK 0x00 +#define ACM_IRQ_LINE_STATE 0x20 + +/* + * Output control lines. + */ + +#define ACM_CTRL_DTR 0x01 +#define ACM_CTRL_RTS 0x02 + +/* + * Input control lines and line errors. + */ + +#define ACM_CTRL_DCD 0x01 +#define ACM_CTRL_DSR 0x02 +#define ACM_CTRL_BRK 0x04 +#define ACM_CTRL_RI 0x08 + +#define ACM_CTRL_FRAMING 0x10 +#define ACM_CTRL_PARITY 0x20 +#define ACM_CTRL_OVERRUN 0x40 + +/* + * Line speed and caracter encoding. + */ + +struct acm_line { + __u32 speed; + __u8 stopbits; + __u8 parity; + __u8 databits; +} __attribute__ ((packed)); + +/* + * Internal driver structures. + */ + +struct acm { + struct usb_device *dev; /* the corresponding usb device */ + struct usb_interface *control; /* control interface */ + struct usb_interface *data; /* data interface */ + struct tty_struct *tty; /* the corresponding tty */ + struct urb *ctrlurb, *readurb, *writeurb; /* urbs */ + struct acm_line line; /* line coding (bits, stop, parity) */ + struct work_struct work; /* work queue entry for line discipline waking up */ + struct tasklet_struct bh; /* rx processing */ + unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ + unsigned int ctrlout; /* output control lines (DTR, RTS) */ + unsigned int writesize; /* max packet size for the output bulk endpoint */ + unsigned int used; /* someone has this acm's device open */ + unsigned int minor; /* acm minor number */ + unsigned char throttle; /* throttled by tty layer */ + unsigned char clocal; /* termios CLOCAL */ + unsigned char ready_for_write; /* write urb can be used */ +}; + +/* "Union Functional Descriptor" from CDC spec 5.2.3.X */ +struct union_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 bMasterInterface0; + u8 bSlaveInterface0; + /* ... and there could be other slave interfaces */ +} __attribute__ ((packed)); + +#define CDC_UNION_TYPE 0x06 +#define CDC_DATA_INTERFACE_TYPE 0x0a + diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 29799129a..734ba0a0c 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -719,7 +719,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg) static int proc_resetdevice(struct dev_state *ps) { - return __usb_reset_device(ps->dev); + return usb_reset_device(ps->dev); } @@ -862,7 +862,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; - if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) { + if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) { kfree(isopkt); return -EFAULT; } @@ -1023,7 +1023,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) free_async(as); if (ret) return ret; - if (put_user(addr, (void __user * __user *)arg)) + if (put_user(addr, (void **)arg)) return -EFAULT; return 0; } @@ -1045,7 +1045,7 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) free_async(as); if (ret) return ret; - if (put_user(addr, (void __user * __user *)arg)) + if (put_user(addr, (void **)arg)) return -EFAULT; return 0; } @@ -1174,7 +1174,6 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd { struct dev_state *ps = (struct dev_state *)file->private_data; struct usb_device *dev = ps->dev; - void __user *p = (void __user *)arg; int ret = -ENOTTY; if (!(file->f_mode & FMODE_WRITE)) @@ -1188,21 +1187,21 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd switch (cmd) { case USBDEVFS_CONTROL: snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); - ret = proc_control(ps, p); + ret = proc_control(ps, (void __user *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_BULK: snoop(&dev->dev, "%s: BULK\n", __FUNCTION__); - ret = proc_bulk(ps, p); + ret = proc_bulk(ps, (void __user *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESETEP: snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__); - ret = proc_resetep(ps, p); + ret = proc_resetep(ps, (void __user *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; @@ -1214,71 +1213,71 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd case USBDEVFS_CLEAR_HALT: snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__); - ret = proc_clearhalt(ps, p); + ret = proc_clearhalt(ps, (void __user *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_GETDRIVER: snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__); - ret = proc_getdriver(ps, p); + ret = proc_getdriver(ps, (void __user *)arg); break; case USBDEVFS_CONNECTINFO: snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__); - ret = proc_connectinfo(ps, p); + ret = proc_connectinfo(ps, (void __user *)arg); break; case USBDEVFS_SETINTERFACE: snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__); - ret = proc_setintf(ps, p); + ret = proc_setintf(ps, (void __user *)arg); break; case USBDEVFS_SETCONFIGURATION: snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__); - ret = proc_setconfig(ps, p); + ret = proc_setconfig(ps, (void __user *)arg); break; case USBDEVFS_SUBMITURB: snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__); - ret = proc_submiturb(ps, p); + ret = proc_submiturb(ps, (void __user *)arg); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_DISCARDURB: snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); - ret = proc_unlinkurb(ps, p); + ret = proc_unlinkurb(ps, (void __user *)arg); break; case USBDEVFS_REAPURB: snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__); - ret = proc_reapurb(ps, p); + ret = proc_reapurb(ps, (void __user *)arg); break; case USBDEVFS_REAPURBNDELAY: snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__); - ret = proc_reapurbnonblock(ps, p); + ret = proc_reapurbnonblock(ps, (void __user *)arg); break; case USBDEVFS_DISCSIGNAL: snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__); - ret = proc_disconnectsignal(ps, p); + ret = proc_disconnectsignal(ps, (void __user *)arg); break; case USBDEVFS_CLAIMINTERFACE: snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__); - ret = proc_claiminterface(ps, p); + ret = proc_claiminterface(ps, (void __user *)arg); break; case USBDEVFS_RELEASEINTERFACE: snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__); - ret = proc_releaseinterface(ps, p); + ret = proc_releaseinterface(ps, (void __user *)arg); break; case USBDEVFS_IOCTL: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); - ret = proc_ioctl(ps, p); + ret = proc_ioctl(ps, (void __user *) arg); break; } up(&dev->serialize); diff --git a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c deleted file mode 100644 index 51ff9bbd6..000000000 --- a/drivers/usb/core/driverfs.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * drivers/usb/core/driverfs.c - * - * (C) Copyright 2002 David Brownell - * (C) Copyright 2002 Greg Kroah-Hartman - * (C) Copyright 2002 IBM Corp. - * - * All of the driverfs file attributes for usb devices and interfaces. - * - */ - - -#include -#include - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif -#include - -#include "usb.h" - -/* Active configuration fields */ -#define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, char *buf) \ -{ \ - struct usb_device *udev; \ - \ - udev = to_usb_device (dev); \ - if (udev->actconfig) \ - return sprintf (buf, format_string, \ - udev->actconfig->desc.field * multiplier); \ - else \ - return 0; \ -} \ - -#define usb_actconfig_attr(field, multiplier, format_string) \ -usb_actconfig_show(field, multiplier, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") -usb_actconfig_attr (bmAttributes, 1, "%2x\n") -usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") - -/* configuration value is always present, and r/w */ -usb_actconfig_show(bConfigurationValue, 1, "%u\n"); - -static ssize_t -set_bConfigurationValue (struct device *dev, const char *buf, size_t count) -{ - struct usb_device *udev = udev = to_usb_device (dev); - int config, value; - - if (sscanf (buf, "%u", &config) != 1 || config > 255) - return -EINVAL; - down(&udev->serialize); - value = usb_set_configuration (udev, config); - up(&udev->serialize); - return (value < 0) ? value : count; -} - -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, - show_bConfigurationValue, set_bConfigurationValue); - -/* String fields */ -#define usb_string_attr(name, field) \ -static ssize_t show_##name(struct device *dev, char *buf) \ -{ \ - struct usb_device *udev; \ - int len; \ - \ - udev = to_usb_device (dev); \ - len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE); \ - if (len < 0) \ - return 0; \ - buf[len] = '\n'; \ - buf[len+1] = 0; \ - return len+1; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -usb_string_attr(product, iProduct); -usb_string_attr(manufacturer, iManufacturer); -usb_string_attr(serial, iSerialNumber); - -static ssize_t -show_speed (struct device *dev, char *buf) -{ - struct usb_device *udev; - char *speed; - - udev = to_usb_device (dev); - - switch (udev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - return sprintf (buf, "%s\n", speed); -} -static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); - -static ssize_t -show_devnum (struct device *dev, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->devnum); -} -static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); - -static ssize_t -show_version (struct device *dev, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device (dev); - return sprintf (buf, "%2x.%02x\n", udev->descriptor.bcdUSB >> 8, - udev->descriptor.bcdUSB & 0xff); -} -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); - -static ssize_t -show_maxchild (struct device *dev, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->maxchild); -} -static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); - -/* Descriptor fields */ -#define usb_descriptor_attr(field, format_string) \ -static ssize_t \ -show_##field (struct device *dev, char *buf) \ -{ \ - struct usb_device *udev; \ - \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, udev->descriptor.field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_descriptor_attr (idVendor, "%04x\n") -usb_descriptor_attr (idProduct, "%04x\n") -usb_descriptor_attr (bcdDevice, "%04x\n") -usb_descriptor_attr (bDeviceClass, "%02x\n") -usb_descriptor_attr (bDeviceSubClass, "%02x\n") -usb_descriptor_attr (bDeviceProtocol, "%02x\n") -usb_descriptor_attr (bNumConfigurations, "%d\n") - - -void usb_create_driverfs_dev_files (struct usb_device *udev) -{ - struct device *dev = &udev->dev; - - /* current configuration's attributes */ - device_create_file (dev, &dev_attr_bNumInterfaces); - device_create_file (dev, &dev_attr_bConfigurationValue); - device_create_file (dev, &dev_attr_bmAttributes); - device_create_file (dev, &dev_attr_bMaxPower); - - /* device attributes */ - device_create_file (dev, &dev_attr_idVendor); - device_create_file (dev, &dev_attr_idProduct); - device_create_file (dev, &dev_attr_bcdDevice); - device_create_file (dev, &dev_attr_bDeviceClass); - device_create_file (dev, &dev_attr_bDeviceSubClass); - device_create_file (dev, &dev_attr_bDeviceProtocol); - device_create_file (dev, &dev_attr_bNumConfigurations); - - /* speed varies depending on how you connect the device */ - device_create_file (dev, &dev_attr_speed); - // FIXME iff there are other speed configs, show how many - - if (udev->descriptor.iManufacturer) - device_create_file (dev, &dev_attr_manufacturer); - if (udev->descriptor.iProduct) - device_create_file (dev, &dev_attr_product); - if (udev->descriptor.iSerialNumber) - device_create_file (dev, &dev_attr_serial); - - device_create_file (dev, &dev_attr_devnum); - device_create_file (dev, &dev_attr_version); - device_create_file (dev, &dev_attr_maxchild); -} - -/* Interface fields */ -#define usb_intf_attr(field, format_string) \ -static ssize_t \ -show_##field (struct device *dev, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface (dev); \ - \ - return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_intf_attr (bInterfaceNumber, "%02x\n") -usb_intf_attr (bAlternateSetting, "%2d\n") -usb_intf_attr (bNumEndpoints, "%02x\n") -usb_intf_attr (bInterfaceClass, "%02x\n") -usb_intf_attr (bInterfaceSubClass, "%02x\n") -usb_intf_attr (bInterfaceProtocol, "%02x\n") -usb_intf_attr (iInterface, "%02x\n") - -void usb_create_driverfs_intf_files (struct usb_interface *intf) -{ - device_create_file (&intf->dev, &dev_attr_bInterfaceNumber); - device_create_file (&intf->dev, &dev_attr_bAlternateSetting); - device_create_file (&intf->dev, &dev_attr_bNumEndpoints); - device_create_file (&intf->dev, &dev_attr_bInterfaceClass); - device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass); - device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol); - device_create_file (&intf->dev, &dev_attr_iInterface); -} diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 38c64f656..78c5ca2f1 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -2,8 +2,8 @@ * drivers/usb/core/sysfs.c * * (C) Copyright 2002 David Brownell - * (C) Copyright 2002 Greg Kroah-Hartman - * (C) Copyright 2002 IBM Corp. + * (C) Copyright 2002,2004 Greg Kroah-Hartman + * (C) Copyright 2002,2004 IBM Corp. * * All of the sysfs file attributes for usb devices and interfaces. * @@ -162,29 +162,35 @@ usb_descriptor_attr (bDeviceSubClass, "%02x\n") usb_descriptor_attr (bDeviceProtocol, "%02x\n") usb_descriptor_attr (bNumConfigurations, "%d\n") +static struct attribute *dev_attrs[] = { + /* current configuration's attributes */ + &dev_attr_bNumInterfaces.attr, + &dev_attr_bConfigurationValue.attr, + &dev_attr_bmAttributes.attr, + &dev_attr_bMaxPower.attr, + /* device attributes */ + &dev_attr_idVendor.attr, + &dev_attr_idProduct.attr, + &dev_attr_bcdDevice.attr, + &dev_attr_bDeviceClass.attr, + &dev_attr_bDeviceSubClass.attr, + &dev_attr_bDeviceProtocol.attr, + &dev_attr_bNumConfigurations.attr, + &dev_attr_speed.attr, + &dev_attr_devnum.attr, + &dev_attr_version.attr, + &dev_attr_maxchild.attr, + NULL, +}; +static struct attribute_group dev_attr_grp = { + .attrs = dev_attrs, +}; void usb_create_sysfs_dev_files (struct usb_device *udev) { struct device *dev = &udev->dev; - /* current configuration's attributes */ - device_create_file (dev, &dev_attr_bNumInterfaces); - device_create_file (dev, &dev_attr_bConfigurationValue); - device_create_file (dev, &dev_attr_bmAttributes); - device_create_file (dev, &dev_attr_bMaxPower); - - /* device attributes */ - device_create_file (dev, &dev_attr_idVendor); - device_create_file (dev, &dev_attr_idProduct); - device_create_file (dev, &dev_attr_bcdDevice); - device_create_file (dev, &dev_attr_bDeviceClass); - device_create_file (dev, &dev_attr_bDeviceSubClass); - device_create_file (dev, &dev_attr_bDeviceProtocol); - device_create_file (dev, &dev_attr_bNumConfigurations); - - /* speed varies depending on how you connect the device */ - device_create_file (dev, &dev_attr_speed); - // FIXME iff there are other speed configs, show how many + sysfs_create_group(&dev->kobj, &dev_attr_grp); if (udev->descriptor.iManufacturer) device_create_file (dev, &dev_attr_manufacturer); @@ -192,10 +198,20 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) device_create_file (dev, &dev_attr_product); if (udev->descriptor.iSerialNumber) device_create_file (dev, &dev_attr_serial); +} + +void usb_remove_sysfs_dev_files (struct usb_device *udev) +{ + struct device *dev = &udev->dev; - device_create_file (dev, &dev_attr_devnum); - device_create_file (dev, &dev_attr_version); - device_create_file (dev, &dev_attr_maxchild); + sysfs_remove_group(&dev->kobj, &dev_attr_grp); + + if (udev->descriptor.iManufacturer) + device_remove_file(dev, &dev_attr_manufacturer); + if (udev->descriptor.iProduct) + device_remove_file(dev, &dev_attr_product); + if (udev->descriptor.iSerialNumber) + device_remove_file(dev, &dev_attr_serial); } /* Interface fields */ @@ -217,13 +233,26 @@ usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") usb_intf_attr (iInterface, "%02x\n") +static struct attribute *intf_attrs[] = { + &dev_attr_bInterfaceNumber.attr, + &dev_attr_bAlternateSetting.attr, + &dev_attr_bNumEndpoints.attr, + &dev_attr_bInterfaceClass.attr, + &dev_attr_bInterfaceSubClass.attr, + &dev_attr_bInterfaceProtocol.attr, + &dev_attr_iInterface.attr, + NULL, +}; +static struct attribute_group intf_attr_grp = { + .attrs = intf_attrs, +}; + void usb_create_sysfs_intf_files (struct usb_interface *intf) { - device_create_file (&intf->dev, &dev_attr_bInterfaceNumber); - device_create_file (&intf->dev, &dev_attr_bAlternateSetting); - device_create_file (&intf->dev, &dev_attr_bNumEndpoints); - device_create_file (&intf->dev, &dev_attr_bInterfaceClass); - device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass); - device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol); - device_create_file (&intf->dev, &dev_attr_iInterface); + sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); +} + +void usb_remove_sysfs_intf_files (struct usb_interface *intf) +{ + sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 2891eeeef..77262750f 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1651,12 +1651,12 @@ static struct net_device_stats *eth_get_stats (struct net_device *net) return &((struct eth_dev *) net->priv)->stats; } -static int eth_ethtool_ioctl (struct net_device *net, void __user *useraddr) +static int eth_ethtool_ioctl (struct net_device *net, void *useraddr) { struct eth_dev *dev = (struct eth_dev *) net->priv; u32 cmd; - if (get_user (cmd, (u32 __user *)useraddr)) + if (get_user (cmd, (u32 *)useraddr)) return -EFAULT; switch (cmd) { @@ -1694,7 +1694,7 @@ static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { switch (cmd) { case SIOCETHTOOL: - return eth_ethtool_ioctl(net, rq->ifr_data); + return eth_ethtool_ioctl (net, (void *)rq->ifr_data); default: return -EOPNOTSUPP; } diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c new file mode 100644 index 000000000..4e11a8eae --- /dev/null +++ b/drivers/usb/host/ohci-lh7a404.c @@ -0,0 +1,385 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * + * Bus Glue for Sharp LH7A404 + * + * Written by Christopher Hoover + * Based on fragments of previous driver by Rusell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta + * + * This file is licenced under the GPL. + */ + +#include +#include +#include + + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void lh7a404_start_hc(struct platform_device *dev) +{ + printk(KERN_DEBUG __FILE__ + ": starting LH7A404 OHCI USB Controller\n"); + + /* + * Now, carefully enable the USB clock, and take + * the USB host controller out of reset. + */ + CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */ + udelay(1000); + USBH_CMDSTATUS = OHCI_HCR; + + printk(KERN_DEBUG __FILE__ + ": Clock to USB host has been enabled \n"); +} + +static void lh7a404_stop_hc(struct platform_device *dev) +{ + printk(KERN_DEBUG __FILE__ + ": stopping LH7A404 OHCI USB Controller\n"); + + CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */ +} + + +/*-------------------------------------------------------------------------*/ + + +static irqreturn_t usb_hcd_lh7a404_hcim_irq (int irq, void *__hcd, + struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + + return usb_hcd_irq(irq, hcd, r); +} + +/*-------------------------------------------------------------------------*/ + +void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_lh7a404_probe - initialize LH7A404-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + */ +int usb_hcd_lh7a404_probe (const struct hc_driver *driver, + struct usb_hcd **hcd_out, + struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd = 0; + + unsigned int *addr = NULL; + + if (!request_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1, hcd_name)) { + pr_debug("request_mem_region failed"); + return -EBUSY; + } + + + lh7a404_start_hc(dev); + + addr = ioremap(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); + if (!addr) { + pr_debug("ioremap failed"); + retval = -ENOMEM; + goto err1; + } + + + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + pr_debug ("hcd_alloc failed"); + retval = -ENOMEM; + goto err1; + } + + if(dev->resource[1].flags != IORESOURCE_IRQ){ + pr_debug ("resource[1] is not IORESOURCE_IRQ"); + retval = -ENOMEM; + goto err1; + } + + hcd->driver = (struct hc_driver *) driver; + hcd->description = driver->description; + hcd->irq = dev->resource[1].start; + hcd->regs = addr; + hcd->self.controller = &dev->dev; + + retval = hcd_buffer_create (hcd); + if (retval != 0) { + pr_debug ("pool alloc fail"); + goto err1; + } + + retval = request_irq (hcd->irq, usb_hcd_lh7a404_hcim_irq, SA_INTERRUPT, + hcd->description, hcd); + if (retval != 0) { + pr_debug("request_irq failed"); + retval = -EBUSY; + goto err2; + } + + pr_debug ("%s (LH7A404) at 0x%p, irq %d", + hcd->description, hcd->regs, hcd->irq); + + usb_bus_init (&hcd->self); + hcd->self.op = &usb_hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->self.bus_name = "lh7a404"; + hcd->product_desc = "LH7A404 OHCI"; + + INIT_LIST_HEAD (&hcd->dev_list); + + usb_register_bus (&hcd->self); + + if ((retval = driver->start (hcd)) < 0) + { + usb_hcd_lh7a404_remove(hcd, dev); + return retval; + } + + *hcd_out = hcd; + return 0; + + err2: + hcd_buffer_destroy (hcd); + if (hcd) + driver->hcd_free(hcd); + err1: + lh7a404_stop_hc(dev); + release_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_lh7a404_remove - shutdown processing for LH7A404-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_lh7a404_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev) +{ + void *base; + + pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + + if (in_interrupt ()) + BUG (); + + hcd->state = USB_STATE_QUIESCING; + + pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name); + usb_disconnect (&hcd->self.root_hub); + + hcd->driver->stop (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + hcd_buffer_destroy (hcd); + + usb_deregister_bus (&hcd->self); + + base = hcd->regs; + hcd->driver->hcd_free (hcd); + + lh7a404_stop_hc(dev); + release_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_lh7a404_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci); + + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); + if (!ohci->hcca) + return -ENOMEM; + + ohci_dbg (ohci, "ohci_lh7a404_start, ohci->hcca:%p", + ohci->hcca); + + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + + if ((ret = ohci_mem_init (ohci)) < 0) { + ohci_stop (hcd); + return ret; + } + ohci->regs = hcd->regs; + + if (hc_reset (ohci) < 0) { + ohci_stop (hcd); + return -ENODEV; + } + + if (hc_start (ohci) < 0) { + err ("can't start %s", ohci->hcd.self.bus_name); + ohci_stop (hcd); + return -EBUSY; + } + create_debug_files (ohci); + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif /*DEBUG*/ + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_lh7a404_hc_driver = { + .description = hcd_name, + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_lh7a404_start, +#ifdef CONFIG_PM + /* suspend: ohci_lh7a404_suspend, -- tbd */ + /* resume: ohci_lh7a404_resume, -- tbd */ +#endif /*CONFIG_PM*/ + .stop = ohci_stop, + + /* + * memory lifecycle (except per-request) + */ + .hcd_alloc = ohci_hcd_alloc, + .hcd_free = ohci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_lh7a404_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = NULL; + int ret; + + pr_debug ("In ohci_hcd_lh7a404_drv_probe"); + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, &hcd, pdev); + + if (ret == 0) + dev_set_drvdata(dev, hcd); + + return ret; +} + +static int ohci_hcd_lh7a404_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + usb_hcd_lh7a404_remove(hcd, pdev); + dev_set_drvdata(dev, NULL); + return 0; +} + /*TBD*/ +/*static int ohci_hcd_lh7a404_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +static int ohci_hcd_lh7a404_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + + return 0; +} +*/ + +static struct device_driver ohci_hcd_lh7a404_driver = { + .name = "lh7a404-ohci", + .bus = &platform_bus_type, + .probe = ohci_hcd_lh7a404_drv_probe, + .remove = ohci_hcd_lh7a404_drv_remove, + /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ + /*.resume = ohci_hcd_lh7a404_drv_resume, */ +}; + +static int __init ohci_hcd_lh7a404_init (void) +{ + pr_debug (DRIVER_INFO " (LH7A404)"); + pr_debug ("block sizes: ed %d td %d\n", + sizeof (struct ed), sizeof (struct td)); + + return driver_register(&ohci_hcd_lh7a404_driver); +} + +static void __exit ohci_hcd_lh7a404_cleanup (void) +{ + driver_unregister(&ohci_hcd_lh7a404_driver); +} + +module_init (ohci_hcd_lh7a404_init); +module_exit (ohci_hcd_lh7a404_cleanup); diff --git a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c index aea703bed..4d503a20b 100644 --- a/drivers/usb/media/pwc-if.c +++ b/drivers/usb/media/pwc-if.c @@ -129,6 +129,7 @@ static struct { static int pwc_video_open(struct inode *inode, struct file *file); static int pwc_video_close(struct inode *inode, struct file *file); +static int pwc_video_release(struct video_device *); static ssize_t pwc_video_read(struct file *file, char *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); @@ -1120,6 +1121,12 @@ static int pwc_video_close(struct inode *inode, struct file *file) return 0; } +static int pwc_video_release(struct video_device *vfd) +{ + Trace(TRACE_OPEN, "pwc_video_release() called. Now what?\n"); +} + + /* * FIXME: what about two parallel reads ???? * ANSWER: Not supported. You can't open the device more than once, @@ -1848,7 +1855,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } } - pdev->vdev.release = video_device_release; + pdev->vdev.release = pwc_video_release; i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { Err("Failed to register as video device (%d).\n", i); diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index f81bf5987..eb257e55a 100644 --- a/drivers/usb/media/w9968cf.c +++ b/drivers/usb/media/w9968cf.c @@ -2915,7 +2915,7 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, void* arg) { struct w9968cf_device* cam; - const char* v4l1_ioctls[] = { + static const char* v4l1_ioctls[] = { "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", @@ -2923,6 +2923,8 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", "GVBIFMT", "SVBIFMT" }; + struct video_tuner tuner; + struct video_channel chan; #define V4L1_IOCTL(cmd) \ ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \ @@ -2957,7 +2959,6 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, case VIDIOCGCHAN: /* get video channel informations */ { - struct video_channel chan; if (copy_from_user(&chan, arg, sizeof(chan))) return -EFAULT; @@ -2979,8 +2980,6 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, case VIDIOCSCHAN: /* set active channel */ { - struct video_channel chan; - if (copy_from_user(&chan, arg, sizeof(chan))) return -EFAULT; @@ -3369,7 +3368,6 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, case VIDIOCGTUNER: { - struct video_tuner tuner; if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; @@ -3392,7 +3390,6 @@ w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, case VIDIOCSTUNER: { - struct video_tuner tuner; if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index 9018774ae..b89b53401 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -17,6 +17,10 @@ * * CAUTION: Generally you should use 0 < degrees < 180 as anything else * is probably beyond the range of your servo and may damage it. + * + * Jun 16, 2004: Sean Young + * - cleanups + * - was using memory after kfree() */ #include @@ -33,19 +37,36 @@ #define DRIVER_AUTHOR "Sean Young " #define DRIVER_DESC "USB PhidgetServo Driver" -#define VENDOR_ID_GLAB 0x06c2 -#define DEVICE_ID_4MOTOR_SERVO_30 0x0038 -#define DEVICE_ID_1MOTOR_SERVO_30 0x0039 +#define VENDOR_ID_GLAB 0x06c2 +#define DEVICE_ID_GLAB_PHIDGETSERVO_QUAD 0x0038 +#define DEVICE_ID_GLAB_PHIDGETSERVO_UNI 0x0039 + +#define VENDOR_ID_WISEGROUP 0x0925 +#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD 0x8101 +#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI 0x8104 -#define VENDOR_ID_WISEGROUP 0x0925 -#define DEVICE_ID_1MOTOR_SERVO_20 0x8101 -#define DEVICE_ID_4MOTOR_SERVO_20 0x8104 +#define SERVO_VERSION_30 0x01 +#define SERVO_COUNT_QUAD 0x02 static struct usb_device_id id_table[] = { - {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_4MOTOR_SERVO_30)}, - {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_1MOTOR_SERVO_30)}, - {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_4MOTOR_SERVO_20)}, - {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_1MOTOR_SERVO_20)}, + { + USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_QUAD), + .driver_info = SERVO_VERSION_30 | SERVO_COUNT_QUAD + }, + { + USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_UNI), + .driver_info = SERVO_VERSION_30 + }, + { + USB_DEVICE(VENDOR_ID_WISEGROUP, + VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD), + .driver_info = SERVO_COUNT_QUAD + }, + { + USB_DEVICE(VENDOR_ID_WISEGROUP, + VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI), + .driver_info = 0 + }, {} }; @@ -53,14 +74,13 @@ MODULE_DEVICE_TABLE(usb, id_table); struct phidget_servo { struct usb_device *udev; - int version; - int quad_servo; + ulong type; int pulse[4]; int degrees[4]; int minutes[4]; }; -static void +static int change_position_v30(struct phidget_servo *servo, int servo_no, int degrees, int minutes) { @@ -71,7 +91,7 @@ change_position_v30(struct phidget_servo *servo, int servo_no, int degrees, if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", __FUNCTION__); - return; + return -ENOMEM; } /* @@ -124,12 +144,13 @@ change_position_v30(struct phidget_servo *servo, int servo_no, int degrees, retval = usb_control_msg(servo->udev, usb_sndctrlpipe(servo->udev, 0), 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2 * HZ); - if (retval != 6) - dev_err(&servo->udev->dev, "retval = %d\n", retval); + kfree(buffer); + + return retval; } -static void +static int change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, int minutes) { @@ -140,7 +161,7 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, if (!buffer) { dev_err(&servo->udev->dev, "%s - out of memory\n", __FUNCTION__); - return; + return -ENOMEM; } /* @@ -171,16 +192,17 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, retval = usb_control_msg(servo->udev, usb_sndctrlpipe(servo->udev, 0), 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2 * HZ); - if (retval != 2) - dev_err(&servo->udev->dev, "retval = %d\n", retval); + kfree(buffer); + + return retval; } #define show_set(value) \ static ssize_t set_servo##value (struct device *dev, \ const char *buf, size_t count) \ { \ - int degrees, minutes; \ + int degrees, minutes, retval; \ struct usb_interface *intf = to_usb_interface (dev); \ struct phidget_servo *servo = usb_get_intfdata (intf); \ \ @@ -195,12 +217,14 @@ static ssize_t set_servo##value (struct device *dev, \ return -EINVAL; \ } \ \ - if (servo->version >= 3) \ - change_position_v30 (servo, value, degrees, minutes); \ + if (servo->type & SERVO_VERSION_30) \ + retval = change_position_v30 (servo, value, degrees, \ + minutes); \ else \ - change_position_v20 (servo, value, degrees, minutes); \ + retval = change_position_v20 (servo, value, degrees, \ + minutes); \ \ - return count; \ + return retval < 0 ? retval : count; \ } \ \ static ssize_t show_servo##value (struct device *dev, char *buf) \ @@ -223,7 +247,7 @@ static int servo_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); - struct phidget_servo *dev = NULL; + struct phidget_servo *dev; dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL); if (dev == NULL) { @@ -233,37 +257,21 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id) memset(dev, 0x00, sizeof (*dev)); dev->udev = usb_get_dev(udev); - switch (udev->descriptor.idVendor) { - case VENDOR_ID_WISEGROUP: - dev->version = 2; - break; - case VENDOR_ID_GLAB: - dev->version = 3; - break; - } - switch (udev->descriptor.idProduct) { - case DEVICE_ID_4MOTOR_SERVO_20: - case DEVICE_ID_4MOTOR_SERVO_30: - dev->quad_servo = 1; - break; - case DEVICE_ID_1MOTOR_SERVO_20: - case DEVICE_ID_1MOTOR_SERVO_30: - dev->quad_servo = 0; - break; - } - + dev->type = id->driver_info; usb_set_intfdata(interface, dev); device_create_file(&interface->dev, &dev_attr_servo0); - if (dev->quad_servo) { + if (dev->type & SERVO_COUNT_QUAD) { device_create_file(&interface->dev, &dev_attr_servo1); device_create_file(&interface->dev, &dev_attr_servo2); device_create_file(&interface->dev, &dev_attr_servo3); } dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n", - dev->quad_servo ? 4 : 1, dev->version); - if (dev->version == 2) + dev->type & SERVO_COUNT_QUAD ? 4 : 1, + dev->type & SERVO_VERSION_30 ? 3 : 2); + + if(!(dev->type & SERVO_VERSION_30)) dev_info(&interface->dev, "WARNING: v2.0 not tested! Please report if it works.\n"); @@ -279,7 +287,7 @@ servo_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); device_remove_file(&interface->dev, &dev_attr_servo0); - if (dev->quad_servo) { + if (dev->type & SERVO_COUNT_QUAD) { device_remove_file(&interface->dev, &dev_attr_servo1); device_remove_file(&interface->dev, &dev_attr_servo2); device_remove_file(&interface->dev, &dev_attr_servo3); @@ -287,10 +295,11 @@ servo_disconnect(struct usb_interface *interface) usb_put_dev(dev->udev); - kfree(dev); - dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n", - dev->quad_servo ? 4 : 1, dev->version); + dev->type & SERVO_COUNT_QUAD ? 4 : 1, + dev->type & SERVO_VERSION_30 ? 3 : 2); + + kfree(dev); } static struct usb_driver servo_driver = { @@ -304,7 +313,7 @@ static struct usb_driver servo_driver = { static int __init phidget_servo_init(void) { - int retval = 0; + int retval; retval = usb_register(&servo_driver); if (retval) diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 42a248f8f..d61d7d7de 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -737,7 +737,7 @@ static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { switch (cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(net, rq->ifr_data); + return netdev_ethtool_ioctl(net, (void __user *)rq->ifr_data); } return -EOPNOTSUPP; } diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 5142d8a07..917482501 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1030,7 +1030,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void __user *uaddr) int cmd; pegasus = net->priv; - if (get_user(cmd, (int __user *) uaddr)) + if (get_user(cmd, (int *) uaddr)) return -EFAULT; switch (cmd) { case ETHTOOL_GDRVINFO:{ @@ -1107,13 +1107,13 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void __user *uaddr) #endif static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { - __u16 *data = (__u16 *) & rq->ifr_ifru; + __u16 *data = (__u16 *) & rq->ifr_data; pegasus_t *pegasus = net->priv; int res; switch (cmd) { case SIOCETHTOOL: - res = pegasus_ethtool_ioctl(net, rq->ifr_data); + res = pegasus_ethtool_ioctl(net, (void __user *)rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = pegasus->phy; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 2be3eba6b..52592ef1d 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -776,13 +776,13 @@ static int rtl8150_close(struct net_device *netdev) return res; } -static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr) +static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) { rtl8150_t *dev; int cmd; dev = netdev->priv; - if (get_user(cmd, (int __user *) uaddr)) + if (get_user(cmd, (int *) uaddr)) return -EFAULT; switch (cmd) { @@ -856,7 +856,7 @@ static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) int res; dev = netdev->priv; - data = (u16 *) & rq->ifr_ifru; + data = (u16 *) & rq->ifr_data; res = 0; switch (cmd) { diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 557edde67..e2e328f33 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -2668,7 +2668,9 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) struct usbnet *dev = (struct usbnet *)net->priv; if (dev->mii.mdio_read != NULL && dev->mii.mdio_write != NULL) - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); + return generic_mii_ioctl(&dev->mii, + (struct mii_ioctl_data *) &rq->ifr_data, + cmd, NULL); } #endif return -EOPNOTSUPP; diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 9ca40acd3..299daca1f 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -109,7 +109,7 @@ struct cyberjack_private { short rdtodo; /* Bytes still to read */ unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ short wrfilled; /* Overall data size we already got */ - short wrsent; /* Data already sent */ + short wrsent; /* Data akready sent */ }; /* do some startup allocations not currently performed by usb_serial_probe() */ @@ -159,6 +159,8 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp) dbg("%s - usb_clear_halt", __FUNCTION__ ); usb_clear_halt(port->serial->dev, port->write_urb->pipe); + usb_clear_halt(port->serial->dev, port->read_urb->pipe); + usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe); /* force low_latency on so that our tty_push actually forces * the data through, otherwise it is scheduled, and with high @@ -210,6 +212,7 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u unsigned long flags; int result; int wrexpected; + unsigned char localbuf[CYBERJACK_LOCAL_BUF_SIZE]; /* Buffer for collecting data to write */ dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - from_user %d", __FUNCTION__, from_user); @@ -226,23 +229,29 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u spin_lock_irqsave(&priv->lock, flags); - if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) { - /* To much data for buffer. Reset buffer. */ + if( (count+priv->wrfilled)>sizeof(priv->wrbuf) || + (count>sizeof(localbuf)) ) { + /* To much data for buffer. Reset buffer. */ priv->wrfilled=0; spin_unlock_irqrestore(&priv->lock, flags); return (0); } + spin_unlock_irqrestore(&priv->lock, flags); + /* Copy data */ if (from_user) { - if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) { - spin_unlock_irqrestore(&priv->lock, flags); + if (copy_from_user(localbuf, buf, count)) { return -EFAULT; } } else { - memcpy (priv->wrbuf+priv->wrfilled, buf, count); + memcpy (localbuf, buf, count); } + spin_lock_irqsave(&priv->lock, flags); + + memcpy (priv->wrbuf+priv->wrfilled, localbuf, count); + usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->wrbuf+priv->wrfilled); priv->wrfilled += count; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index ca3be781e..f903d3969 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -398,7 +398,7 @@ struct scsi_host_template usb_stor_host_template = { .sg_tablesize = SG_ALL, /* limit the total size of a transfer to 120 KB */ - .max_sectors = 240, + .max_sectors = 256, /* merge commands... this seems to help performance, but * periodically someone should test to see which setting is more diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index d88079eb9..7ec775681 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -1398,19 +1398,23 @@ int radeonfb_set_par(struct fb_info *info) { struct radeonfb_info *rinfo = info->par; struct fb_var_screeninfo *mode = &info->var; - struct radeon_regs newmode; + struct radeon_regs *newmode; int hTotal, vTotal, hSyncStart, hSyncEnd, hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock; int i, freq; - int format = 0; + int format = 0; int nopllcalc = 0; int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); int depth = var_to_depth(mode); + newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); + if (!newmode) + return -ENOMEM; + /* We always want engine to be idle on a mode switch, even * if we won't actually change the mode */ @@ -1450,9 +1454,9 @@ int radeonfb_set_par(struct fb_info *info) if (rinfo->panel_info.use_bios_dividers) { nopllcalc = 1; - newmode.ppll_div_3 = rinfo->panel_info.fbk_divider | + newmode->ppll_div_3 = rinfo->panel_info.fbk_divider | (rinfo->panel_info.post_divider << 16); - newmode.ppll_ref_div = rinfo->panel_info.ref_divider; + newmode->ppll_ref_div = rinfo->panel_info.ref_divider; } } dotClock = 1000000000 / pixClock; @@ -1490,38 +1494,38 @@ int radeonfb_set_par(struct fb_info *info) hsync_start = hSyncStart - 8 + hsync_fudge; - newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | + newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | (format << 8); /* Clear auto-center etc... */ - newmode.crtc_more_cntl = rinfo->init_state.crtc_more_cntl; - newmode.crtc_more_cntl &= 0xfffffff0; + newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl; + newmode->crtc_more_cntl &= 0xfffffff0; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { - newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; + newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; if (mirror) - newmode.crtc_ext_cntl |= CRTC_CRT_ON; + newmode->crtc_ext_cntl |= CRTC_CRT_ON; - newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | + newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN); } else { - newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | + newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON; } - newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | + newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN; - newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | + newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); - newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | + newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23)); - newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) | + newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | ((mode->yres - 1) << 16); - newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | + newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); if (!radeon_accel_disabled()) { @@ -1530,18 +1534,18 @@ int radeonfb_set_par(struct fb_info *info) & ~(0x3f)) >> 6; /* Then, re-multiply it to get the CRTC pitch */ - newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); } else - newmode.crtc_pitch = (mode->xres_virtual >> 3); + newmode->crtc_pitch = (mode->xres_virtual >> 3); - newmode.crtc_pitch |= (newmode.crtc_pitch << 16); + newmode->crtc_pitch |= (newmode->crtc_pitch << 16); /* * It looks like recent chips have a problem with SURFACE_CNTL, * setting SURF_TRANSLATION_DIS completely disables the * swapper as well, so we leave it unset now. */ - newmode.surface_cntl = 0; + newmode->surface_cntl = 0; #if defined(__BIG_ENDIAN) @@ -1551,28 +1555,28 @@ int radeonfb_set_par(struct fb_info *info) */ switch (mode->bits_per_pixel) { case 16: - newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP; - newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP; + newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP; + newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP; break; case 24: case 32: - newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP; - newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP; + newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP; + newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP; break; } #endif /* Clear surface registers */ for (i=0; i<8; i++) { - newmode.surf_lower_bound[i] = 0; - newmode.surf_upper_bound[i] = 0x1f; - newmode.surf_info[i] = 0; + newmode->surf_lower_bound[i] = 0; + newmode->surf_upper_bound[i] = 0x1f; + newmode->surf_info[i] = 0; } RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", - newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid); + newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", - newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid); + newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); rinfo->bpp = mode->bits_per_pixel; rinfo->depth = depth; @@ -1581,9 +1585,9 @@ int radeonfb_set_par(struct fb_info *info) RTRACE("freq = %lu\n", (unsigned long)freq); if (!nopllcalc) - radeon_calc_pll_regs(rinfo, &newmode, freq); + radeon_calc_pll_regs(rinfo, newmode, freq); - newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; + newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { unsigned int hRatio, vRatio; @@ -1593,35 +1597,35 @@ int radeonfb_set_par(struct fb_info *info) if (mode->yres > rinfo->panel_info.yres) mode->yres = rinfo->panel_info.yres; - newmode.fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) + newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) << HORZ_PANEL_SHIFT); - newmode.fp_vert_stretch = ((rinfo->panel_info.yres - 1) + newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1) << VERT_PANEL_SHIFT); if (mode->xres != rinfo->panel_info.xres) { hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, rinfo->panel_info.xres); - newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | - (newmode.fp_horz_stretch & + newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | + (newmode->fp_horz_stretch & (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | HORZ_AUTO_RATIO_INC))); - newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND | + newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND | HORZ_STRETCH_ENABLE); } - newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO; + newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO; if (mode->yres != rinfo->panel_info.yres) { vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, rinfo->panel_info.yres); - newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | - (newmode.fp_vert_stretch & + newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | + (newmode->fp_vert_stretch & (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); - newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND | + newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND | VERT_STRETCH_ENABLE); } - newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; + newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; - newmode.fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) + newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) ~(FP_SEL_CRTC2 | FP_RMX_HVSYNC_CONTROL_EN | FP_DFP_SYNC_SEL | @@ -1631,46 +1635,46 @@ int radeonfb_set_par(struct fb_info *info) FP_CRTC_USE_SHADOW_VEND | FP_CRT_SYNC_ALT)); - newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | + newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | FP_CRTC_DONT_SHADOW_HEND); - newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; - newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; - newmode.tmds_crc = rinfo->init_state.tmds_crc; - newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; + newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; + newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; + newmode->tmds_crc = rinfo->init_state.tmds_crc; + newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; if (primary_mon == MT_LCD) { - newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); - newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); + newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); + newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); } else { /* DFP */ - newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); - newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) & + newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); + newmode->tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) & ~(TMDS_PLLRST); /* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */ if ((rinfo->family == CHIP_FAMILY_R300) || (rinfo->family == CHIP_FAMILY_R350) || (rinfo->family == CHIP_FAMILY_RV350) || (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2) - newmode.tmds_transmitter_cntl &= ~TMDS_PLL_EN; + newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN; else - newmode.tmds_transmitter_cntl |= TMDS_PLL_EN; - newmode.crtc_ext_cntl &= ~CRTC_CRT_ON; + newmode->tmds_transmitter_cntl |= TMDS_PLL_EN; + newmode->crtc_ext_cntl &= ~CRTC_CRT_ON; } - newmode.fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) | + newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); - newmode.fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) | + newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) | ((mode->yres - 1) << 16); - newmode.fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) | + newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23)); - newmode.fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) | + newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); } /* do it! */ if (!rinfo->asleep) { - radeon_write_mode (rinfo, &newmode); + radeon_write_mode (rinfo, newmode); /* (re)initialize the engine */ if (!radeon_accel_disabled()) radeonfb_engine_init (rinfo); @@ -1691,6 +1695,7 @@ int radeonfb_set_par(struct fb_info *info) rinfo->depth, info->fix.line_length); #endif + kfree(newmode); return 0; } diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index bfa3f8b58..7ded3f7c9 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -109,10 +108,13 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int val, ret = 1; if (regno < fbi->palette_size) { - val = ((red >> 0) & 0xf800); - val |= ((green >> 5) & 0x07e0); - val |= ((blue >> 11) & 0x001f); - + if (fbi->fb.var.grayscale) { + val = ((blue >> 8) & 0x00ff); + } else { + val = ((red >> 0) & 0xf800); + val |= ((green >> 5) & 0x07e0); + val |= ((blue >> 11) & 0x001f); + } fbi->palette_cpu[regno] = val; ret = 0; } @@ -150,7 +152,7 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, switch (fbi->fb.fix.visual) { case FB_VISUAL_TRUECOLOR: /* - * 12 or 16-bit True Colour. We encode the RGB value + * 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < 16) { @@ -242,7 +244,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) * The pixel packing format is described on page 7-11 of the * PXA2XX Developer's Manual. */ - if ( var->bits_per_pixel == 16 ) { + if (var->bits_per_pixel == 16) { var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; @@ -297,7 +299,10 @@ static int pxafb_set_par(struct fb_info *info) fbi->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; - fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; + if (var->bits_per_pixel == 16) + fbi->palette_size = 0; + else + fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; palette_mem_size = fbi->palette_size * sizeof(u16); @@ -311,6 +316,11 @@ static int pxafb_set_par(struct fb_info *info) */ pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); + if (fbi->fb.var.bits_per_pixel == 16) + fb_dealloc_cmap(&fbi->fb.cmap); + else + fb_alloc_cmap(&fbi->fb.cmap, 1<fb.var.bits_per_pixel, 0); + pxafb_activate_var(var, fbi); return 0; @@ -349,7 +359,7 @@ static int pxafb_set_par(struct fb_info *info) /* * pxafb_blank(): * Blank the display by setting all palette values to zero. Note, the - * 12 and 16 bpp modes don't really use the palette, so this will not + * 16 bpp mode does not really use the palette, so this will not * blank the display in all modes. */ static int pxafb_blank(int blank, struct fb_info *info) @@ -514,7 +524,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * * the YRES parameter. */ lines_per_panel = var->yres; - if (fbi->lccr0 & LCCR0_SDS) + if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) lines_per_panel /= 2; new_regs.lccr2 = @@ -566,20 +576,16 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * fbi->dmadesc_palette_cpu->fidr = 0; fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; - if( var->bits_per_pixel < 12) - { - /* assume any mode with <12 bpp is palette driven */ - fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; - fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; - fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ - } - else - { + if (var->bits_per_pixel == 16) { /* palette shouldn't be loaded in true-color mode */ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ /* init it to something, even though we won't be using it */ fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma; + } else { + fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; + fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; + fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ } #if 0 @@ -696,7 +702,7 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi) } else { - printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); + printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); } } @@ -1123,11 +1129,11 @@ static int __init pxafb_parse_options(struct device *dev, char *options) res_specified = 1; } done: - if ( res_specified ) { - dev_info(dev, "overriding resolution: %dx%x\n", xres, yres); + if (res_specified) { + dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); inf->xres = xres; inf->yres = yres; } - if ( bpp_specified ) + if (bpp_specified) switch (bpp) { case 1: case 2: @@ -1142,7 +1148,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options) } } else if (!strncmp(this_opt, "pixclock:", 9)) { inf->pixclock = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override pixclock: %u\n", inf->pixclock); + dev_info(dev, "override pixclock: %ld\n", inf->pixclock); } else if (!strncmp(this_opt, "left:", 5)) { inf->left_margin = simple_strtoul(this_opt+5, NULL, 0); dev_info(dev, "override left: %u\n", inf->left_margin); @@ -1162,7 +1168,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options) inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0); dev_info(dev, "override vsynclen: %u\n", inf->vsync_len); } else if (!strncmp(this_opt, "hsync:", 6)) { - if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { dev_info(dev, "override hsync: Active Low\n"); inf->sync &= ~FB_SYNC_HOR_HIGH_ACT; } else { @@ -1170,7 +1176,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options) inf->sync |= FB_SYNC_HOR_HIGH_ACT; } } else if (!strncmp(this_opt, "vsync:", 6)) { - if ( simple_strtoul(this_opt+6, NULL, 0) == 0 ) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { dev_info(dev, "override vsync: Active Low\n"); inf->sync &= ~FB_SYNC_VERT_HIGH_ACT; } else { @@ -1178,7 +1184,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options) inf->sync |= FB_SYNC_VERT_HIGH_ACT; } } else if (!strncmp(this_opt, "dpc:", 4)) { - if ( simple_strtoul(this_opt+4, NULL, 0) == 0 ) { + if (simple_strtoul(this_opt+4, NULL, 0) == 0) { dev_info(dev, "override double pixel clock: false\n"); inf->lccr3 &= ~LCCR3_DPC; } else { @@ -1186,20 +1192,20 @@ static int __init pxafb_parse_options(struct device *dev, char *options) inf->lccr3 |= LCCR3_DPC; } } else if (!strncmp(this_opt, "outputen:", 9)) { - if ( simple_strtoul(this_opt+9, NULL, 0) == 0 ) { + if (simple_strtoul(this_opt+9, NULL, 0) == 0) { dev_info(dev, "override output enable: active low\n"); - inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnL; + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL; } else { dev_info(dev, "override output enable: active high\n"); - inf->lccr3 = ( inf->lccr3 & ~LCCR3_OEP ) | LCCR3_OutEnH; + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH; } } else if (!strncmp(this_opt, "pixclockpol:", 12)) { - if ( simple_strtoul(this_opt+12, NULL, 0) == 0 ) { + if (simple_strtoul(this_opt+12, NULL, 0) == 0) { dev_info(dev, "override pixel clock polarity: falling edge\n"); - inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixFlEdg; + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg; } else { dev_info(dev, "override pixel clock polarity: rising edge\n"); - inf->lccr3 = ( inf->lccr3 & ~LCCR3_PCP ) | LCCR3_PixRsEdg; + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg; } } else if (!strncmp(this_opt, "color", 5)) { inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color; @@ -1244,7 +1250,7 @@ int __init pxafb_probe(struct device *dev) #ifdef CONFIG_FB_PXA_PARAMETERS ret = pxafb_parse_options(dev, g_options); - if ( ret < 0 ) + if (ret < 0) goto failed; #endif @@ -1252,23 +1258,23 @@ int __init pxafb_probe(struct device *dev) /* Check for various illegal bit-combinations. Currently only * a warning is given. */ - if ( inf->lccr0 & LCCR0_INVALID_CONFIG_MASK ) + if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n", inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); - if ( inf->lccr3 & LCCR3_INVALID_CONFIG_MASK ) + if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n", inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); - if ( inf->lccr0 & LCCR0_DPD && - ( ( inf->lccr0 & LCCR0_PAS ) != LCCR0_Pas || - ( inf->lccr0 & LCCR0_SDS ) != LCCR0_Sngl || - ( inf->lccr0 & LCCR0_CMS ) != LCCR0_Mono ) ) + if (inf->lccr0 & LCCR0_DPD && + ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || + (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || + (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono" " single panel mode\n"); - if ( (inf->lccr0 & LCCR0_PAS) == LCCR0_Act && - ( inf->lccr0 & LCCR0_SDS ) == LCCR0_Dual ) + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && + (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) dev_warn(dev, "Dual panel only valid in passive mode\n"); - if ( (inf->lccr0 & LCCR0_PAS ) == LCCR0_Pas && - (inf->upper_margin || inf->lower_margin) ) + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && + (inf->upper_margin || inf->lower_margin)) dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n"); #endif diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 1df67bcbc..1dc6e9555 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1620,27 +1620,14 @@ static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) struct riva_par *par = (struct riva_par *) info->par; struct device_node *dp; unsigned char *pedid = NULL; - unsigned char *disptype = NULL; - static char *propnames[] = { - "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; - int i; dp = pci_device_to_OF_node(pd); - for (; dp != NULL; dp = dp->child) { - disptype = (unsigned char *)get_property(dp, "display-type", NULL); - if (disptype == NULL) - continue; - if (strncmp(disptype, "LCD", 3) != 0) - continue; - for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) - get_property(dp, propnames[i], NULL); - if (pedid != NULL) { + pedid = (unsigned char *)get_property(dp, "EDID,B", 0); + + if (pedid) { par->EDID = pedid; return 1; - } - } - } + } else return 0; } #endif /* CONFIG_PPC_OF */ diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c new file mode 100644 index 000000000..a8dbc252d --- /dev/null +++ b/drivers/video/riva/rivafb-i2c.c @@ -0,0 +1,209 @@ +/* + * linux/drivers/video/riva/fbdev-i2c.c - nVidia i2c + * + * Maintained by Ani Joshi + * + * Copyright 2004 Antonino A. Daplas + * + * Based on radeonfb-i2c.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rivafb.h" +#include "../edid.h" + +#define RIVA_DDC 0x50 + +static void riva_gpio_setscl(void* data, int state) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x20; + else + val &= ~0x20; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1); +} + +static void riva_gpio_setsda(void* data, int state) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0; + + if (state) + val |= 0x10; + else + val &= ~0x10; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1); + VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1); +} + +static int riva_gpio_getscl(void* data) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) + val = 1; + + val = VGA_RD08(par->riva.PCIO, 0x3d5); + + return val; +} + +static int riva_gpio_getsda(void* data) +{ + struct riva_i2c_chan *chan = (struct riva_i2c_chan *)data; + struct riva_par *par = chan->par; + u32 val = 0; + + VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base); + if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x08) + val = 1; + + return val; +} + +#define I2C_ALGO_RIVA 0x0e0000 +static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_RIVA; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pdev->dev; + chan->algo.setsda = riva_gpio_setsda; + chan->algo.setscl = riva_gpio_setscl; + chan->algo.getsda = riva_gpio_getsda; + chan->algo.getscl = riva_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + riva_gpio_setsda(chan, 1); + riva_gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + dev_dbg(&chan->par->pdev->dev, "I2C bus %s registered.\n", name); + else + dev_warn(&chan->par->pdev->dev, "Failed to register I2C bus %s.\n", name); + return rc; +} + +void riva_create_i2c_busses(struct riva_par *par) +{ + par->chan[0].par = par; + par->chan[1].par = par; + par->chan[2].par = par; + + switch (par->riva.Architecture) { +#if 0 /* no support yet for other nVidia chipsets */ + par->chan[2].ddc_base = 0x50; + riva_setup_i2c_bus(&par->chan[2], "BUS2"); +#endif + case NV_ARCH_10: + case NV_ARCH_20: + case NV_ARCH_04: + par->chan[1].ddc_base = 0x36; + riva_setup_i2c_bus(&par->chan[1], "BUS1"); + case NV_ARCH_03: + par->chan[0].ddc_base = 0x3e; + riva_setup_i2c_bus(&par->chan[0], "BUS0"); + } +} + +void riva_delete_i2c_busses(struct riva_par *par) +{ + if (par->chan[0].par) + i2c_bit_del_bus(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_bit_del_bus(&par->chan[1].adapter); + par->chan[1].par = NULL; + +} + +static u8 *riva_do_probe_i2c_edid(struct riva_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = RIVA_DDC, + .len = 1, + .buf = &start, + }, { + .addr = RIVA_DDC, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + dev_warn(&chan->par->pdev->dev, "Out of memory!\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) + return buf; + dev_dbg(&chan->par->pdev->dev, "Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid) +{ + u8 *edid = NULL; + int i; + + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = riva_do_probe_i2c_edid(&par->chan[conn-1]); + if (edid) + break; + } + if (out_edid) + *out_edid = edid; + if (!edid) + return 1; + + return 0; +} + diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index bdcc8ecef..820769e1b 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1372,6 +1372,8 @@ int __init vga16fb_init(void) vga16fb.par = &vga16_par; vga16fb.flags = FBINFO_FLAG_DEFAULT; + vga16fb.fix.smem_start = VGA_MAP_MEM(vga16fb.fix.smem_start); + i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16; ret = fb_alloc_cmap(&vga16fb.cmap, i, 0); if (ret) { diff --git a/fs/Kconfig b/fs/Kconfig index 27c901867..141007e3e 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -946,6 +946,56 @@ config RAMFS To compile this as a module, choose M here: the module will be called ramfs. +config RELAYFS_FS + tristate "Relayfs file system support" + ---help--- + Relayfs is a high-speed data relay filesystem designed to provide + an efficient mechanism for tools and facilities to relay large + amounts of data from kernel space to user space. It's not useful + on its own, and should only be enabled if other facilities that + need it are enabled, such as for example klog or the Linux Trace + Toolkit. + + See for further + information. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called relayfs. If you want to compile it as a + module, say M here and read . + + If unsure, say N. + +config KLOG_CHANNEL + bool "Enable klog debugging support" + depends on RELAYFS_FS + help + If you say Y to this, a relayfs channel named klog will be created + in the root of the relayfs file system. You can write to the klog + channel using klog() or klog_raw() from within the kernel or + kernel modules, and read from the klog channel by mounting relayfs + and using read(2) to read from it (or using cat). If you're not + sure, say N. + +config KLOG_CHANNEL_AUTOENABLE + bool "Enable klog logging on startup" + depends on KLOG_CHANNEL + default y + help + If you say Y to this, the klog channel will be automatically enabled + on startup. Otherwise, to turn klog logging on, you need use + sysctl (fs.relayfs.klog_enabled). This option is used in cases where + you don't actually want the channel to be written to until it's + enabled. If you're not sure, say Y. + +config KLOG_CHANNEL_SHIFT + depends on KLOG_CHANNEL + int "klog debugging channel size (14 => 16KB, 22 => 4MB)" + range 14 22 + default 21 + help + Select klog debugging channel size as a power of 2. + endmenu menu "Miscellaneous filesystems" @@ -1210,8 +1260,6 @@ config HPFS_FS To compile this file system support as a module, choose M here: the module will be called hpfs. If unsure, say N. - - config QNX4FS_FS tristate "QNX4 file system support (read only)" help @@ -1237,8 +1285,6 @@ config QNX4FS_RW It's currently broken, so for now: answer N. - - config SYSV_FS tristate "System V/Xenix/V7/Coherent file system support" help @@ -1275,8 +1321,6 @@ config SYSV_FS If you haven't heard about all of this before, it's safe to say N. - - config UFS_FS tristate "UFS file system support (read only)" help diff --git a/fs/Makefile b/fs/Makefile index 41cac35d1..e39e43f35 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ obj-$(CONFIG_RAMFS) += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ +obj-$(CONFIG_RELAYFS_FS) += relayfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_MINIX_FS) += minix/ obj-$(CONFIG_FAT_FS) += fat/ @@ -91,3 +92,6 @@ obj-$(CONFIG_JFS_FS) += jfs/ obj-$(CONFIG_XFS_FS) += xfs/ obj-$(CONFIG_AFS_FS) += afs/ obj-$(CONFIG_BEFS_FS) += befs/ +obj-$(CONFIG_HOSTFS) += hostfs/ +obj-$(CONFIG_HPPFS) += hppfs/ +obj-$(CONFIG_RCFS_FS) += rcfs/ diff --git a/fs/Makefile.orig b/fs/Makefile.orig new file mode 100644 index 000000000..a288c0cb3 --- /dev/null +++ b/fs/Makefile.orig @@ -0,0 +1,94 @@ +# +# Makefile for the Linux filesystems. +# +# 14 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + +obj-y := open.o read_write.o file_table.o buffer.o \ + bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \ + namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ + dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \ + filesystems.o namespace.o seq_file.o xattr.o libfs.o \ + fs-writeback.o mpage.o direct-io.o aio.o + +obj-$(CONFIG_EPOLL) += eventpoll.o +obj-$(CONFIG_COMPAT) += compat.o + +nfsd-$(CONFIG_NFSD) := nfsctl.o +obj-y += $(nfsd-y) $(nfsd-m) + +obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o +obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o + +# binfmt_script is always there +obj-y += binfmt_script.o + +obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o +obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o + +obj-$(CONFIG_FS_MBCACHE) += mbcache.o +obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o + +obj-$(CONFIG_QUOTA) += dquot.o +obj-$(CONFIG_QFMT_V1) += quota_v1.o +obj-$(CONFIG_QFMT_V2) += quota_v2.o +obj-$(CONFIG_QUOTACTL) += quota.o + +obj-$(CONFIG_PROC_FS) += proc/ +obj-y += partitions/ +obj-$(CONFIG_SYSFS) += sysfs/ +obj-y += devpts/ + +obj-$(CONFIG_PROFILING) += dcookies.o + +# Do not add any filesystems before this line +obj-$(CONFIG_REISERFS_FS) += reiserfs/ +obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 +obj-$(CONFIG_JBD) += jbd/ +obj-$(CONFIG_EXT2_FS) += ext2/ +obj-$(CONFIG_CRAMFS) += cramfs/ +obj-$(CONFIG_RAMFS) += ramfs/ +obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ +obj-$(CONFIG_CODA_FS) += coda/ +obj-$(CONFIG_INTERMEZZO_FS) += intermezzo/ +obj-$(CONFIG_MINIX_FS) += minix/ +obj-$(CONFIG_FAT_FS) += fat/ +obj-$(CONFIG_UMSDOS_FS) += umsdos/ +obj-$(CONFIG_MSDOS_FS) += msdos/ +obj-$(CONFIG_VFAT_FS) += vfat/ +obj-$(CONFIG_BFS_FS) += bfs/ +obj-$(CONFIG_ISO9660_FS) += isofs/ +obj-$(CONFIG_DEVFS_FS) += devfs/ +obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ +obj-$(CONFIG_HFS_FS) += hfs/ +obj-$(CONFIG_VXFS_FS) += freevxfs/ +obj-$(CONFIG_NFS_FS) += nfs/ +obj-$(CONFIG_EXPORTFS) += exportfs/ +obj-$(CONFIG_NFSD) += nfsd/ +obj-$(CONFIG_LOCKD) += lockd/ +obj-$(CONFIG_NLS) += nls/ +obj-$(CONFIG_SYSV_FS) += sysv/ +obj-$(CONFIG_SMB_FS) += smbfs/ +obj-$(CONFIG_CIFS) += cifs/ +obj-$(CONFIG_NCP_FS) += ncpfs/ +obj-$(CONFIG_HPFS_FS) += hpfs/ +obj-$(CONFIG_NTFS_FS) += ntfs/ +obj-$(CONFIG_UFS_FS) += ufs/ +obj-$(CONFIG_EFS_FS) += efs/ +obj-$(CONFIG_JFFS_FS) += jffs/ +obj-$(CONFIG_JFFS2_FS) += jffs2/ +obj-$(CONFIG_AFFS_FS) += affs/ +obj-$(CONFIG_ROMFS_FS) += romfs/ +obj-$(CONFIG_QNX4FS_FS) += qnx4/ +obj-$(CONFIG_AUTOFS_FS) += autofs/ +obj-$(CONFIG_AUTOFS4_FS) += autofs4/ +obj-$(CONFIG_ADFS_FS) += adfs/ +obj-$(CONFIG_UDF_FS) += udf/ +obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ +obj-$(CONFIG_JFS_FS) += jfs/ +obj-$(CONFIG_XFS_FS) += xfs/ +obj-$(CONFIG_AFS_FS) += afs/ +obj-$(CONFIG_BEFS_FS) += befs/ diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index c01cd4c64..4ef626e49 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -78,7 +78,8 @@ struct address_space_operations affs_symlink_aops = { }; struct inode_operations affs_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setattr = affs_notify_change, }; diff --git a/fs/aio.c b/fs/aio.c index 6249313ce..a2cf98648 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -15,7 +15,7 @@ #include #include -#define DEBUG 0 +//#define DEBUG 1 #include #include @@ -394,7 +394,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) req->ki_ctx = ctx; req->ki_cancel = NULL; req->ki_retry = NULL; - req->ki_obj.user = NULL; + req->ki_user_obj = NULL; /* Check if the completion queue has enough free space to * accept an event from this io. @@ -437,7 +437,7 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) { req->ki_ctx = NULL; req->ki_filp = NULL; - req->ki_obj.user = NULL; + req->ki_user_obj = NULL; kmem_cache_free(kiocb_cachep, req); ctx->reqs_active--; @@ -605,7 +605,7 @@ void fastcall kick_iocb(struct kiocb *iocb) * single context. */ if (is_sync_kiocb(iocb)) { kiocbSetKicked(iocb); - wake_up_process(iocb->ki_obj.tsk); + wake_up_process(iocb->ki_user_obj); return; } @@ -653,7 +653,7 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) spin_unlock_irq(&ctx->ctx_lock); } /* sync iocbs put the task here for us */ - wake_up_process(iocb->ki_obj.tsk); + wake_up_process(iocb->ki_user_obj); return ret; } @@ -673,13 +673,13 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) event = aio_ring_event(info, tail, KM_IRQ0); tail = (tail + 1) % info->nr; - event->obj = (u64)(unsigned long)iocb->ki_obj.user; + event->obj = (u64)(unsigned long)iocb->ki_user_obj; event->data = iocb->ki_user_data; event->res = res; event->res2 = res2; dprintk("aio_complete: %p[%lu]: %p: %p %Lx %lx %lx\n", - ctx, tail, iocb, iocb->ki_obj.user, iocb->ki_user_data, + ctx, tail, iocb, iocb->ki_user_obj, iocb->ki_user_data, res, res2); /* after flagging the request as done, we @@ -777,11 +777,19 @@ static inline void init_timeout(struct timeout *to) static inline void set_timeout(long start_jiffies, struct timeout *to, const struct timespec *ts) { - to->timer.expires = start_jiffies + timespec_to_jiffies(ts); - if (time_after(to->timer.expires, jiffies)) - add_timer(&to->timer); - else + unsigned long how_long; + + if (ts->tv_sec < 0 || (!ts->tv_sec && !ts->tv_nsec)) { to->timed_out = 1; + return; + } + + how_long = ts->tv_sec * HZ; +#define HZ_NS (1000000000 / HZ) + how_long += (ts->tv_nsec + HZ_NS - 1) / HZ_NS; + + to->timer.expires = jiffies + how_long; + add_timer(&to->timer); } static inline void clear_timeout(struct timeout *to) @@ -954,7 +962,6 @@ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp) ret = put_user(ioctx->user_id, ctxp); if (!ret) return 0; - get_ioctx(ioctx); io_destroy(ioctx); } @@ -1022,7 +1029,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, goto out_put_req; } - req->ki_obj.user = user_iocb; + req->ki_user_obj = user_iocb; req->ki_user_data = iocb->aio_data; req->ki_pos = iocb->aio_offset; @@ -1148,7 +1155,7 @@ struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, u32 key /* TODO: use a hash or array, this sucks. */ list_for_each(pos, &ctx->active_reqs) { struct kiocb *kiocb = list_kiocb(pos); - if (kiocb->ki_obj.user == iocb && kiocb->ki_key == key) + if (kiocb->ki_user_obj == iocb && kiocb->ki_key == key) return kiocb; } return NULL; @@ -1195,7 +1202,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, struct io_event tmp; pr_debug("calling cancel\n"); memset(&tmp, 0, sizeof(tmp)); - tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; + tmp.obj = (u64)(unsigned long)kiocb->ki_user_obj; tmp.data = kiocb->ki_user_data; ret = cancel(kiocb, &tmp); if (!ret) { diff --git a/fs/attr.c b/fs/attr.c index d63350cfc..5bb63a855 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -62,6 +62,24 @@ error: EXPORT_SYMBOL(inode_change_ok); +int inode_setattr_flags(struct inode *inode, unsigned int flags) +{ + unsigned int oldflags, newflags; + + oldflags = inode->i_flags; + newflags = oldflags & ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER); + if (flags & ATTR_FLAG_IMMUTABLE) + newflags |= S_IMMUTABLE; + if (flags & ATTR_FLAG_IUNLINK) + newflags |= S_IUNLINK; + if (flags & ATTR_FLAG_BARRIER) + newflags |= S_BARRIER; + + if (oldflags ^ newflags) + inode->i_flags = newflags; + return 0; +} + int inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; @@ -98,6 +116,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr) mode &= ~S_ISGID; inode->i_mode = mode; } + if (ia_valid & ATTR_ATTR_FLAG) + inode_setattr_flags(inode, attr->ia_attr_flags); mark_inode_dirty(inode); out: return error; diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index 237a6305a..f028396f1 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -12,19 +12,14 @@ #include "autofs_i.h" -static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; - return vfs_readlink(dentry, buffer, buflen, s); -} - static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; - return vfs_follow_link(nd, s); + nd_set_link(nd, s); + return 0; } struct inode_operations autofs_symlink_inode_operations = { - .readlink = autofs_readlink, + .readlink = generic_readlink, .follow_link = autofs_follow_link }; diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 9cc355a08..c265a66ed 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -12,21 +12,14 @@ #include "autofs_i.h" -static int autofs4_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - struct autofs_info *ino = autofs4_dentry_ino(dentry); - - return vfs_readlink(dentry, buffer, buflen, ino->u.symlink); -} - static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) { struct autofs_info *ino = autofs4_dentry_ino(dentry); - - return vfs_follow_link(nd, ino->u.symlink); + nd_set_link(nd, (char *)ino->u.symlink); + return 0; } struct inode_operations autofs4_symlink_inode_operations = { - .readlink = autofs4_readlink, + .readlink = generic_readlink, .follow_link = autofs4_follow_link }; diff --git a/fs/bad_inode.c b/fs/bad_inode.c index c0619d21a..e388765ba 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -21,7 +21,8 @@ */ static int bad_follow_link(struct dentry *dent, struct nameidata *nd) { - return vfs_follow_link(nd, ERR_PTR(-EIO)); + nd_set_link(nd, ERR_PTR(-EIO)); + return 0; } static int return_EIO(void) diff --git a/fs/befs/debug.c b/fs/befs/debug.c index b5e190116..651c39634 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -23,7 +23,7 @@ #include "befs.h" #include "endian.h" -#define ERRBUFSIZE 1024 +#define ERRBUFSIZE 512 void befs_error(const struct super_block *sb, const char *fmt, ...) diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 649d02b03..9dd86d62b 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -40,8 +40,8 @@ static struct inode *befs_alloc_inode(struct super_block *sb); static void befs_destroy_inode(struct inode *inode); static int befs_init_inodecache(void); static void befs_destroy_inodecache(void); -static int befs_readlink(struct dentry *, char __user *, int); -static int befs_follow_link(struct dentry *, struct nameidata *nd); +static int befs_follow_link(struct dentry *, struct nameidata *); +static void befs_put_link(struct dentry *, struct nameidata *); static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, char **out, int *out_len); static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, @@ -85,8 +85,9 @@ struct address_space_operations befs_aops = { }; static struct inode_operations befs_symlink_inode_operations = { - .readlink = befs_readlink, + .readlink = generic_readlink, .follow_link = befs_follow_link, + .put_link = befs_put_link, }; /* @@ -462,71 +463,40 @@ befs_destroy_inodecache(void) static int befs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct super_block *sb = dentry->d_sb; befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); char *link; - int res; if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { + struct super_block *sb = dentry->d_sb; befs_data_stream *data = &befs_ino->i_data.ds; - befs_off_t linklen = data->size; + befs_off_t len = data->size; befs_debug(sb, "Follow long symlink"); - link = kmalloc(linklen, GFP_NOFS); - if (link == NULL) - return -ENOMEM; - - if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { + link = kmalloc(len, GFP_NOFS); + if (!link) { + link = ERR_PTR(-ENOMEM); + } else if (befs_read_lsymlink(sb, data, link, len) != len) { kfree(link); befs_error(sb, "Failed to read entire long symlink"); - return -EIO; + link = ERR_PTR(-EIO); } - - res = vfs_follow_link(nd, link); - - kfree(link); } else { link = befs_ino->i_data.symlink; - res = vfs_follow_link(nd, link); } - return res; + nd_set_link(nd, link); + return 0; } -static int -befs_readlink(struct dentry *dentry, char __user *buffer, int buflen) +static void befs_put_link(struct dentry *dentry, struct nameidata *nd) { - struct super_block *sb = dentry->d_sb; befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); - char *link; - int res; - if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { - befs_data_stream *data = &befs_ino->i_data.ds; - befs_off_t linklen = data->size; - - befs_debug(sb, "Read long symlink"); - - link = kmalloc(linklen, GFP_NOFS); - if (link == NULL) - return -ENOMEM; - - if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { - kfree(link); - befs_error(sb, "Failed to read entire long symlink"); - return -EIO; - } - - res = vfs_readlink(dentry, buffer, buflen, link); - - kfree(link); - } else { - link = befs_ino->i_data.symlink; - res = vfs_readlink(dentry, buffer, buflen, link); + char *p = nd_get_link(nd); + if (!IS_ERR(p)) + kfree(p); } - - return res; } /* diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 9bda8b9ac..8db14c6df 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -308,8 +308,10 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = TASK_UNMAPPED_BASE; - - current->mm->rss = 0; + /* unlimited stack is larger than TASK_SIZE */ + current->mm->non_executable_cache = current->mm->mmap_top; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a672adc9b..2eef1b022 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -46,7 +46,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(struct file*); -static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); +static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); #ifndef elf_addr_t @@ -156,20 +156,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, if (k_platform) { size_t len = strlen(k_platform) + 1; -#ifdef CONFIG_X86_HT - /* - * In some cases (e.g. Hyper-Threading), we want to avoid L1 - * evictions by the processes running on the same package. One - * thing we can do is to shuffle the initial stack for them. - * - * The conditionals here are unneeded, but kept in to make the - * code behaviour the same as pre change unless we have - * hyperthreaded processors. This should be cleaned up - * before 2.6 - */ - - if (smp_num_siblings > 1) - STACK_ALLOC(p, ((current->pid % 64) << 7)); +#ifdef __HAVE_ARCH_ALIGN_STACK + p = (unsigned long)arch_align_stack((unsigned long)p); #endif u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); __copy_to_user(u_platform, k_platform, len); @@ -273,20 +261,59 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, #ifndef elf_map static unsigned long elf_map(struct file *filep, unsigned long addr, - struct elf_phdr *eppnt, int prot, int type) + struct elf_phdr *eppnt, int prot, int type, + unsigned long total_size) { unsigned long map_addr; + unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr); + unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr); + + addr = ELF_PAGESTART(addr); + size = ELF_PAGEALIGN(size); down_write(¤t->mm->mmap_sem); - map_addr = do_mmap(filep, ELF_PAGESTART(addr), - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + + /* + * total_size is the size of the ELF (interpreter) image. + * The _first_ mmap needs to know the full size, otherwise + * randomization might put this image into an overlapping + * position with the ELF binary image. (since size < total_size) + * So we first map the 'big' image - and unmap the remainder at + * the end. (which unmap is needed for ELF images with holes.) + */ + if (total_size) { + total_size = ELF_PAGEALIGN(total_size); + map_addr = do_mmap(filep, addr, total_size, prot, type, off); + if (!BAD_ADDR(map_addr)) + do_munmap(current->mm, map_addr+size, total_size-size); + } else + map_addr = do_mmap(filep, addr, size, prot, type, off); + up_write(¤t->mm->mmap_sem); - return(map_addr); + + return map_addr; } #endif /* !elf_map */ +static inline unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) +{ + int i, first_idx = -1, last_idx = -1; + + for (i = 0; i < nr; i++) + if (cmds[i].p_type == PT_LOAD) { + last_idx = i; + if (first_idx == -1) + first_idx = i; + } + + if (first_idx == -1) + return 0; + + return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz - + ELF_PAGESTART(cmds[first_idx].p_vaddr); +} + /* This is much more generalized than the library routine read function, so we keep this separate. Technically the library read function is only provided so that we can read a.out libraries that have @@ -294,7 +321,8 @@ static unsigned long elf_map(struct file *filep, unsigned long addr, static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, struct file * interpreter, - unsigned long *interp_load_addr) + unsigned long *interp_load_addr, + unsigned long no_base) { struct elf_phdr *elf_phdata; struct elf_phdr *eppnt; @@ -302,6 +330,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, int load_addr_set = 0; unsigned long last_bss = 0, elf_bss = 0; unsigned long error = ~0UL; + unsigned long total_size; int retval, i, size; /* First of all, some simple consistency checks */ @@ -336,6 +365,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (retval < 0) goto out_close; + total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); + if (!total_size) + goto out_close; + eppnt = elf_phdata; for (i=0; ie_phnum; i++, eppnt++) { if (eppnt->p_type == PT_LOAD) { @@ -350,8 +383,11 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, vaddr = eppnt->p_vaddr; if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) elf_type |= MAP_FIXED; + else if (no_base && interp_elf_ex->e_type == ET_DYN) + load_addr = -vaddr; - map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); + map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type, total_size); + total_size = 0; error = map_addr; if (BAD_ADDR(map_addr)) goto out_close; @@ -490,7 +526,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) struct exec interp_ex; char passed_fileno[6]; struct files_struct *files; - int executable_stack = EXSTACK_DEFAULT; + int executable_stack, relocexec, old_relocexec = current->flags & PF_RELOCEXEC; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); @@ -616,14 +652,35 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) } elf_ppnt = elf_phdata; + executable_stack = EXSTACK_DEFAULT; + for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) if (elf_ppnt->p_type == PT_GNU_STACK) { if (elf_ppnt->p_flags & PF_X) executable_stack = EXSTACK_ENABLE_X; else executable_stack = EXSTACK_DISABLE_X; + break; } + relocexec = 0; + + if (current->personality == PER_LINUX) + switch (exec_shield) { + case 1: + if (executable_stack != EXSTACK_DEFAULT) { + current->flags |= PF_RELOCEXEC; + relocexec = PF_RELOCEXEC; + } + break; + + case 2: + executable_stack = EXSTACK_DISABLE_X; + current->flags |= PF_RELOCEXEC; + relocexec = PF_RELOCEXEC; + break; + } + /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; @@ -676,6 +733,16 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; + current->flags |= relocexec; + +#ifdef __i386__ + /* + * Turn off the CS limit completely if exec-shield disabled or + * NX active: + */ + if (!exec_shield || use_nx) + arch_add_exec_range(current->mm, -1); +#endif /* Discard our unneeded old files struct */ if (files) { @@ -689,6 +756,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; +#ifdef __HAVE_ARCH_MMAP_TOP + current->mm->mmap_top = mmap_top(); +#endif current->flags &= ~PF_FORKNOEXEC; /* Do this immediately, since STACK_TOP as used in setup_arg_pages @@ -697,8 +767,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* Do this so that we can load the interpreter, if need be. We will change some of these later */ - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); current->mm->free_area_cache = TASK_UNMAPPED_BASE; + current->mm->non_executable_cache = current->mm->mmap_top; retval = setup_arg_pages(bprm, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); @@ -707,10 +779,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->start_stack = bprm->p; + /* Now we do a little grungy work by mmaping the ELF image into - the correct location in memory. At this point, we assume that - the image should be loaded at fixed address, not at a variable - address. */ + the correct location in memory. + */ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; @@ -747,16 +819,16 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; - if (elf_ex.e_type == ET_EXEC || load_addr_set) { + if (elf_ex.e_type == ET_EXEC || load_addr_set) elf_flags |= MAP_FIXED; - } else if (elf_ex.e_type == ET_DYN) { - /* Try and get dynamic programs out of the way of the default mmap - base, as well as whatever program they might try to exec. This - is because the brk will follow the loader, and is not movable. */ + else if (elf_ex.e_type == ET_DYN) +#ifdef __i386__ + load_bias = 0; +#else load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); - } +#endif - error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags, 0); if (BAD_ADDR(error)) continue; @@ -827,7 +899,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) else elf_entry = load_elf_interp(&interp_elf_ex, interpreter, - &interp_load_addr); + &interp_load_addr, + load_bias); if (BAD_ADDR(elf_entry)) { printk(KERN_ERR "Unable to load interpreter\n"); send_sig(SIGSEGV, current, 0); @@ -850,6 +923,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) set_binfmt(&elf_format); + /* + * Map the vsyscall trampoline. This address is then passed via + * AT_SYSINFO. + */ +#ifdef __HAVE_ARCH_VSYSCALL + map_vsyscall(); +#endif + compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; create_elf_tables(bprm, &elf_ex, (interpreter_type == INTERPRETER_AOUT), @@ -863,6 +944,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->end_data = end_data; current->mm->start_stack = bprm->p; +#ifdef __HAVE_ARCH_RANDOMIZE_BRK + if (current->flags & PF_RELOCEXEC) + randomize_brk(elf_brk); +#endif if (current->personality & MMAP_PAGE_ZERO) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. @@ -916,6 +1001,8 @@ out_free_fh: } out_free_ph: kfree(elf_phdata); + current->flags &= ~PF_RELOCEXEC; + current->flags |= old_relocexec; goto out; } diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 465133cd6..8728d532d 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -651,7 +651,8 @@ static int load_flat_file(struct linux_binprm * bprm, current->mm->start_brk = datapos + data_len + bss_len; current->mm->brk = (current->mm->start_brk + 3) & ~3; current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); } if (flags & FLAT_FLAG_KTRACE) diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 9f2c43aba..6ba6a2f88 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -196,7 +196,7 @@ static int unquote(char *from) * ':name:type:offset:magic:mask:interpreter:' * where the ':' is the IFS, that can be chosen with the first char */ -static Node *create_entry(const char __user *buffer, size_t count) +static Node *create_entry(const char *buffer, size_t count) { Node *e; int memsize, err; @@ -319,7 +319,7 @@ Einval: * Set status of entry/binfmt_misc: * '1' enables, '0' disables and '-1' clears entry/binfmt_misc */ -static int parse_command(const char __user *buffer, size_t count) +static int parse_command(const char *buffer, size_t count) { char s[4]; @@ -424,7 +424,7 @@ static void kill_node(Node *e) /* / */ static ssize_t -bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) +bm_entry_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { Node *e = file->f_dentry->d_inode->u.generic_ip; loff_t pos = *ppos; @@ -456,7 +456,7 @@ out: return res; } -static ssize_t bm_entry_write(struct file *file, const char __user *buffer, +static ssize_t bm_entry_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct dentry *root; @@ -488,7 +488,7 @@ static struct file_operations bm_entry_operations = { /* /register */ -static ssize_t bm_register_write(struct file *file, const char __user *buffer, +static ssize_t bm_register_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { Node *e; @@ -556,7 +556,7 @@ static struct file_operations bm_register_operations = { /* /status */ static ssize_t -bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +bm_status_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { char *s = enabled ? "enabled" : "disabled"; int len = strlen(s); @@ -574,7 +574,7 @@ bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) return nbytes; } -static ssize_t bm_status_write(struct file * file, const char __user * buffer, +static ssize_t bm_status_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) { int res = parse_command(buffer, count); diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index d7e5f1f23..496196b4e 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -259,7 +259,8 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) create_som_tables(bprm); current->mm->start_stack = bprm->p; - current->mm->rss = 0; + // current->mm->rss = 0; + vx_rsspages_sub(current->mm, current->mm->rss); #if 0 printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index ac239020f..0759aab0e 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS @@ -23,7 +23,6 @@ Amrut Joshi Shobhit Dayal Sergey Vlasov Richard Hughes -Yury Umanets Test case and Bug Report contributors ------------------------------------- @@ -31,7 +30,5 @@ Thanks to those in the community who have submitted detailed bug reports and debug of problems they have found: Jochen Dolze, David Blaine, Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, -Olaf Kirch, Kieron Briggs and others. +Kieron Briggs and others. -And thanks to the IBM LTC and Power test teams and SuSE testers for -finding multiple bugs during excellent stress test runs. diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index cae2bfb99..c1028f952 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,20 +1,3 @@ -Version 1.18 ------------- -Do not rename hardlinked files (since that should be a noop). Flush -cached write behind data when reopening a file after session abend, -except when already in write. Grab per socket sem during reconnect -to avoid oops in sendmsg if overlapping with reconnect. - - -Version 1.17 ------------- -Update number of blocks in file so du command is happier (in Linux a fake -blocksize of 512 is required for calculating number of blocks in inode). -Fix prepare write of partial pages to read in data from server if possible. -Fix race on tcpStatus field between unmount and reconnection code, causing -cifsd process sometimes to hang around forever. Improve out of memory -checks in cifs_filldir - Version 1.16 ------------ Fix incorrect file size in file handle based setattr on big endian hardware. diff --git a/fs/cifs/README b/fs/cifs/README index 09b49c804..8dba57f94 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -97,9 +97,7 @@ Linux: case sensitive = yes delete readonly = yes - ea support = yes - -Note that ea support is required for supporting Linux xattrs. + Some administrators also change the "map archive" and the "create mask" parameters from their default values. Creating special devices (mknod) remotely may require specifying a mkdev function to Samba. For more information on these @@ -270,12 +268,11 @@ Misc /proc/fs/cifs Flags and Debug Info ======================================= Informational pseudo-files: DebugData Displays information about active CIFS sessions - and shares. + as well as per share statistics (if CONFIG_CIFS_STATS + is enabled in the kernel configuration). SimultaneousOps Counter which holds maximum number of simultaneous outstanding SMB/CIFS requests. -Stats Lists summary resource usage information as well as per - share statistics, if CONFIG_CIFS_STATS in enabled - in the kernel configuration. +Stats Lists summary resource usage information Configuration pseudo-files: MultiuserMount If set to one, more than one CIFS session to diff --git a/fs/cifs/TODO b/fs/cifs/TODO index c4ee8107a..b7e5ef239 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -80,13 +80,27 @@ symlink text beginning with slash but recognizes them 3) create of new files to FAT partitions on Windows servers can succeed but still return access denied (appears to be Windows -server not cifs client problem) and has not been reproduced recently. +not client problem) and has not been reproduced recently. NTFS partitions do not have this problem. 4) debug connectation lock test case 10 which fails against Samba (may be unmappable due to POSIX to Windows lock model differences but worth investigating). Also debug Samba to see why lock test case 7 takes longer to complete to Samba than to Windows. +5) prepare_write does not initialize pages properly when partial +page writes begin in the middle of a page (pages can get zeroed). +6) Write caching done incorrectly when files are only opened +with write permission by the application. +7) Rename of files that are hardlinked does not work correctly e.g. + ln source target + mv source target +This should be no op since files are linked but in cifs it causes +the source file to go away. This may require implementation of +the cifs POSIX extensions (Unix Extensions version 2) for +it to be done correctly since Samba is failing the rename, +(rather than ignoring it) so the client not knowing they +are linked proceeds to delete the target and then retry the +move which succeeds this time (but the source is gone). Misc testing to do ================== diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 2c3d9a867..0b114f0b5 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -142,10 +142,30 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, sprintf(buf, " type: %d ", tcon->fsDevInfo.DeviceType); buf += length; - if(tcon->tidStatus == CifsNeedReconnect) { + if(tcon->tidStatus == CifsNeedReconnect) buf += sprintf(buf, "\tDISCONNECTED "); - length += 14; - } +#ifdef CONFIG_CIFS_STATS + length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", + atomic_read(&tcon->num_smbs_sent), + atomic_read(&tcon->num_oplock_brks)); + buf += length; + length = sprintf(buf,"\nReads: %d Bytes %lld", + atomic_read(&tcon->num_reads), + (long long)(tcon->bytes_read)); + buf += length; + length = sprintf(buf,"\nWrites: %d Bytes: %lld", + atomic_read(&tcon->num_writes), + (long long)(tcon->bytes_written)); + buf += length; + length = sprintf(buf, + "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", + atomic_read(&tcon->num_opens), + atomic_read(&tcon->num_deletes), + atomic_read(&tcon->num_mkdirs), + atomic_read(&tcon->num_rmdirs)); + buf += length; +#endif + } read_unlock(&GlobalSMBSeslock); @@ -180,80 +200,32 @@ cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset, return length; } -#ifdef CONFIG_CIFS_STATS int cifs_stats_read(char *buf, char **beginBuffer, off_t offset, int length, int *eof, void *data) { - int item_length,i; - struct list_head *tmp; - struct cifsTconInfo *tcon; - - length = sprintf(buf, - "Resources in use\nCIFS Session: %d\n", - sesInfoAllocCount.counter); + int item_length; + length = + sprintf(buf, + "Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter); buf += length; item_length = - sprintf(buf,"Share (unique mount targets): %d\n", - tconInfoAllocCount.counter); + sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter); length += item_length; buf += item_length; item_length = - sprintf(buf,"SMB Request/Response Buffer: %d\n", - bufAllocCount.counter); + sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter); length += item_length; buf += item_length; item_length = - sprintf(buf,"Operations (MIDs): %d\n", - midCount.counter); + sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); length += item_length; buf += item_length; - item_length = sprintf(buf, - "\n%d session %d share reconnects\n", - tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); + item_length = sprintf(buf,"%d sessions and %d shares reconnected after failure\n",tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); length += item_length; - buf += item_length; - - i = 0; - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalTreeConnectionList) { - i++; - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); - buf += item_length; - length += item_length; - if(tcon->tidStatus == CifsNeedReconnect) { - buf += sprintf(buf, "\tDISCONNECTED "); - length += 14; - } - item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", - atomic_read(&tcon->num_smbs_sent), - atomic_read(&tcon->num_oplock_brks)); - buf += item_length; - length += item_length; - item_length = sprintf(buf,"\nReads: %d Bytes %lld", - atomic_read(&tcon->num_reads), - (long long)(tcon->bytes_read)); - buf += item_length; - item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", - atomic_read(&tcon->num_writes), - (long long)(tcon->bytes_written)); - buf += item_length; - item_length = sprintf(buf, - "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", - atomic_read(&tcon->num_opens), - atomic_read(&tcon->num_deletes), - atomic_read(&tcon->num_mkdirs), - atomic_read(&tcon->num_rmdirs)); - buf += item_length; - length += item_length; - } - read_unlock(&GlobalSMBSeslock); - return length; } -#endif struct proc_dir_entry *proc_fs_cifs; read_proc_t cifs_txanchor_read; @@ -293,10 +265,10 @@ cifs_proc_init(void) create_proc_read_entry("SimultaneousOps", 0, proc_fs_cifs, cifs_total_xid_read, 0); -#ifdef CONFIG_CIFS_STATS + create_proc_read_entry("Stats", 0, proc_fs_cifs, cifs_stats_read, 0); -#endif + pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, cifsFYI_read, 0); if (pde) @@ -364,9 +336,7 @@ cifs_proc_clean(void) remove_proc_entry("cifsFYI", proc_fs_cifs); remove_proc_entry("traceSMB", proc_fs_cifs); remove_proc_entry("SimultaneousOps", proc_fs_cifs); -#ifdef CONFIG_CIFS_STATS remove_proc_entry("Stats", proc_fs_cifs); -#endif remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); @@ -400,7 +370,7 @@ cifsFYI_read(char *page, char **start, off_t off, int count, return len; } static int -cifsFYI_write(struct file *file, const char __user *buffer, +cifsFYI_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -439,7 +409,7 @@ oplockEnabled_read(char *page, char **start, off_t off, return len; } static int -oplockEnabled_write(struct file *file, const char __user *buffer, +oplockEnabled_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -479,7 +449,7 @@ quotaEnabled_read(char *page, char **start, off_t off, return len; } static int -quotaEnabled_write(struct file *file, const char __user *buffer, +quotaEnabled_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -519,7 +489,7 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, return len; } static int -linuxExtensionsEnabled_write(struct file *file, const char __user *buffer, +linuxExtensionsEnabled_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -559,7 +529,7 @@ lookupFlag_read(char *page, char **start, off_t off, return len; } static int -lookupFlag_write(struct file *file, const char __user *buffer, +lookupFlag_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -597,7 +567,7 @@ traceSMB_read(char *page, char **start, off_t off, int count, return len; } static int -traceSMB_write(struct file *file, const char __user *buffer, +traceSMB_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -636,7 +606,7 @@ multiuser_mount_read(char *page, char **start, off_t off, return len; } static int -multiuser_mount_write(struct file *file, const char __user *buffer, +multiuser_mount_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -675,7 +645,7 @@ extended_security_read(char *page, char **start, off_t off, return len; } static int -extended_security_write(struct file *file, const char __user *buffer, +extended_security_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -714,7 +684,7 @@ ntlmv2_enabled_read(char *page, char **start, off_t off, return len; } static int -ntlmv2_enabled_write(struct file *file, const char __user *buffer, +ntlmv2_enabled_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; @@ -753,7 +723,7 @@ packet_signing_enabled_read(char *page, char **start, off_t off, return len; } static int -packet_signing_enabled_write(struct file *file, const char __user *buffer, +packet_signing_enabled_write(struct file *file, const char *buffer, unsigned long count, void *data) { char c; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1fe2654a7..03d91f196 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -426,7 +426,7 @@ cifs_get_sb(struct file_system_type *fs_type, } static ssize_t -cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, +cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { if(file == NULL) @@ -455,7 +455,7 @@ cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, } static ssize_t -cifs_write_wrapper(struct file * file, const char __user *write_data, +cifs_write_wrapper(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { ssize_t written; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index b8be30c09..d960b3555 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -85,7 +85,7 @@ extern struct dentry_operations cifs_dentry_ops; /* Functions related to symlinks */ extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); -extern int cifs_readlink(struct dentry *direntry, char __user *buffer, int buflen); +extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen); extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); extern int cifs_removexattr(struct dentry *, const char *); @@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); -#define CIFS_VERSION "1.18" +#define CIFS_VERSION "1.16" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 067eb4e3e..4a57daf48 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -862,10 +862,6 @@ typedef struct smb_com_create_directory_rsp { __u16 ByteCount; /* bct = 0 */ } CREATE_DIRECTORY_RSP; -/***************************************************/ -/* NT Transact structure defintions follow */ -/* Currently only ioctl and notify are implemented */ -/***************************************************/ typedef struct smb_com_transaction_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; @@ -908,45 +904,29 @@ typedef struct smb_com_transaction_ioctl_rsp { } TRANSACT_IOCTL_RSP; typedef struct smb_com_transaction_change_notify_req { - struct smb_hdr hdr; /* wct = 23 */ - __u8 MaxSetupCount; - __u16 Reserved; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 MaxParameterCount; - __u32 MaxDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 DataCount; - __u32 DataOffset; - __u8 SetupCount; /* four setup words follow subcommand */ - /* SNIA spec incorrectly included spurious pad here */ - __u16 SubCommand;/* 4 = Change Notify */ + struct smb_hdr hdr; /* wct = 23 */ + __u8 MaxSetupCount; + __u16 Reserved; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 MaxParameterCount; + __u32 MaxDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 DataCount; + __u32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __u16 SubCommand;/* 4 = Change Notify */ __u32 CompletionFilter; /* operation to monitor */ __u16 Fid; __u8 WatchTree; /* 1 = Monitor subdirectories */ - __u8 Reserved2; __u16 ByteCount; -/* __u8 Pad[3];*/ -/* __u8 Data[1];*/ + __u8 Pad[3]; + __u8 Data[1]; } TRANSACT_CHANGE_NOTIFY_REQ; -typedef struct smb_com_transaction_change_notify_rsp { - struct smb_hdr hdr; /* wct = 18 */ - __u8 Reserved[3]; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 ParameterDisplacement; - __u32 DataCount; - __u32 DataOffset; - __u32 DataDisplacement; - __u8 SetupCount; /* 0 */ - __u16 ByteCount; - /* __u8 Pad[3]; */ -} TRANSACT_CHANGE_NOTIFY_RSP; -/* Completion Filter flags for Notify */ +/* Completion Filter flags */ #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 #define FILE_NOTIFY_CHANGE_NAME 0x00000003 @@ -1046,12 +1026,9 @@ typedef union smb_com_transaction2 { /* PathInfo/FileInfo infolevels */ #define SMB_INFO_STANDARD 1 -#define SMB_INFO_QUERY_EAS_FROM_LIST 3 -#define SMB_INFO_QUERY_ALL_EAS 4 #define SMB_INFO_IS_NAME_VALID 6 #define SMB_QUERY_FILE_BASIC_INFO 0x101 #define SMB_QUERY_FILE_STANDARD_INFO 0x102 -#define SMB_QUERY_FILE_EA_INFO 0x103 #define SMB_QUERY_FILE_NAME_INFO 0x104 #define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 #define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 @@ -1690,17 +1667,16 @@ struct gealist { }; struct fea { - unsigned char EA_flags; - __u8 name_len; - __u16 value_len; + unsigned char fEA; + unsigned char cbName; + unsigned short cbValue; char szName[1]; - /* optionally followed by value */ }; /* flags for _FEA.fEA */ #define FEA_NEEDEA 0x80 /* need EA bit */ struct fealist { - __u32 list_len; + unsigned long cbList; struct fea list[1]; }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index cf99e22c6..cc6871542 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -244,11 +244,4 @@ extern int CIFSSMBCopy(int xid, const __u16 target_tid, const char *toName, const int flags, const struct nls_table *nls_codepage); -extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs,const __u16 netfid,__u32 filter, - const struct nls_table *nls_codepage); -extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - char * EAData, size_t size, - const struct nls_table *nls_codepage); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 420742abb..6a26f8c41 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -383,11 +383,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) smb_buffer_response, &length, 0); if (ses->server) { atomic_dec(&ses->server->socketUseCount); - if (atomic_read(&ses->server->socketUseCount) == 0) { - spin_lock(&GlobalMid_Lock); + if (atomic_read(&ses->server->socketUseCount) == 0) ses->server->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); - } } if (pSMB) cifs_buf_release(pSMB); @@ -1467,9 +1464,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, pSMB->TotalParameterCount = 0 ; pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le32(2); + pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = cpu_to_le32(4000); + pSMB->MaxDataCount = cpu_to_le16(4000); pSMB->MaxSetupCount = 4; pSMB->Reserved = 0; pSMB->ParameterOffset = 0; @@ -1596,8 +1593,6 @@ QPathInfoRetry: } else { /* decode response */ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); /* BB also check enough total bytes returned */ - /* BB we need to improve the validity checking - of these trans2 responses */ if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) rc = -EIO; /* bad smb */ else if (pFindData){ @@ -2833,149 +2828,3 @@ setPermsRetry: goto setPermsRetry; return rc; } - -int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, const struct nls_table *nls_codepage) -{ - int rc = 0; - struct smb_com_transaction_change_notify_req * pSMB = NULL; - struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; - int bytes_returned; - - cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); - rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->TotalParameterCount = 0 ; - pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le32(2); - /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = 0; /* same in little endian or be */ - pSMB->MaxSetupCount = 4; - pSMB->Reserved = 0; - pSMB->ParameterOffset = 0; - pSMB->DataCount = 0; - pSMB->DataOffset = 0; - pSMB->SetupCount = 4; /* single byte does not need le conversion */ - pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); - pSMB->ParameterCount = pSMB->TotalParameterCount; - if(notify_subdirs) - pSMB->WatchTree = 1; /* one byte - no le conversion needed */ - pSMB->Reserved2 = 0; - pSMB->CompletionFilter = cpu_to_le32(filter); - pSMB->Fid = netfid; /* file handle always le */ - pSMB->ByteCount = 0; - - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) { - cFYI(1, ("Error in Notify = %d", rc)); - } - if (pSMB) - cifs_buf_release(pSMB); -/* if (rc == -EAGAIN) - goto NotifyRetry; */ - return rc; -} -#ifdef CONFIG_CIFS_XATTR -int -CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - char * EAData, size_t size, - const struct nls_table *nls_codepage) -{ - /* BB assumes one setup word */ - TRANSACTION2_QPI_REQ *pSMB = NULL; - TRANSACTION2_QPI_RSP *pSMBr = NULL; - int rc = 0; - int bytes_returned; - int name_len; - - cFYI(1, ("In Query All EAs path %s", searchName)); -QAllEAsRetry: - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 - /* find define for this maxpathcomponent */ - , nls_codepage); - name_len++; /* trailing null */ - name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(searchName, 530); - name_len++; /* trailing null */ - strncpy(pSMB->FileName, searchName, name_len); - } - - pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + - name_len /* includes null */ ; - pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ - pSMB->MaxSetupCount = 0; - pSMB->Reserved = 0; - pSMB->Flags = 0; - pSMB->Timeout = 0; - pSMB->Reserved2 = 0; - pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); - pSMB->DataCount = 0; - pSMB->DataOffset = 0; - pSMB->SetupCount = 1; - pSMB->Reserved3 = 0; - pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); - pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); - pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) { - cFYI(1, ("Send error in QueryAllEAs = %d", rc)); - } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - /* BB also check enough total bytes returned */ - /* BB we need to improve the validity checking - of these trans2 responses */ - if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) - rc = -EIO; /* bad smb */ - /* else if (pFindData){ - memcpy((char *) pFindData, - (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, kl); - }*/ else { - /* check that length of list is not more than bcc */ - /* check that each entry does not go beyond length - of list */ - /* check that each element of each entry does not - go beyond end of list */ - struct fealist * ea_response_data; - rc = 0; - /* validate_trans2_offsets() */ - /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ - ea_response_data = (struct fealist *) - (((char *) &pSMBr->hdr.Protocol) + - pSMBr->DataOffset); - cFYI(1,("ea length %d",ea_response_data->list_len)); - } - } - if (pSMB) - cifs_buf_release(pSMB); - if (rc == -EAGAIN) - goto QAllEAsRetry; - - return rc; -} -#endif diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index befbff5d6..3f1261aa9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -95,15 +95,9 @@ cifs_reconnect(struct TCP_Server_Info *server) struct cifsTconInfo *tcon; struct mid_q_entry * mid_entry; - spin_lock(&GlobalMid_Lock); - if(server->tcpStatus == CifsExiting) { - /* the demux thread will exit normally - next time through the loop */ - spin_unlock(&GlobalMid_Lock); + if(server->tcpStatus == CifsExiting) return rc; - } else - server->tcpStatus = CifsNeedReconnect; - spin_unlock(&GlobalMid_Lock); + server->tcpStatus = CifsNeedReconnect; server->maxBuf = 0; cFYI(1, ("Reconnecting tcp session ")); @@ -128,8 +122,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } } read_unlock(&GlobalSMBSeslock); - /* do not want to be sending data on a socket we are freeing */ - down(&server->tcpSem); + if(server->ssocket) { cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, server->ssocket->flags)); @@ -155,7 +148,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } } spin_unlock(&GlobalMid_Lock); - up(&server->tcpSem); + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { @@ -171,10 +164,7 @@ cifs_reconnect(struct TCP_Server_Info *server) schedule_timeout(3 * HZ); } else { atomic_inc(&tcpSesReconnectCount); - spin_lock(&GlobalMid_Lock); - if(server->tcpStatus != CifsExiting) - server->tcpStatus = CifsGood; - spin_unlock(&GlobalMid_Lock); + server->tcpStatus = CifsGood; atomic_set(&server->inFlight,0); wake_up(&server->response_q); } @@ -253,14 +243,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* some servers kill tcp session rather than returning smb negprot error in which case reconnecting here is not going to help - return error to mount */ - spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); wake_up(&server->response_q); break; } - cFYI(1,("Reconnecting after unexpected peek error %d",length)); + cFYI(1,("Reconnecting after unexpected rcvmsg error ")); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); @@ -280,7 +268,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = sock_recvmsg(csocket, &smb_msg, 4, 0); cFYI(0,("Received 4 byte keep alive packet")); } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { - iov.iov_base = smb_buffer; + iov.iov_base = smb_buffer; iov.iov_len = 4; length = sock_recvmsg(csocket, &smb_msg, 4, 0); cFYI(1,("Good RFC 1002 session rsp")); @@ -292,9 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* if nack on negprot (rather than ret of smb negprot error) reconnecting not going to help, ret error to mount */ - spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); /* wake up thread doing negprot */ wake_up(&server->response_q); break; @@ -405,9 +391,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } } } - spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); atomic_set(&server->inFlight, 0); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests @@ -611,8 +595,6 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol } if ((temp_len = strnlen(value, 300)) < 300) { vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); - if(vol->UNC == NULL) - return 1; strcpy(vol->UNC,value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -760,8 +742,6 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol } if ((temp_len = strnlen(devname, 300)) < 300) { vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); - if(vol->UNC == NULL) - return 1; strcpy(vol->UNC,devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -1050,7 +1030,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) } else { /* BB other socket options to set KEEPALIVE, NODELAY? */ cFYI(1,("ipv6 Socket created")); - (*csocket)->sk->sk_allocation = GFP_NOFS; + (*csocket)->sk->sk_allocation = GFP_NOFS; } } @@ -1246,9 +1226,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, init_waitqueue_head(&srvTcp->response_q); init_waitqueue_head(&srvTcp->request_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q); - /* at this point we are the only ones with the pointer - to the struct since the kernel thread not created yet - so no need to spinlock this init of tcpStatus */ srvTcp->tcpStatus = CifsNew; init_MUTEX(&srvTcp->tcpSem); kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, @@ -1365,12 +1342,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* on error free sesinfo and tcon struct if needed */ if (rc) { - if(atomic_read(&srvTcp->socketUseCount) == 0) { - spin_lock(&GlobalMid_Lock); - srvTcp->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); - } - /* If find_unc succeeded then rc == 0 so we can not end */ + if(atomic_read(&srvTcp->socketUseCount) == 0) + srvTcp->tcpStatus = CifsExiting; + /* If find_unc succeeded then rc == 0 so we can not end */ if (tcon) /* up here accidently freeing someone elses tcon struct */ tconInfoFree(tcon); if (existingCifsSes == 0) { @@ -1560,7 +1534,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr += pSMBr->resp.SecurityBlobLength; - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) @@ -1813,7 +1787,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, pSMBr->resp.SecurityBlobLength)); } - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) @@ -2124,7 +2098,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ses->server->secMode |= SECMODE_SIGN_ENABLED; - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) @@ -2520,7 +2494,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cFYI(1, ("NTLMSSP response to Authenticate ")); - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) @@ -2719,7 +2693,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, /* skip service field (NB: this field is always ASCII) */ bcc_ptr += length + 1; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { length = UniStrnlen((wchar_t *) bcc_ptr, 512); if (((long) bcc_ptr + (2 * length)) - (long) pByteArea(smb_buffer_response) <= @@ -2817,7 +2791,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; int ntlmv2_flag = FALSE; - /* what if server changes its buffer size after dropping the session? */ + /* what if server changes its buffer size after dropping the session? */ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { rc = CIFSSMBNegotiate(xid, pSesInfo); if(rc == -EAGAIN) /* retry only once on 1st time connection */ { @@ -2825,15 +2799,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, if(rc == -EAGAIN) rc = -EHOSTDOWN; } - if(rc == 0) { - spin_lock(&GlobalMid_Lock); - if(pSesInfo->server->tcpStatus != CifsExiting) - pSesInfo->server->tcpStatus = CifsGood; - else - rc = -EHOSTDOWN; - spin_unlock(&GlobalMid_Lock); - - } + if(rc == 0) + pSesInfo->server->tcpStatus = CifsGood; } if (!rc) { pSesInfo->capabilities = pSesInfo->server->capabilities; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 85cccbb05..7f12af145 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -159,7 +159,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, struct cifsFileInfo * pCifsFile = NULL; struct cifsInodeInfo * pCifsInode; int disposition = FILE_OVERWRITE_IF; - int write_only = FALSE; xid = GetXid(); @@ -177,10 +176,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, if(nd) { if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) desiredAccess = GENERIC_READ; - else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) { + else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) desiredAccess = GENERIC_WRITE; - write_only = TRUE; - } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { + else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { /* GENERIC_ALL is too much permission to request */ /* can cause unnecessary access denied on create */ /* desiredAccess = GENERIC_ALL; */ @@ -264,25 +262,16 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, pCifsFile->invalidHandle = FALSE; pCifsFile->closePend = FALSE; init_MUTEX(&pCifsFile->fh_sem); - /* put the following in at open now */ - /* pCifsFile->pfile = file; */ + /* pCifsFile->pfile = file; */ /* put in at open time */ write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist,&pTcon->openFileList); pCifsInode = CIFS_I(newinode); if(pCifsInode) { - /* if readable file instance put first in list*/ - if (write_only == TRUE) { - list_add_tail(&pCifsFile->flist, - &pCifsInode->openFileList); - } else { - list_add(&pCifsFile->flist, - &pCifsInode->openFileList); - } + list_add(&pCifsFile->flist,&pCifsInode->openFileList); if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheRead = TRUE; - cFYI(1,("Exclusive Oplock granted on inode %p", - newinode)); + cFYI(1,("Exclusive Oplock granted on inode %p",newinode)); } else if((oplock & 0xF) == OPLOCK_READ) pCifsInode->clientCanCacheRead = TRUE; } diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 1469a406f..39d7b89b7 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -32,12 +32,9 @@ int cifs_directory_notify(unsigned long arg, struct file * file) { int xid; int rc = -EINVAL; - int oplock = FALSE; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; - __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; - __u16 netfid; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -51,20 +48,7 @@ int cifs_directory_notify(unsigned long arg, struct file * file) rc = -ENOMEM; } else { cFYI(1,("cifs dir notify on file %s",full_path)); - rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, - GENERIC_READ | SYNCHRONIZE, 0 /* create options */, - &netfid, &oplock,NULL, cifs_sb->local_nls); - /* BB fixme - add this handle to a notify handle list */ - if(rc) { - cFYI(1,("Could not open directory for notify")); - } else { - rc = CIFSSMBNotify(xid, pTcon, 1 /* subdirs */, netfid, - filter, cifs_sb->local_nls); - /* BB add code to close file eventually (at unmount - it would close automatically but may be a way - to do it easily when inode freed or when - notify info is cleared/changed */ - } + /* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/ } FreeXid(xid); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 7d0ac5104..87d28964e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -143,10 +143,6 @@ cifs_open(struct inode *inode, struct file *file) /* Also refresh inode by passing in file_info buf returned by SMBOpen and calling get_inode_info with returned buf (at least helps non-Unix server case */ - - /* BB we can not do this if this is the second open of a file - and the first handle has writebehind data, we might be - able to simply do a filemap_fdatawrite/filemap_fdatawait first */ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); if(buf==0) { if (full_path) @@ -177,14 +173,7 @@ cifs_open(struct inode *inode, struct file *file) list_add(&pCifsFile->tlist,&pTcon->openFileList); pCifsInode = CIFS_I(file->f_dentry->d_inode); if(pCifsInode) { - /* want handles we can use to read with first */ - /* in the list so we do not have to walk the */ - /* list to search for one in prepare_write */ - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList); - } else { - list_add(&pCifsFile->flist,&pCifsInode->openFileList); - } + list_add(&pCifsFile->flist,&pCifsInode->openFileList); write_unlock(&GlobalSMBSeslock); write_unlock(&file->f_owner.lock); if(pCifsInode->clientCanCacheRead) { @@ -267,7 +256,7 @@ static int cifs_relock_file(struct cifsFileInfo * cifsFile) return rc; } -static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush) +static int cifs_reopen_file(struct inode *inode, struct file *file) { int rc = -EACCES; int xid, oplock; @@ -279,6 +268,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flus int desiredAccess = 0x20197; int disposition = FILE_OPEN; __u16 netfid; + FILE_ALL_INFO * buf = NULL; if(inode == NULL) return -EBADF; @@ -331,23 +321,21 @@ and we can never tell if the caller already has the rename_sem */ else oplock = FALSE; - - /* Can not refresh inode by passing in file_info buf to be returned - by SMBOpen and then calling get_inode_info with returned buf - since file might have write behind data that needs to be flushed - and server version of file size can be stale. If we - knew for sure that inode was not dirty locally we could do this */ + /* BB pass O_SYNC flag through on file attributes .. BB */ -/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + /* Also refresh inode by passing in file_info buf returned by SMBOpen + and calling get_inode_info with returned buf (at least + helps non-Unix server case */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); if(buf==0) { up(&pCifsFile->fh_sem); if (full_path) kfree(full_path); FreeXid(xid); return -ENOMEM; - }*/ + } rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls); + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); if (rc) { up(&pCifsFile->fh_sem); cFYI(1, ("cifs_open returned 0x%x ", rc)); @@ -358,25 +346,13 @@ and we can never tell if the caller already has the rename_sem */ up(&pCifsFile->fh_sem); pCifsInode = CIFS_I(inode); if(pCifsInode) { - if(can_flush) { - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); - /* temporarily disable caching while we - go to server to get inode info */ - pCifsInode->clientCanCacheAll = FALSE; - pCifsInode->clientCanCacheRead = FALSE; - if (pTcon->ses->capabilities & CAP_UNIX) - rc = cifs_get_inode_info_unix(&inode, + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb); - else - rc = cifs_get_inode_info(&inode, - full_path, NULL, inode->i_sb); - } /* else we are writing out data to server already - and could deadlock if we tried to flush data, and - since we do not know if we have data that would - invalidate the current end of file on the server - we can not go to the server to get the new - inod info */ + else + rc = cifs_get_inode_info(&inode, + full_path, buf, inode->i_sb); + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheRead = TRUE; @@ -392,6 +368,8 @@ and we can never tell if the caller already has the rename_sem */ } } + if (buf) + kfree(buf); if (full_path) kfree(full_path); FreeXid(xid); @@ -627,11 +605,7 @@ cifs_write(struct file * file, const char *write_data, FreeXid(xid); return total_written; } - /* we could deadlock if we called - filemap_fdatawait from here so tell - reopen_file not to flush data to server now */ - rc = cifs_reopen_file(file->f_dentry->d_inode, - file,FALSE); + rc = cifs_reopen_file(file->f_dentry->d_inode,file); if(rc != 0) break; } @@ -727,7 +701,6 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) cifsInode = CIFS_I(mapping->host); read_lock(&GlobalSMBSeslock); - /* BB we should start at the end */ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp,struct cifsFileInfo, flist); if(open_file->closePend) @@ -797,9 +770,6 @@ cifs_writepage(struct page* page, struct writeback_control *wbc) xid = GetXid(); /* BB add check for wbc flags */ page_cache_get(page); - if (!PageUptodate(page)) { - cFYI(1,("ppw - page not up to date")); - } rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE); SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ @@ -817,7 +787,8 @@ cifs_commit_write(struct file *file, struct page *page, unsigned offset, int rc = 0; struct inode *inode = page->mapping->host; loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - char * page_data; + /* struct cifsFileInfo *open_file; + struct cifs_sb_info *cifs_sb; */ xid = GetXid(); cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); @@ -848,31 +819,7 @@ cifs_commit_write(struct file *file, struct page *page, unsigned offset, cFYI(1,(" SetEOF (commit write) rc = %d",rc)); }*/ } - if (!PageUptodate(page)) { - position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; - /* can not rely on (or let) writepage write this data */ - if(to < offset) { - cFYI(1,("Illegal offsets, can not copy from %d to %d", - offset,to)); - FreeXid(xid); - return rc; - } - /* this is probably better than directly calling - partialpage_write since in this function - the file handle is known which we might as well - leverage */ - /* BB check if anything else missing out of ppw */ - /* such as updating last write time */ - page_data = kmap(page); - rc = cifs_write(file, page_data+offset,to-offset, - &position); - if(rc > 0) - rc = 0; - /* else if rc < 0 should we set writebehind rc? */ - kunmap(page); - } else { - set_page_dirty(page); - } + set_page_dirty(page); FreeXid(xid); return rc; @@ -977,18 +924,13 @@ cifs_read(struct file * file, char *read_data, size_t read_size, } open_file = (struct cifsFileInfo *)file->private_data; - if((file->f_flags & O_ACCMODE) == O_WRONLY) { - cFYI(1,("attempting read on write only file instance")); - } - for (total_read = 0,current_offset=read_data; read_size > total_read; total_read += bytes_read,current_offset+=bytes_read) { current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); rc = -EAGAIN; while(rc == -EAGAIN) { if ((open_file->invalidHandle) && (!open_file->closePend)) { - rc = cifs_reopen_file(file->f_dentry->d_inode, - file,TRUE); + rc = cifs_reopen_file(file->f_dentry->d_inode,file); if(rc != 0) break; } @@ -1143,8 +1085,7 @@ cifs_readpages(struct file *file, struct address_space *mapping, rc = -EAGAIN; while(rc == -EAGAIN) { if ((open_file->invalidHandle) && (!open_file->closePend)) { - rc = cifs_reopen_file(file->f_dentry->d_inode, - file, TRUE); + rc = cifs_reopen_file(file->f_dentry->d_inode,file); if(rc != 0) break; } @@ -1228,105 +1169,53 @@ cifs_readpages(struct file *file, struct address_space *mapping, return rc; } -static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset) +static int +cifs_readpage(struct file *file, struct page *page) { + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; char * read_data; - int rc; + int rc = -EACCES; + int xid; + + xid = GetXid(); + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + + cFYI(0,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset)); page_cache_get(page); read_data = kmap(page); /* for reads over a certain size could initiate async read ahead */ - - rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); - + + rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, &offset); + if (rc < 0) goto io_error; else { cFYI(1,("Bytes read %d ",rc)); } - + file->f_dentry->d_inode->i_atime = CURRENT_TIME; - + if(PAGE_CACHE_SIZE > rc) { memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); } flush_dcache_page(page); SetPageUptodate(page); rc = 0; - -io_error: - kunmap(page); - page_cache_release(page); - return rc; -} - -static int -cifs_readpage(struct file *file, struct page *page) -{ - loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; - int rc = -EACCES; - int xid; - - xid = GetXid(); - - if (file->private_data == NULL) { - FreeXid(xid); - return -EBADF; - } - - cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset)); - - rc = cifs_readpage_worker(file,page,&offset); +io_error: + kunmap(page); unlock_page(page); + page_cache_release(page); FreeXid(xid); return rc; } -/* We do not want to update the file size from server for inodes - open for write - to avoid races with writepage extending - the file - in the future we could consider allowing - refreshing the inode only on increases in the file size - but this is tricky to do without racing with writebehind - page caching in the current Linux kernel design */ - -int is_size_safe_to_change(struct cifsInodeInfo * cifsInode) -{ - struct list_head *tmp; - struct list_head *tmp1; - struct cifsFileInfo *open_file = NULL; - int rc = TRUE; - - if(cifsInode == NULL) - return rc; - - read_lock(&GlobalSMBSeslock); - list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { - open_file = list_entry(tmp,struct cifsFileInfo, flist); - if(open_file == NULL) - break; - if(open_file->closePend) - continue; - /* We check if file is open for writing, - BB we could supplement this with a check to see if file size - changes have been flushed to server - ie inode metadata dirty */ - if((open_file->pfile) && - ((open_file->pfile->f_flags & O_RDWR) || - (open_file->pfile->f_flags & O_WRONLY))) { - rc = FALSE; - break; - } - if(tmp->next == NULL) { - cFYI(1,("File instance %p removed",tmp)); - break; - } - } - read_unlock(&GlobalSMBSeslock); - return rc; -} - - void fill_in_inode(struct inode *tmp_inode, FILE_DIRECTORY_INFO * pfindData, int *pobject_type) @@ -1386,16 +1275,9 @@ fill_in_inode(struct inode *tmp_inode, atomic_set(&cifsInfo->inUse,1); } - if(is_size_safe_to_change(cifsInfo)) { - /* can not safely change the file size here if the - client is writing to it due to potential races */ - i_size_write(tmp_inode,pfindData->EndOfFile); - - /* 512 bytes (2**9) is the fake blocksize that must be used */ - /* for this calculation, even though the reported blocksize is larger */ - tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; - } - + i_size_write(tmp_inode,pfindData->EndOfFile); + tmp_inode->i_blocks = + (tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits; if (pfindData->AllocationSize < pfindData->EndOfFile) cFYI(1, ("Possible sparse file: allocation size less than end of file ")); cFYI(1, @@ -1466,17 +1348,10 @@ unix_fill_in_inode(struct inode *tmp_inode, tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); - - if(is_size_safe_to_change(cifsInfo)) { - /* can not safely change the file size here if the - client is writing to it due to potential races */ - pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - i_size_write(tmp_inode,pfindData->EndOfFile); - - /* 512 bytes (2**9) is the fake blocksize that must be used */ - /* for this calculation, not the real blocksize */ - tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; - } + pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); + i_size_write(tmp_inode,pfindData->EndOfFile); + tmp_inode->i_blocks = + (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits; if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); @@ -1518,15 +1393,12 @@ construct_dentry(struct qstr *qstring, struct file *file, /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */ if(*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_dentry->d_sb); - if(*ptmp_inode == NULL) - return; d_instantiate(tmp_dentry, *ptmp_inode); } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); if(tmp_dentry == NULL) { cERROR(1,("Failed allocating dentry")); - *ptmp_inode = NULL; return; } @@ -1534,8 +1406,6 @@ construct_dentry(struct qstr *qstring, struct file *file, tmp_dentry->d_op = &cifs_dentry_ops; cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ", tmp_dentry, *ptmp_inode)); - if(*ptmp_inode == NULL) - return; d_instantiate(tmp_dentry, *ptmp_inode); d_rehash(tmp_dentry); } @@ -1592,9 +1462,7 @@ cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, pqstring->len = pfindData->FileNameLength; construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); - if((tmp_inode == NULL) || (tmp_dentry == NULL)) { - return -ENOMEM; - } + fill_in_inode(tmp_inode, pfindData, &object_type); rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); @@ -1620,9 +1488,6 @@ cifs_filldir_unix(struct qstr *pqstring, pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); - if((tmp_inode == NULL) || (tmp_dentry == NULL)) { - return -ENOMEM; - } unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, @@ -2085,34 +1950,17 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int cifs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { - int rc = 0; - loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); if (!PageUptodate(page)) { - /* if (to - from != PAGE_CACHE_SIZE) { + if (to - from != PAGE_CACHE_SIZE) { void *kaddr = kmap_atomic(page, KM_USER0); memset(kaddr, 0, from); memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - } */ - /* If we are writing a full page it will be up to date, - no need to read from the server */ - if((to==PAGE_CACHE_SIZE) && (from == 0)) - SetPageUptodate(page); - - /* might as well read a page, it is fast enough */ - if((file->f_flags & O_ACCMODE) != O_WRONLY) { - rc = cifs_readpage_worker(file,page,&offset); - } else { - /* should we try using another - file handle if there is one - how would we lock it - to prevent close of that handle racing with this read? */ - /* In any case this will be written out by commit_write */ } + SetPageUptodate(page); } - - /* BB should we pass any errors back? e.g. if we do not have read access to the file */ return 0; } @@ -2121,7 +1969,8 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, - .prepare_write = cifs_prepare_write, + .prepare_write = simple_prepare_write, /* BB fixme BB */ +/* .prepare_write = cifs_prepare_write, */ /* BB removeme BB */ .commit_write = cifs_commit_write, /* .sync_page = cifs_sync_page, */ /*.direct_IO = */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index c12231b48..e3c47ee56 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -30,8 +30,6 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" -extern int is_size_safe_to_change(struct cifsInodeInfo *); - int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, @@ -45,6 +43,9 @@ cifs_get_inode_info_unix(struct inode **pinode, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *tmp_path; +/* BB add caching check so we do not go to server to overwrite inode info to cached file + where the local file sizes are correct and the server info is stale BB */ + xid = GetXid(); pTcon = cifs_sb->tcon; @@ -124,29 +125,13 @@ cifs_get_inode_info_unix(struct inode **pinode, inode->i_nlink = le64_to_cpu(findData.Nlinks); findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); findData.EndOfFile = le64_to_cpu(findData.EndOfFile); - - if(is_size_safe_to_change(cifsInfo)) { - /* can not safely change the file size here if the - client is writing to it due to potential races */ - - i_size_write(inode,findData.EndOfFile); + i_size_write(inode,findData.EndOfFile); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match */ /* inode->i_blksize = (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ - - /* This seems incredibly stupid but it turns out that - i_blocks is not related to (i_size / i_blksize), instead a - size of 512 is required to be used for calculating num blocks */ - - -/* inode->i_blocks = - (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/ - - /* 512 bytes (2**9) is the fake blocksize that must be used */ - /* for this calculation */ - inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9; - } + inode->i_blocks = + (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits; if (findData.NumOfBytes < findData.EndOfFile) cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); @@ -288,18 +273,10 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, inode->i_mode &= ~(S_IWUGO); /* BB add code here - validate if device or weird share or device type? */ } - if(is_size_safe_to_change(cifsInfo)) { - /* can not safely change the file size here if the - client is writing to it due to potential races */ - - i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); - - /* 512 bytes (2**9) is the fake blocksize that must be used */ - /* for this calculation */ - inode->i_blocks = (512 - 1 + pfindData->AllocationSize) - >> 9; - } + i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); + inode->i_blocks = + (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); @@ -579,38 +556,9 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, rc = CIFSSMBRename(xid, pTcon, fromName, toName, cifs_sb_source->local_nls); if(rc == -EEXIST) { - /* check if they are the same file - because rename of hardlinked files is a noop */ - FILE_UNIX_BASIC_INFO * info_buf_source; - FILE_UNIX_BASIC_INFO * info_buf_target; - - info_buf_source = - kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL); - if(info_buf_source != NULL) { - info_buf_target = info_buf_source+1; - rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, - info_buf_source, cifs_sb_source->local_nls); - if(rc == 0) { - rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName, - info_buf_target, - cifs_sb_target->local_nls); - } - if((rc == 0) && - (info_buf_source->UniqueId == - info_buf_target->UniqueId)) { - /* do not rename since the files are hardlinked - which is a noop */ - } else { - /* we either can not tell the files are hardlinked - (as with Windows servers) or files are not hardlinked - so delete the target manually before renaming to - follow POSIX rather than Windows semantics */ - cifs_unlink(target_inode, target_direntry); - rc = CIFSSMBRename(xid, pTcon, fromName, toName, - cifs_sb_source->local_nls); - } - kfree(info_buf_source); - } /* if we can not get memory just leave rc as EEXIST */ + cifs_unlink(target_inode, target_direntry); + rc = CIFSSMBRename(xid, pTcon, fromName, toName, + cifs_sb_source->local_nls); } if((rc == -EIO)||(rc == -EEXIST)) { diff --git a/fs/cifs/link.c b/fs/cifs/link.c index f257ff0ad..38cb122b5 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -210,7 +210,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) } int -cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) +cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) { struct inode *inode = direntry->d_inode; int rc = -EACCES; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3668ab00b..c55118c58 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -120,13 +120,13 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, unsigned int smb_buf_length, struct sockaddr *sin) { int rc = 0; - int i = 0; struct msghdr smb_msg; struct iovec iov; mm_segment_t temp_fs; if(ssocket == NULL) return -ENOTSOCK; /* BB eventually add reconnect code here */ +/* ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */ iov.iov_base = smb_buffer; iov.iov_len = smb_buf_length + 4; @@ -152,14 +152,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, while(iov.iov_len > 0) { rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { - i++; - if(i > 60) { - cERROR(1, - ("sends on sock %p stuck for 30 seconds", - ssocket)); - rc = -EAGAIN; - break; - } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/2); continue; @@ -268,17 +260,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->addr.sockAddr)); - if(rc < 0) { - DeleteMidQEntry(midQ); - up(&ses->server->tcpSem); - /* If not lock req, update # of requests on wire to server */ - if(long_op < 3) { - atomic_dec(&ses->server->inFlight); - wake_up(&ses->server->request_q); - } - return rc; - } else - up(&ses->server->tcpSem); + up(&ses->server->tcpSem); if (long_op == -1) goto cifs_no_response_exit; else if (long_op == 2) /* writes past end of file can take looooong time */ diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 9ef74a31a..6bf72ebb1 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -17,8 +17,9 @@ inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) } static struct inode_operations coda_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setattr = coda_setattr, }; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index fc3fb9f14..c14b9cd97 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -218,14 +218,9 @@ static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u { u32 tmp; - if (get_user(tmp, &up->base)) + if(get_user(tmp, &up->base)) return -EFAULT; - - /* This is actually a physical address stored - * as a void pointer. - */ - kp->base = (void *)(unsigned long) tmp; - + kp->base = compat_ptr(tmp); __get_user(kp->height, &up->height); __get_user(kp->width, &up->width); __get_user(kp->depth, &up->depth); @@ -3112,8 +3107,7 @@ static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long set_fs(old_fs); if (!err) - err = put_user(kuid, - (unsigned int __user *) compat_ptr(arg)); + err = put_user(kuid, (unsigned int *)compat_ptr(arg)); return err; } @@ -3193,8 +3187,7 @@ static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ncp_privatedata_ioctl_32 n32, __user *p32 = compat_ptr(arg); - struct ncp_privatedata_ioctl __user *p = - compat_alloc_user_space(sizeof(*p)); + struct ncp_privatedata_ioctl *p = __user compat_alloc_user_space(sizeof(*p)); u32 len; int err; @@ -3216,10 +3209,8 @@ static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned lon static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct ncp_privatedata_ioctl_32 n32; - struct ncp_privatedata_ioctl_32 __user *p32 = compat_ptr(arg); - struct ncp_privatedata_ioctl __user *p = - compat_alloc_user_space(sizeof(*p)); + struct ncp_privatedata_ioctl_32 n32, *p32 = compat_ptr(arg); + struct ncp_privatedata_ioctl *p = compat_alloc_user_space(sizeof(*p)); if (copy_from_user(&n32, p32, sizeof(n32)) || put_user(n32.len, &p->len) || diff --git a/fs/dcache.c b/fs/dcache.c index 613ff66da..cf32eb26f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -59,6 +59,9 @@ static unsigned int d_hash_shift; static struct hlist_head *dentry_hashtable; static LIST_HEAD(dentry_unused); +static void prune_dcache(int count); + + /* Statistics gathering. */ struct dentry_stat_t dentry_stat = { .age_limit = 45, @@ -81,6 +84,10 @@ static void d_free(struct dentry *dentry) { if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); + if (dentry->d_extra_attributes) { + kfree(dentry->d_extra_attributes); + dentry->d_extra_attributes = NULL; + } call_rcu(&dentry->d_rcu, d_callback, dentry); } @@ -681,6 +688,19 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) struct dentry *dentry; char *dname; +#define DENTRY_UNUSED_THRESHOLD 30000 +#define DENTRY_BATCH_COUNT 32 + + if (dentry_stat.nr_unused > DENTRY_UNUSED_THRESHOLD) { + int doit = 1; + spin_lock(&dcache_lock); + if (dentry_stat.nr_unused < DENTRY_UNUSED_THRESHOLD) + doit = 0; + spin_unlock(&dcache_lock); + if (doit) + prune_dcache(DENTRY_BATCH_COUNT); + } + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; @@ -709,6 +729,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) dentry->d_sb = NULL; dentry->d_op = NULL; dentry->d_fsdata = NULL; + dentry->d_extra_attributes = NULL; dentry->d_mounted = 0; dentry->d_cookie = NULL; dentry->d_bucket = NULL; @@ -1231,6 +1252,16 @@ already_unhashed: /* Unhash the target: dput() will then get rid of it */ __d_drop(target); + /* flush any possible attributes */ + if (dentry->d_extra_attributes) { + kfree(dentry->d_extra_attributes); + dentry->d_extra_attributes = NULL; + } + if (target->d_extra_attributes) { + kfree(target->d_extra_attributes); + target->d_extra_attributes = NULL; + } + list_del(&dentry->d_child); list_del(&target->d_child); @@ -1275,7 +1306,7 @@ already_unhashed: * * "buflen" should be positive. Caller holds the dcache_lock. */ -static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, +char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, char *buffer, int buflen) { @@ -1343,6 +1374,8 @@ Elong: return ERR_PTR(-ENAMETOOLONG); } +EXPORT_SYMBOL_GPL(__d_path); + /* write full pathname into buffer and return start of pathname */ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, int buflen) @@ -1561,6 +1594,23 @@ static int __init set_dhash_entries(char *str) } __setup("dhash_entries=", set_dhash_entries); +void flush_dentry_attributes (void) +{ + struct hlist_node *tmp; + struct dentry *dentry; + int i; + + spin_lock(&dcache_lock); + for (i = 0; i <= d_hash_mask; i++) + hlist_for_each_entry(dentry, tmp, dentry_hashtable+i, d_hash) { + kfree(dentry->d_extra_attributes); + dentry->d_extra_attributes = NULL; + } + spin_unlock(&dcache_lock); +} + +EXPORT_SYMBOL_GPL(flush_dentry_attributes); + static void __init dcache_init(unsigned long mempages) { struct hlist_head *d; @@ -1589,6 +1639,9 @@ static void __init dcache_init(unsigned long mempages) dhash_entries *= sizeof(struct hlist_head); for (order = 0; ((1UL << order) << PAGE_SHIFT) < dhash_entries; order++) ; + + if (order > 5) + order = 5; do { unsigned long tmp; diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 5e66bc917..20842c510 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -848,13 +848,13 @@ static unsigned int boot_options = OPTION_NONE; static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, const char *name, int namelen, int traverse_symlink); -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, +static ssize_t devfsd_read(struct file *file, char *buf, size_t len, loff_t * ppos); static int devfsd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int devfsd_close(struct inode *inode, struct file *file); #ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, +static ssize_t stat_read(struct file *file, char *buf, size_t len, loff_t * ppos); static struct file_operations stat_fops = { .read = stat_read, @@ -2490,28 +2490,11 @@ static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, return 0; } /* End Function devfs_mknod */ -static int devfs_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - int err; - struct devfs_entry *de; - - de = get_devfs_entry_from_vfs_inode(dentry->d_inode); - if (!de) - return -ENODEV; - err = vfs_readlink(dentry, buffer, buflen, de->u.symlink.linkname); - return err; -} /* End Function devfs_readlink */ - static int devfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - int err; - struct devfs_entry *de; - - de = get_devfs_entry_from_vfs_inode(dentry->d_inode); - if (!de) - return -ENODEV; - err = vfs_follow_link(nd, de->u.symlink.linkname); - return err; + struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode); + nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV)); + return 0; } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = { @@ -2529,7 +2512,7 @@ static struct inode_operations devfs_dir_iops = { }; static struct inode_operations devfs_symlink_iops = { - .readlink = devfs_readlink, + .readlink = generic_readlink, .follow_link = devfs_follow_link, .setattr = devfs_notify_change, }; @@ -2579,7 +2562,7 @@ static struct file_system_type devfs_fs_type = { /* File operations for devfsd follow */ -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, +static ssize_t devfsd_read(struct file *file, char *buf, size_t len, loff_t * ppos) { int done = FALSE; @@ -2693,7 +2676,7 @@ static int devfsd_ioctl(struct inode *inode, struct file *file, switch (cmd) { case DEVFSDIOC_GET_PROTO_REV: ival = DEVFSD_PROTOCOL_REVISION_KERNEL; - if (copy_to_user((void __user *)arg, &ival, sizeof ival)) + if (copy_to_user((void *)arg, &ival, sizeof ival)) return -EFAULT; break; case DEVFSDIOC_SET_EVENT_MASK: @@ -2732,7 +2715,7 @@ static int devfsd_ioctl(struct inode *inode, struct file *file, /*break; */ #ifdef CONFIG_DEVFS_DEBUG case DEVFSDIOC_SET_DEBUG_MASK: - if (copy_from_user(&ival, (void __user *)arg, sizeof ival)) + if (copy_from_user(&ival, (void *)arg, sizeof ival)) return -EFAULT; devfs_debug = ival; break; @@ -2772,7 +2755,7 @@ static int devfsd_close(struct inode *inode, struct file *file) } /* End Function devfsd_close */ #ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, +static ssize_t stat_read(struct file *file, char *buf, size_t len, loff_t * ppos) { ssize_t num; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 1d49ef4af..17b686a82 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "xattr.h" #define DEVPTS_SUPER_MAGIC 0x1cd1 @@ -134,11 +135,21 @@ static struct dentry *get_node(int num) return lookup_one_len(s, root, sprintf(s, "%d", num)); } +static int devpts_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + int ret = -EACCES; + + if (vx_check(inode->i_xid, VX_IDENT)) + ret = vfs_permission(inode, mask); + return ret; +} + static struct inode_operations devpts_file_inode_operations = { .setxattr = devpts_setxattr, .getxattr = devpts_getxattr, .listxattr = devpts_listxattr, .removexattr = devpts_removexattr, + .permission = devpts_permission, }; int devpts_pty_new(struct tty_struct *tty) @@ -162,6 +173,7 @@ int devpts_pty_new(struct tty_struct *tty) inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); + inode->i_xid = vx_current_xid(); inode->i_op = &devpts_file_inode_operations; inode->u.generic_ip = tty; diff --git a/fs/direct-io.c b/fs/direct-io.c index d498521c9..a2910fbd6 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -990,6 +990,13 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, } } /* end iovec loop */ + if (ret == -ENOTBLK && rw == WRITE) { + /* + * The remaining part of the request will be + * be handled by buffered I/O when we return + */ + ret = 0; + } /* * There may be some unwritten disk at the end of a part-written * fs-block-sized block. Go zero that now. @@ -1056,29 +1063,24 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, kfree(dio); } } else { - ssize_t transferred = 0; - finished_one_bio(dio); ret2 = dio_await_completion(dio); if (ret == 0) ret = ret2; if (ret == 0) ret = dio->page_errors; - if (dio->result) { + if (ret == 0 && dio->result) { loff_t i_size = i_size_read(inode); - transferred = dio->result; + ret = dio->result; /* * Adjust the return value if the read crossed a * non-block-aligned EOF. */ - if (rw == READ && (offset + transferred > i_size)) - transferred = i_size - offset; + if (rw == READ && (offset + ret > i_size)) + ret = i_size - offset; } - dio_complete(dio, offset, transferred); - if (ret == 0) - ret = transferred; - + dio_complete(dio, offset, ret); /* We could have also come here on an AIO file extend */ if (!is_sync_kiocb(iocb) && rw == WRITE && ret >= 0 && dio->result == dio->size) @@ -1089,13 +1091,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, aio_complete(iocb, ret, 0); kfree(dio); } - if (ret == -ENOTBLK && rw == WRITE) { - /* - * The entire request will be be handled by buffered I/O - * when we return - */ - ret = 0; - } return ret; } diff --git a/fs/dquot.c b/fs/dquot.c index 70280bc2f..df4280050 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -306,7 +306,7 @@ EXPORT_SYMBOL(mark_info_dirty); int dquot_acquire(struct dquot *dquot) { - int ret = 0, ret2 = 0; + int ret = 0; struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); down(&dquot->dq_lock); @@ -319,15 +319,8 @@ int dquot_acquire(struct dquot *dquot) /* Instantiate dquot if needed */ if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); - /* Write the info if needed */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); if (ret < 0) goto out_iolock; - if (ret2 < 0) { - ret = ret2; - goto out_iolock; - } } set_bit(DQ_ACTIVE_B, &dquot->dq_flags); out_iolock: @@ -341,7 +334,7 @@ out_iolock: */ int dquot_commit(struct dquot *dquot) { - int ret = 0, ret2 = 0; + int ret = 0; struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); down(&dqopt->dqio_sem); @@ -353,15 +346,12 @@ int dquot_commit(struct dquot *dquot) spin_unlock(&dq_list_lock); /* Inactive dquot can be only if there was error during read/init * => we have better not writing it */ - if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { + if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); - if (ret >= 0) - ret = ret2; - } out_sem: up(&dqopt->dqio_sem); + if (info_dirty(&dqopt->info[dquot->dq_type])) + dquot->dq_sb->dq_op->write_info(dquot->dq_sb, dquot->dq_type); return ret; } @@ -370,7 +360,7 @@ out_sem: */ int dquot_release(struct dquot *dquot) { - int ret = 0, ret2 = 0; + int ret = 0; struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); down(&dquot->dq_lock); @@ -378,14 +368,8 @@ int dquot_release(struct dquot *dquot) if (atomic_read(&dquot->dq_count) > 1) goto out_dqlock; down(&dqopt->dqio_sem); - if (dqopt->ops[dquot->dq_type]->release_dqblk) { + if (dqopt->ops[dquot->dq_type]->release_dqblk) ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot); - /* Write the info */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); - if (ret >= 0) - ret = ret2; - } clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); up(&dqopt->dqio_sem); out_dqlock: diff --git a/fs/eventpoll.c b/fs/eventpoll.c index bc30a3cdd..1c8083989 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -499,11 +499,6 @@ asmlinkage long sys_epoll_create(int size) DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", current, size)); - /* Sanity check on the size parameter */ - error = -EINVAL; - if (size <= 0) - goto eexit_1; - /* Correctly size the hash */ hashbits = ep_get_hash_bits((unsigned int) size); diff --git a/fs/exec.c b/fs/exec.c index f30b49540..7e5aec30d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -320,7 +321,8 @@ void install_arg_page(struct vm_area_struct *vma, pte_unmap(pte); goto out; } - mm->rss++; + // mm->rss++; + vx_rsspages_inc(mm); lru_cache_add_active(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte( page, vma->vm_page_prot)))); @@ -389,8 +391,13 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) /* zero pages that were copied above */ while (i < MAX_ARG_PAGES) bprm->page[i++] = NULL; +#else +#ifdef __HAVE_ARCH_ALIGN_STACK + stack_base = arch_align_stack(STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE); + stack_base = PAGE_ALIGN(stack_base); #else stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; +#endif mm->arg_start = bprm->p + stack_base; arg_size = STACK_TOP - (PAGE_MASK & (unsigned long) mm->arg_start); #endif @@ -404,7 +411,8 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) { + if (security_vm_enough_memory(arg_size >> PAGE_SHIFT) || + !vx_vmpages_avail(mm, arg_size >> PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -433,7 +441,9 @@ int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; insert_vm_struct(mm, mpnt); - mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + // mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + vx_vmpages_sub(mm, mm->total_vm - + ((mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)); } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -836,6 +846,7 @@ int flush_old_exec(struct linux_binprm * bprm) } current->comm[i] = '\0'; + current->flags &= ~PF_RELOCEXEC; flush_thread(); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || @@ -886,8 +897,13 @@ int prepare_binprm(struct linux_binprm *bprm) if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ - if (mode & S_ISUID) + if (mode & S_ISUID) { bprm->e_uid = inode->i_uid; +#ifdef __i386__ + /* reset personality */ + current->personality = PER_LINUX; +#endif + } /* Set-gid? */ /* @@ -895,8 +911,13 @@ int prepare_binprm(struct linux_binprm *bprm) * is a candidate for mandatory locking, not a setgid * executable. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->e_gid = inode->i_gid; +#ifdef __i386__ + /* reset personality */ + current->personality = PER_LINUX; +#endif + } } /* fill in binprm security blob */ @@ -1074,14 +1095,14 @@ int do_execve(char * filename, int retval; int i; + sched_balance_exec(); + file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) return retval; - sched_balance_exec(); - bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); @@ -1134,6 +1155,8 @@ int do_execve(char * filename, if (retval >= 0) { free_arg_pages(&bprm); + ckrm_cb_exec(filename); + /* execve success */ security_bprm_free(&bprm); return retval; diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index e03b54231..5aa6769ba 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -579,7 +579,8 @@ got: inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_flags = EXT2_I(dir)->i_flags & ~EXT2_BTREE_FL; + ei->i_flags = EXT2_I(dir)->i_flags & + ~(EXT2_BTREE_FL|EXT2_IUNLINK_FL|EXT2_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL); /* dirsync is only applied to directories */ diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 769c0b3af..4389ac953 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "ext2.h" #include "acl.h" @@ -65,6 +66,8 @@ void ext2_put_inode(struct inode *inode) ext2_discard_prealloc(inode); } +static void ext2_truncate_nocheck (struct inode * inode); + /* * Called at the last iput() if i_nlink is zero. */ @@ -78,7 +81,7 @@ void ext2_delete_inode (struct inode * inode) inode->i_size = 0; if (inode->i_blocks) - ext2_truncate (inode); + ext2_truncate_nocheck(inode); ext2_free_inode (inode); return; @@ -878,7 +881,7 @@ static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth) ext2_free_data(inode, p, q); } -void ext2_truncate (struct inode * inode) +static void ext2_truncate_nocheck(struct inode * inode) { u32 *i_data = EXT2_I(inode)->i_data; int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); @@ -895,8 +898,6 @@ void ext2_truncate (struct inode * inode) return; if (ext2_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; ext2_discard_prealloc(inode); @@ -1018,6 +1019,13 @@ Egdp: return ERR_PTR(-EIO); } +void ext2_truncate (struct inode * inode) +{ + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + ext2_truncate_nocheck(inode); +} + void ext2_set_inode_flags(struct inode *inode) { unsigned int flags = EXT2_I(inode)->i_flags; @@ -1029,6 +1037,10 @@ void ext2_set_inode_flags(struct inode *inode) inode->i_flags |= S_APPEND; if (flags & EXT2_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; + if (flags & EXT2_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & EXT2_BARRIER_FL) + inode->i_flags |= S_BARRIER; if (flags & EXT2_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & EXT2_DIRSYNC_FL) @@ -1041,6 +1053,8 @@ void ext2_read_inode (struct inode * inode) ino_t ino = inode->i_ino; struct buffer_head * bh; struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); + uid_t uid; + gid_t gid; int n; #ifdef CONFIG_EXT2_FS_POSIX_ACL @@ -1051,12 +1065,17 @@ void ext2_read_inode (struct inode * inode) goto bad_inode; inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); if (!(test_opt (inode->i_sb, NO_UID32))) { - inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } + inode->i_uid = INOXID_UID(uid, gid); + inode->i_gid = INOXID_GID(uid, gid); + if (inode->i_sb->s_flags & MS_TAGXID) + inode->i_xid = INOXID_XID(uid, gid, le16_to_cpu(raw_inode->i_raw_xid)); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime); @@ -1149,8 +1168,8 @@ static int ext2_update_inode(struct inode * inode, int do_sync) struct ext2_inode_info *ei = EXT2_I(inode); struct super_block *sb = inode->i_sb; ino_t ino = inode->i_ino; - uid_t uid = inode->i_uid; - gid_t gid = inode->i_gid; + uid_t uid = XIDINO_UID(inode->i_uid, inode->i_xid); + gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid); struct buffer_head * bh; struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); int n; @@ -1185,6 +1204,9 @@ static int ext2_update_inode(struct inode * inode, int do_sync) raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } +#ifdef CONFIG_INOXID_GID32 + raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid); +#endif raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); raw_inode->i_size = cpu_to_le32(inode->i_size); raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); @@ -1262,6 +1284,27 @@ int ext2_sync_inode(struct inode *inode) return sync_inode(inode, &wbc); } +int ext2_setattr_flags(struct inode *inode, unsigned int flags) +{ + unsigned int oldflags, newflags; + + oldflags = EXT2_I(inode)->i_flags; + newflags = oldflags & + ~(EXT2_IMMUTABLE_FL | EXT2_IUNLINK_FL | EXT2_BARRIER_FL); + if (flags & ATTR_FLAG_IMMUTABLE) + newflags |= EXT2_IMMUTABLE_FL; + if (flags & ATTR_FLAG_IUNLINK) + newflags |= EXT2_IUNLINK_FL; + if (flags & ATTR_FLAG_BARRIER) + newflags |= EXT2_BARRIER_FL; + + if (oldflags ^ newflags) { + EXT2_I(inode)->i_flags = newflags; + inode->i_ctime = CURRENT_TIME; + } + return 0; +} + int ext2_setattr(struct dentry *dentry, struct iattr *iattr) { struct inode *inode = dentry->d_inode; @@ -1276,6 +1319,9 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) if (error) return error; } + if (iattr->ia_valid & ATTR_ATTR_FLAG) + ext2_setattr_flags(inode, iattr->ia_attr_flags); + inode_setattr(inode, iattr); if (iattr->ia_valid & ATTR_MODE) error = ext2_acl_chmod(inode); diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 945d22aa8..2520c2ff5 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -49,7 +49,9 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { + if ((oldflags & EXT2_IMMUTABLE_FL) || + ((flags ^ oldflags) & + (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 3a06830a5..3e54fbeac 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -270,7 +270,7 @@ enum { Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_tagxid, Opt_ignore, Opt_err, }; @@ -299,6 +299,7 @@ static match_table_t tokens = { {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_tagxid, "tagxid"}, {Opt_ignore, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, @@ -362,6 +363,11 @@ static int parse_options (char * options, case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + set_opt (sbi->s_mount_opt, TAG_XID); + break; +#endif case Opt_check: #ifdef CONFIG_EXT2_CHECK set_opt (sbi->s_mount_opt, CHECK); @@ -646,6 +652,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (!parse_options ((char *) data, sbi)) goto failed_mount; + if (EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_TAG_XID) + sb->s_flags |= MS_TAGXID; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index b282670a5..d77d4b3ed 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -20,22 +20,17 @@ #include "ext2.h" #include "xattr.h" -static int -ext2_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); - return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data); -} - static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); - return vfs_follow_link(nd, (char *)ei->i_data); + nd_set_link(nd, (char *)ei->i_data); + return 0; } struct inode_operations ext2_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setxattr = ext2_setxattr, .getxattr = ext2_getxattr, .listxattr = ext2_listxattr, @@ -43,7 +38,7 @@ struct inode_operations ext2_symlink_inode_operations = { }; struct inode_operations ext2_fast_symlink_inode_operations = { - .readlink = ext2_readlink, + .readlink = generic_readlink, .follow_link = ext2_follow_link, .setxattr = ext2_setxattr, .getxattr = ext2_getxattr, diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile index 92deb0d95..704cd44a4 100644 --- a/fs/ext3/Makefile +++ b/fs/ext3/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o + ioctl.o namei.o super.o symlink.o hash.o resize.o ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 7fd70c88e..fb2410c47 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -428,7 +428,9 @@ ext3_acl_chmod(struct inode *inode) error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) { handle_t *handle; + int retries = 0; + retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) { error = PTR_ERR(handle); @@ -437,6 +439,9 @@ ext3_acl_chmod(struct inode *inode) } error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); ext3_journal_stop(handle); + if (error == -ENOSPC && + ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; } out: posix_acl_release(clone); @@ -516,7 +521,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, { handle_t *handle; struct posix_acl *acl; - int error; + int error, retries = 0; if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; @@ -535,11 +540,14 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, } else acl = NULL; +retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) return PTR_ERR(handle); error = ext3_set_acl(handle, inode, type, acl); ext3_journal_stop(handle); + if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; release_and_out: posix_acl_release(acl); diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 893b08bd5..75369a95c 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -96,9 +96,87 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) error_out: return bh; } +/* + * The reservation window structure operations + * -------------------------------------------- + * Operations include: + * dump, find, add, remove, is_empty, find_next_reservable_window, etc. + * + * We use sorted double linked list for the per-filesystem reservation + * window list. (like in vm_region). + * + * Initially, we keep those small operations in the abstract functions, + * so later if we need a better searching tree than double linked-list, + * we could easily switch to that without changing too much + * code. + */ +static inline void rsv_window_dump(struct reserve_window *head, char *fn) +{ + struct reserve_window *rsv; + + printk("Block Allocation Reservation Windows Map (%s):\n", fn); + list_for_each_entry(rsv, &head->rsv_list, rsv_list) { + printk("reservation window 0x%p start: %d, end: %d\n", + rsv, rsv->rsv_start, rsv->rsv_end); + } +} + +static int +goal_in_my_reservation(struct reserve_window *rsv, int goal, + unsigned int group, struct super_block * sb) +{ + unsigned long group_first_block, group_last_block; + + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + + if ((rsv->rsv_start > group_last_block) || + (rsv->rsv_end < group_first_block)) + return 0; + if ((goal >= 0) && ((goal + group_first_block < rsv->rsv_start) + || (goal + group_first_block > rsv->rsv_end))) + return 0; + return 1; +} + +static inline void rsv_window_add(struct reserve_window *rsv, + struct reserve_window *prev) +{ + /* insert the new reservation window after the head */ + list_add(&rsv->rsv_list, &prev->rsv_list); +} + +static inline void rsv_window_remove(struct reserve_window *rsv) +{ + rsv->rsv_start = 0; + rsv->rsv_end = 0; + rsv->rsv_alloc_hit = 0; + list_del(&rsv->rsv_list); + INIT_LIST_HEAD(&rsv->rsv_list); +} + +static inline int rsv_is_empty(struct reserve_window *rsv) +{ + /* a valid reservation end block could not be 0 */ + return (rsv->rsv_end == 0); +} + +void ext3_discard_reservation(struct inode *inode) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + struct reserve_window *rsv = &ei->i_rsv_window; + spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; + + if (!rsv_is_empty(rsv)) { + spin_lock(rsv_lock); + rsv_window_remove(rsv); + spin_unlock(rsv_lock); + } +} /* Free given blocks, update quota and i_blocks field */ -void ext3_free_blocks (handle_t *handle, struct inode * inode, +void ext3_free_blocks(handle_t *handle, struct inode *inode, unsigned long block, unsigned long count) { struct buffer_head *bitmap_bh = NULL; @@ -275,7 +353,7 @@ do_more: error_return: brelse(bitmap_bh); ext3_std_error(sb, err); - if (dquot_freed_blocks) + if (dquot_freed_blocks && !(EXT3_I(inode)->i_state & EXT3_STATE_RESIZE)) DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); return; } @@ -296,7 +374,7 @@ error_return: * data-writes at some point, and disable it for metadata allocations or * sync-data inodes. */ -static inline int ext3_test_allocatable(int nr, struct buffer_head *bh) +static int ext3_test_allocatable(int nr, struct buffer_head *bh) { int ret; struct journal_head *jh = bh2jh(bh); @@ -313,6 +391,33 @@ static inline int ext3_test_allocatable(int nr, struct buffer_head *bh) return ret; } +static int +bitmap_search_next_usable_block(int start, struct buffer_head *bh, + int maxblocks) +{ + int next; + struct journal_head *jh = bh2jh(bh); + + /* + * The bitmap search --- search forward alternately through the actual + * bitmap and the last-committed copy until we find a bit free in + * both + */ + while (start < maxblocks) { + next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start); + if (next >= maxblocks) + return -1; + if (ext3_test_allocatable(next, bh)) + return next; + jbd_lock_bh_state(bh); + if (jh->b_committed_data) + start = ext3_find_next_zero_bit(jh->b_committed_data, + maxblocks, next); + jbd_unlock_bh_state(bh); + } + return -1; +} + /* * Find an allocatable block in a bitmap. We honour both the bitmap and * its last-committed copy (if that exists), and perform the "most @@ -325,7 +430,6 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) { int here, next; char *p, *r; - struct journal_head *jh = bh2jh(bh); if (start > 0) { /* @@ -337,6 +441,8 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) * next 64-bit boundary is simple.. */ int end_goal = (start + 63) & ~63; + if (end_goal > maxblocks) + end_goal = maxblocks; here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); if (here < end_goal && ext3_test_allocatable(here, bh)) return here; @@ -351,7 +457,7 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *)bh->b_data)) << 3; - if (next < maxblocks && ext3_test_allocatable(next, bh)) + if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) return next; /* @@ -359,19 +465,8 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) * bitmap and the last-committed copy until we find a bit free in * both */ - while (here < maxblocks) { - next = ext3_find_next_zero_bit(bh->b_data, maxblocks, here); - if (next >= maxblocks) - return -1; - if (ext3_test_allocatable(next, bh)) - return next; - jbd_lock_bh_state(bh); - if (jh->b_committed_data) - here = ext3_find_next_zero_bit(jh->b_committed_data, - maxblocks, next); - jbd_unlock_bh_state(bh); - } - return -1; + here = bitmap_search_next_usable_block(here, bh, maxblocks); + return here; } /* @@ -407,62 +502,494 @@ claim_block(spinlock_t *lock, int block, struct buffer_head *bh) */ static int ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, - struct buffer_head *bitmap_bh, int goal, int *errp) + struct buffer_head *bitmap_bh, int goal, struct reserve_window *my_rsv) { - int i; - int fatal; - int credits = 0; - - *errp = 0; - - /* - * Make sure we use undo access for the bitmap, because it is critical - * that we do the frozen_data COW on bitmap buffers in all cases even - * if the buffer is in BJ_Forget state in the committing transaction. - */ - BUFFER_TRACE(bitmap_bh, "get undo access for new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits); - if (fatal) { - *errp = fatal; - goto fail; + int group_first_block, start, end; + + /* we do allocation within the reservation window if we have a window */ + if (my_rsv) { + group_first_block = + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + if (my_rsv->rsv_start >= group_first_block) + start = my_rsv->rsv_start - group_first_block; + else + /* reservation window cross group boundary */ + start = 0; + end = my_rsv->rsv_end - group_first_block + 1; + if (end > EXT3_BLOCKS_PER_GROUP(sb)) + /* reservation window crosses group boundary */ + end = EXT3_BLOCKS_PER_GROUP(sb); + if ((start <= goal) && (goal < end)) + start = goal; + else + goal = -1; + } else { + if (goal > 0) + start = goal; + else + start = 0; + end = EXT3_BLOCKS_PER_GROUP(sb); } + BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb)); + repeat: if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) { - goal = find_next_usable_block(goal, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); + goal = find_next_usable_block(start, bitmap_bh, end); if (goal < 0) goto fail_access; - - for (i = 0; i < 7 && goal > 0 && - ext3_test_allocatable(goal - 1, bitmap_bh); - i++, goal--); + if (!my_rsv) { + int i; + + for (i = 0; i < 7 && goal > start && + ext3_test_allocatable(goal - 1, + bitmap_bh); + i++, goal--) + ; + } } + start = goal; if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) { /* * The block was allocated by another thread, or it was * allocated and then freed by another thread */ + start++; goal++; - if (goal >= EXT3_BLOCKS_PER_GROUP(sb)) + if (start >= end) goto fail_access; goto repeat; } + if (my_rsv) + my_rsv->rsv_alloc_hit++; + return goal; +fail_access: + return -1; +} + +/** + * find_next_reservable_window(): + * find a reservable space within the given range + * It does not allocate the reservation window for now + * alloc_new_reservation() will do the work later. + * + * @search_head: the head of the searching list; + * This is not necessary the list head of the whole filesystem + * + * we have both head and start_block to assist the search + * for the reservable space. The list start from head, + * but we will shift to the place where start_block is, + * then start from there, we looking for a resevable space. + * + * @fs_rsv_head: per-filesystem reervation list head. + * + * @size: the target new reservation window size + * @group_first_block: the first block we consider to start + * the real search from + * + * @last_block: + * the maxium block number that our goal reservable space + * could start from. This is normally the last block in this + * group. The search will end when we found the start of next + * possiblereservable space is out of this boundary. + * This could handle the cross bounday reservation window request. + * + * basically we search from the given range, rather than the whole + * reservation double linked list, (start_block, last_block) + * to find a free region that of of my size and has not + * been reserved. + * + * on succeed, it returns the reservation window to be append to. + * failed, return NULL. + */ +static inline +struct reserve_window *find_next_reservable_window( + struct reserve_window *search_head, + struct reserve_window *fs_rsv_head, + unsigned long size, int *start_block, + int last_block) +{ + struct reserve_window *rsv; + int cur; + + /* TODO:make the start of the reservation window byte alligned */ + /*cur = *start_block & 8;*/ + cur = *start_block; + rsv = list_entry(search_head->rsv_list.next, + struct reserve_window, rsv_list); + while (rsv != fs_rsv_head) { + if (cur + size <= rsv->rsv_start) { + /* + * Found a reserveable space big enough. We could + * have a reservation across the group boundary here + */ + break; + } + if (cur <= rsv->rsv_end) + cur = rsv->rsv_end + 1; + + /* TODO? + * in the case we could not find a reservable space + * that is what is expected, during the re-search, we could + * remember what's the largest reservable space we could have + * and return that one. + * + * For now it will fail if we could not find the reservable + * space with expected-size (or more)... + */ + rsv = list_entry(rsv->rsv_list.next, + struct reserve_window, rsv_list); + if (cur > last_block) + return NULL; /* fail */ + } + /* + * we come here either : + * when we rearch to the end of the whole list, + * and there is empty reservable space after last entry in the list. + * append it to the end of the list. + * + * or we found one reservable space in the middle of the list, + * return the reservation window that we could append to. + * succeed. + */ + *start_block = cur; + return list_entry(rsv->rsv_list.prev, struct reserve_window, rsv_list); +} + +/** + * alloc_new_reservation()--allocate a new reservation window + * if there is an existing reservation, discard it first + * then allocate the new one from there + * otherwise allocate the new reservation from the given + * start block, or the beginning of the group, if a goal + * is not given. + * + * To make a new reservation, we search part of the filesystem + * reservation list(the list that inside the group). + * + * If we have a old reservation, the search goal is the end of + * last reservation. If we do not have a old reservatio, then we + * start from a given goal, or the first block of the group, if + * the goal is not given. + * + * We first find a reservable space after the goal, then from + * there,we check the bitmap for the first free block after + * it. If there is no free block until the end of group, then the + * whole group is full, we failed. Otherwise, check if the free + * block is inside the expected reservable space, if so, we + * succeed. + * If the first free block is outside the reseravle space, then + * start from the first free block, we search for next avalibale + * space, and go on. + * + * on succeed, a new reservation will be found and inserted into the list + * It contains at least one free block, and it is not overlap with other + * reservation window. + * + * failed: we failed to found a reservation window in this group + * + * @rsv: the reservation + * + * @goal: The goal. It is where the search for a + * free reservable space should start from. + * if we have a old reservation, start_block is the end of + * old reservation. Otherwise, + * if we have a goal(goal >0 ), then start from there, + * no goal(goal = -1), we start from the first block + * of the group. + * + * @sb: the super block + * @group: the group we are trying to do allocate in + * @bitmap_bh: the block group block bitmap + */ +static int alloc_new_reservation(struct reserve_window *my_rsv, + int goal, struct super_block *sb, + unsigned int group, struct buffer_head *bitmap_bh) +{ + struct reserve_window *search_head; + int group_first_block, group_end_block, start_block; + int first_free_block; + int reservable_space_start; + struct reserve_window *prev_rsv; + struct reserve_window *fs_rsv_head = &EXT3_SB(sb)->s_rsv_window_head; + unsigned long size; + + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + + if (goal < 0) + start_block = group_first_block; + else + start_block = goal + group_first_block; + + size = atomic_read(&my_rsv->rsv_goal_size); + /* if we have a old reservation, start the search from the old rsv */ + if (!rsv_is_empty(my_rsv)) { + /* + * if the old reservation is cross group boundary + * we will come here when we just failed to allocate from + * the first part of the window. We still have another part + * that belongs to the next group. In this case, there is no + * point to discard our window and try to allocate a new one + * in this group(which will fail). we should + * keep the reservation window, just simply move on. + * + * Maybe we could shift the start block of the reservation + * window to the first block of next group. + */ + + if ((my_rsv->rsv_start <= group_end_block) && + (my_rsv->rsv_end > group_end_block)) + return -1; + + /* remember where we are before we discard the old one */ + if (my_rsv->rsv_end + 1 > start_block) + start_block = my_rsv->rsv_end + 1; + search_head = my_rsv; + if ((my_rsv->rsv_alloc_hit > (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { + /* + * if we previously allocation hit ration is greater than half + * we double the size of reservation window next time + * otherwise keep the same + */ + size = size * 2; + if (size > EXT3_MAX_RESERVE_BLOCKS) + size = EXT3_MAX_RESERVE_BLOCKS; + atomic_set(&my_rsv->rsv_goal_size, size); + } + } + else { + /* + * we don't have a reservation, + * we set our goal(start_block) and + * the list head for the search + */ + search_head = fs_rsv_head; + } + + /* + * find_next_reservable_window() simply find a reservable window + * inside the given range(start_block, group_end_block). + * + * To make sure the reservation window has a free bit inside it, we + * need to check the bitmap after we found a reservable window. + */ +retry: + prev_rsv = find_next_reservable_window(search_head, fs_rsv_head, size, + &start_block, group_end_block); + if (prev_rsv == NULL) + goto failed; + reservable_space_start = start_block; + /* + * On success, find_next_reservable_window() returns the + * reservation window where there is a reservable space after it. + * Before we reserve this reservable space, we need + * to make sure there is at least a free block inside this region. + * + * searching the first free bit on the block bitmap and copy of + * last committed bitmap alternatively, until we found a allocatable + * block. Search start from the start block of the reservable space + * we just found. + */ + first_free_block = bitmap_search_next_usable_block( + reservable_space_start - group_first_block, + bitmap_bh, group_end_block - group_first_block + 1); - BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); - fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (first_free_block < 0) { + /* + * no free block left on the bitmap, no point + * to reserve the space. return failed. + */ + goto failed; + } + start_block = first_free_block + group_first_block; + /* + * check if the first free block is within the + * free space we just found + */ + if ((start_block >= reservable_space_start) && + (start_block < reservable_space_start + size)) + goto found_rsv_window; + /* + * if the first free bit we found is out of the reservable space + * this means there is no free block on the reservable space + * we should continue search for next reservable space, + * start from where the free block is, + * we also shift the list head to where we stopped last time + */ + search_head = prev_rsv; + goto retry; + +found_rsv_window: + /* + * great! the reservable space contains some free blocks. + * if the search returns that we should add the new + * window just next to where the old window, we don't + * need to remove the old window first then add it to the + * same place, just update the new start and new end. + */ + if (my_rsv != prev_rsv) { + if (!rsv_is_empty(my_rsv)) + rsv_window_remove(my_rsv); + rsv_window_add(my_rsv, prev_rsv); + } + my_rsv->rsv_start = reservable_space_start; + my_rsv->rsv_end = my_rsv->rsv_start + size - 1; + return 0; /* succeed */ +failed: + return -1; /* failed */ +} + +/* + * This is the main function used to allocate a new block and its reservation + * window. + * + * Each time when a new block allocation is need, first try to allocate from + * its own reservation. If it does not have a reservation window, instead of + * looking for a free bit on bitmap first, then look up the reservation list to + * see if it is inside somebody else's reservation window, we try to allocate a + * reservation window for it start from the goal first. Then do the block + * allocation within the reservation window. + * + * This will aviod keep searching the reservation list again and again when + * someboday is looking for a free block(without reservation), and there are + * lots of free blocks, but they are all being reserved + * + * We use a sorted double linked list for the per-filesystem reservation list. + * The insert, remove and find a free space(non-reserved) operations for the + * sorted double linked list should be fast. + * + */ +static int +ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, + unsigned int group, struct buffer_head *bitmap_bh, + int goal, struct reserve_window * my_rsv, + int *errp) +{ + spinlock_t *rsv_lock; + unsigned long group_first_block; + int ret = 0; + int fatal; + int credits = 0; + + *errp = 0; + + /* + * Make sure we use undo access for the bitmap, because it is critical + * that we do the frozen_data COW on bitmap buffers in all cases even + * if the buffer is in BJ_Forget state in the committing transaction. + */ + BUFFER_TRACE(bitmap_bh, "get undo access for new block"); + fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits); if (fatal) { *errp = fatal; - goto fail; + return -1; + } + + /* + * we don't deal with reservation when + * filesystem is mounted without reservation + * or the file is not a regular file + * of last attemp of allocating a block with reservation turn on failed + */ + if (my_rsv == NULL ) { + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); + goto out; + } + rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + /* + * goal is a group relative block number (if there is a goal) + * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb) + * first block is a filesystem wide block number + * first block is the block number of the first block in this group + */ + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + + /* + * Basically we will allocate a new block from inode's reservation + * window. + * + * We need to allocate a new reservation window, if: + * a) inode does not have a reservation window; or + * b) last attemp of allocating a block from existing reservation + * failed; or + * c) we come here with a goal and with a reservation window + * + * We do not need to allocate a new reservation window if we come here + * at the beginning with a goal and the goal is inside the window, or + * or we don't have a goal but already have a reservation window. + * then we could go to allocate from the reservation window directly. + */ + while (1) { + if (rsv_is_empty(my_rsv) || (ret < 0) || + !goal_in_my_reservation(my_rsv, goal, group, sb)) { + spin_lock(rsv_lock); + ret = alloc_new_reservation(my_rsv, goal, sb, + group, bitmap_bh); + spin_unlock(rsv_lock); + if (ret < 0) + break; /* failed */ + + if (!goal_in_my_reservation(my_rsv, goal, group, sb)) + goal = -1; + } + if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) + || (my_rsv->rsv_end < group_first_block)) + BUG(); + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, + my_rsv); + if (ret >= 0) + break; /* succeed */ + } +out: + if (ret >= 0) { + BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " + "bitmap block"); + fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + return -1; + } + return ret; } - return goal; -fail_access: BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); ext3_journal_release_buffer(handle, bitmap_bh, credits); -fail: - return -1; + return ret; +} + +static int ext3_has_free_blocks(struct ext3_sb_info *sbi) +{ + int free_blocks, root_blocks; + + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); + if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + return 0; + } + return 1; +} + +/* + * ext3_should_retry_alloc() is called when ENOSPC is returned, and if + * it is profitable to retry the operation, this function will wait + * for the current or commiting transaction to complete, and then + * return TRUE. + */ +int ext3_should_retry_alloc(struct super_block *sb, int *retries) +{ + if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3) + return 0; + + jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); + + return journal_force_commit_nested(EXT3_SB(sb)->s_journal); } /* @@ -473,23 +1000,24 @@ fail: * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */ -int -ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, - u32 *prealloc_count, u32 *prealloc_block, int *errp) +int ext3_new_block(handle_t *handle, struct inode *inode, + unsigned long goal, int *errp) { - struct buffer_head *bitmap_bh = NULL; /* bh */ - struct buffer_head *gdp_bh; /* bh2 */ - int group_no; /* i */ - int ret_block; /* j */ - int bgi; /* blockgroup iteration index */ - int target_block; /* tmp */ + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *gdp_bh; + int group_no; + int goal_group; + int ret_block; + int bgi; /* blockgroup iteration index */ + int target_block; int fatal = 0, err; int performed_allocation = 0; - int free_blocks, root_blocks; + int free_blocks; struct super_block *sb; struct ext3_group_desc *gdp; struct ext3_super_block *es; struct ext3_sb_info *sbi; + struct reserve_window *my_rsv = NULL; #ifdef EXT3FS_DEBUG static int goal_hits, goal_attempts; #endif @@ -511,12 +1039,9 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; ext3_debug("goal=%lu.\n", goal); - - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(es->s_r_blocks_count); - if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode)) + my_rsv = &EXT3_I(inode)->i_rsv_window; + if (!ext3_has_free_blocks(sbi)) { *errp = -ENOSPC; goto out; } @@ -533,6 +1058,8 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, if (!gdp) goto io_error; + goal_group = group_no; +retry: free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); if (free_blocks > 0) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % @@ -540,8 +1067,8 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - ret_block = ext3_try_to_allocate(sb, handle, group_no, - bitmap_bh, ret_block, &fatal); + ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, + bitmap_bh, ret_block, my_rsv, &fatal); if (fatal) goto out; if (ret_block >= 0) @@ -569,14 +1096,25 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - ret_block = ext3_try_to_allocate(sb, handle, group_no, - bitmap_bh, -1, &fatal); + ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, + bitmap_bh, -1, my_rsv, &fatal); if (fatal) goto out; if (ret_block >= 0) goto allocated; } - + /* + * We may end up a bogus ealier ENOSPC error due to + * filesystem is "full" of reservations, but + * there maybe indeed free blocks avaliable on disk + * In this case, we just forget about the reservations + * just do block allocation as without reservations. + */ + if (my_rsv) { + my_rsv = NULL; + group_no = goal_group; + goto retry; + } /* No space left on the device */ *errp = -ENOSPC; goto out; diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 50ba6861a..cb0211629 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -33,8 +33,10 @@ */ static int ext3_release_file (struct inode * inode, struct file * filp) { - if (filp->f_mode & FMODE_WRITE) - ext3_discard_prealloc (inode); + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && + (atomic_read(&inode->i_writecount) == 1)) + ext3_discard_reservation(inode); if (is_dx(inode) && filp->private_data) ext3_htree_free_dir_info(filp->private_data); diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index ac238b2fa..c68240561 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -567,7 +567,8 @@ got: ei->i_dir_start_lookup = 0; ei->i_disksize = 0; - ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL; + ei->i_flags = EXT3_I(dir)->i_flags & + ~(EXT3_INDEX_FL|EXT3_IUNLINK_FL|EXT3_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); /* dirsync only applies to directories */ @@ -581,10 +582,11 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; -#ifdef EXT3_PREALLOCATE - ei->i_prealloc_block = 0; - ei->i_prealloc_count = 0; -#endif + ei->i_rsv_window.rsv_start = 0; + ei->i_rsv_window.rsv_end = 0; + atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); + ei->i_rsv_window.rsv_alloc_hit = 0; + INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list); ei->i_block_group = group; ext3_set_inode_flags(inode); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index d0e5ca59b..433ba25ed 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -176,18 +177,7 @@ static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) return ext3_journal_restart(handle, blocks_for_truncate(inode)); } -/* - * Called at each iput() - * - * The inode may be "bad" if ext3_read_inode() saw an error from - * ext3_get_inode(), so we need to check that to avoid freeing random disk - * blocks. - */ -void ext3_put_inode(struct inode *inode) -{ - if (!is_bad_inode(inode)) - ext3_discard_prealloc(inode); -} +static void ext3_truncate_nocheck (struct inode *inode); /* * Called at the last iput() if i_nlink is zero. @@ -212,7 +202,7 @@ void ext3_delete_inode (struct inode * inode) handle->h_sync = 1; inode->i_size = 0; if (inode->i_blocks) - ext3_truncate(inode); + ext3_truncate_nocheck(inode); /* * Kill off the orphan record which ext3_truncate created. * AKPM: I think this can be inside the above `if'. @@ -242,62 +232,12 @@ no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ } -void ext3_discard_prealloc (struct inode * inode) -{ -#ifdef EXT3_PREALLOCATE - struct ext3_inode_info *ei = EXT3_I(inode); - /* Writer: ->i_prealloc* */ - if (ei->i_prealloc_count) { - unsigned short total = ei->i_prealloc_count; - unsigned long block = ei->i_prealloc_block; - ei->i_prealloc_count = 0; - ei->i_prealloc_block = 0; - /* Writer: end */ - ext3_free_blocks (inode, block, total); - } -#endif -} - static int ext3_alloc_block (handle_t *handle, struct inode * inode, unsigned long goal, int *err) { unsigned long result; -#ifdef EXT3_PREALLOCATE -#ifdef EXT3FS_DEBUG - static unsigned long alloc_hits, alloc_attempts; -#endif - struct ext3_inode_info *ei = EXT3_I(inode); - /* Writer: ->i_prealloc* */ - if (ei->i_prealloc_count && - (goal == ei->i_prealloc_block || - goal + 1 == ei->i_prealloc_block)) - { - result = ei->i_prealloc_block++; - ei->i_prealloc_count--; - /* Writer: end */ - ext3_debug ("preallocation hit (%lu/%lu).\n", - ++alloc_hits, ++alloc_attempts); - } else { - ext3_discard_prealloc (inode); - ext3_debug ("preallocation miss (%lu/%lu).\n", - alloc_hits, ++alloc_attempts); - if (S_ISREG(inode->i_mode)) - result = ext3_new_block (inode, goal, - &ei->i_prealloc_count, - &ei->i_prealloc_block, err); - else - result = ext3_new_block (inode, goal, 0, 0, err); - /* - * AKPM: this is somewhat sticky. I'm not surprised it was - * disabled in 2.2's ext3. Need to integrate b_committed_data - * guarding with preallocation, if indeed preallocation is - * effective. - */ - } -#else - result = ext3_new_block (handle, inode, goal, 0, 0, err); -#endif + result = ext3_new_block (handle, inode, goal, err); return result; } @@ -965,38 +905,6 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode * inode, bh = ext3_getblk (handle, inode, block, create, err); if (!bh) return bh; -#ifdef EXT3_PREALLOCATE - /* - * If the inode has grown, and this is a directory, then use a few - * more of the preallocated blocks to keep directory fragmentation - * down. The preallocated blocks are guaranteed to be contiguous. - */ - if (create && - S_ISDIR(inode->i_mode) && - inode->i_blocks > prev_blocks && - EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_PREALLOC)) { - int i; - struct buffer_head *tmp_bh; - - for (i = 1; - EXT3_I(inode)->i_prealloc_count && - i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks; - i++) { - /* - * ext3_getblk will zero out the contents of the - * directory for us - */ - tmp_bh = ext3_getblk(handle, inode, - block+i, create, err); - if (!tmp_bh) { - brelse (bh); - return 0; - } - brelse (tmp_bh); - } - } -#endif if (buffer_uptodate(bh)) return bh; ll_rw_block (READ, 1, &bh); @@ -1080,7 +988,7 @@ static int ext3_prepare_write(struct file *file, struct page *page, struct inode *inode = page->mapping->host; int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; - int tried_commit = 0; + int retries = 0; retry: handle = ext3_journal_start(inode, needed_blocks); @@ -1089,19 +997,8 @@ retry: goto out; } ret = block_prepare_write(page, from, to, ext3_get_block); - if (ret) { - if (ret != -ENOSPC || tried_commit) - goto prepare_write_failed; - /* - * It could be that there _is_ free space, but it's all tied up - * in uncommitted bitmaps. So force a commit here, which makes - * those blocks allocatable and try again. - */ - tried_commit = 1; - handle->h_sync = 1; - ext3_journal_stop(handle); - goto retry; - } + if (ret) + goto prepare_write_failed; if (ext3_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), @@ -1110,6 +1007,8 @@ retry: prepare_write_failed: if (ret) ext3_journal_stop(handle); + if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; out: return ret; } @@ -2124,7 +2023,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, * ext3_truncate() run will find them and release them. */ -void ext3_truncate(struct inode * inode) +void ext3_truncate_nocheck(struct inode * inode) { handle_t *handle; struct ext3_inode_info *ei = EXT3_I(inode); @@ -2145,10 +2044,8 @@ void ext3_truncate(struct inode * inode) return; if (ext3_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; - ext3_discard_prealloc(inode); + ext3_discard_reservation(inode); /* * We have to lock the EOF page here, because lock_page() nests @@ -2303,9 +2200,11 @@ static unsigned long ext3_get_inode_block(struct super_block *sb, unsigned long offset, block; struct buffer_head *bh; struct ext3_group_desc * gdp; + if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO && + ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) || ino > le32_to_cpu( EXT3_SB(sb)->s_es->s_inodes_count)) { @@ -2453,6 +2352,13 @@ has_buffer: return 0; } +void ext3_truncate(struct inode * inode) +{ + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + ext3_truncate_nocheck(inode); +} + void ext3_set_inode_flags(struct inode *inode) { unsigned int flags = EXT3_I(inode)->i_flags; @@ -2464,6 +2370,10 @@ void ext3_set_inode_flags(struct inode *inode) inode->i_flags |= S_APPEND; if (flags & EXT3_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; + if (flags & EXT3_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & EXT3_BARRIER_FL) + inode->i_flags |= S_BARRIER; if (flags & EXT3_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & EXT3_DIRSYNC_FL) @@ -2477,6 +2387,8 @@ void ext3_read_inode(struct inode * inode) struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh; int block; + uid_t uid; + gid_t gid; #ifdef CONFIG_EXT3_FS_POSIX_ACL ei->i_acl = EXT3_ACL_NOT_CACHED; @@ -2487,12 +2399,17 @@ void ext3_read_inode(struct inode * inode) bh = iloc.bh; raw_inode = ext3_raw_inode(&iloc); inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); if(!(test_opt (inode->i_sb, NO_UID32))) { - inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } + inode->i_uid = INOXID_UID(uid, gid); + inode->i_gid = INOXID_GID(uid, gid); + if (inode->i_sb->s_flags & MS_TAGXID) + inode->i_xid = INOXID_XID(uid, gid, le16_to_cpu(raw_inode->i_raw_xid)); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime); @@ -2541,11 +2458,11 @@ void ext3_read_inode(struct inode * inode) } ei->i_disksize = inode->i_size; inode->i_generation = le32_to_cpu(raw_inode->i_generation); -#ifdef EXT3_PREALLOCATE - ei->i_prealloc_count = 0; -#endif ei->i_block_group = iloc.block_group; - + ei->i_rsv_window.rsv_start = 0; + ei->i_rsv_window.rsv_end= 0; + atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); + INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list); /* * NOTE! The in-memory inode i_data array is in little-endian order * even on big-endian machines: we do NOT byteswap the block numbers! @@ -2600,6 +2517,8 @@ static int ext3_do_update_inode(handle_t *handle, struct ext3_inode *raw_inode = ext3_raw_inode(iloc); struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh = iloc->bh; + uid_t uid = XIDINO_UID(inode->i_uid, inode->i_xid); + gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid); int err = 0, rc, block; /* For fields not not tracking in the in-memory inode, @@ -2609,29 +2528,32 @@ static int ext3_do_update_inode(handle_t *handle, raw_inode->i_mode = cpu_to_le16(inode->i_mode); if(!(test_opt(inode->i_sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); /* * Fix up interoperability with old kernels. Otherwise, old inodes get * re-used with the upper 16 bits of the uid/gid intact */ if(!ei->i_dtime) { raw_inode->i_uid_high = - cpu_to_le16(high_16_bits(inode->i_uid)); + cpu_to_le16(high_16_bits(uid)); raw_inode->i_gid_high = - cpu_to_le16(high_16_bits(inode->i_gid)); + cpu_to_le16(high_16_bits(gid)); } else { raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } } else { raw_inode->i_uid_low = - cpu_to_le16(fs_high2lowuid(inode->i_uid)); + cpu_to_le16(fs_high2lowuid(uid)); raw_inode->i_gid_low = - cpu_to_le16(fs_high2lowgid(inode->i_gid)); + cpu_to_le16(fs_high2lowgid(gid)); raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } +#ifdef CONFIG_INOXID_GID32 + raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid); +#endif raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); raw_inode->i_size = cpu_to_le32(ei->i_disksize); raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); @@ -2753,6 +2675,44 @@ void ext3_write_inode(struct inode *inode, int wait) ext3_force_commit(inode->i_sb); } +int ext3_setattr_flags(struct inode *inode, unsigned int flags) +{ + unsigned int oldflags, newflags; + int err = 0; + + oldflags = EXT3_I(inode)->i_flags; + newflags = oldflags & + ~(EXT3_IMMUTABLE_FL | EXT3_IUNLINK_FL | EXT3_BARRIER_FL); + if (flags & ATTR_FLAG_IMMUTABLE) + newflags |= EXT3_IMMUTABLE_FL; + if (flags & ATTR_FLAG_IUNLINK) + newflags |= EXT3_IUNLINK_FL; + if (flags & ATTR_FLAG_BARRIER) + newflags |= EXT3_BARRIER_FL; + + if (oldflags ^ newflags) { + handle_t *handle; + struct ext3_iloc iloc; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (IS_SYNC(inode)) + handle->h_sync = 1; + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto flags_err; + + EXT3_I(inode)->i_flags = newflags; + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + flags_err: + ext3_journal_stop(handle); + } + return err; +} + /* * ext3_setattr() * @@ -2824,6 +2784,12 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ext3_journal_stop(handle); } + if (ia_valid & ATTR_ATTR_FLAG) { + rc = ext3_setattr_flags(inode, attr->ia_attr_flags); + if (!error) + error = rc; + } + rc = inode_setattr(inode, attr); /* If inode_setattr's call to ext3_truncate failed to get a diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 0d5003913..f4e2cb109 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -20,13 +21,14 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, { struct ext3_inode_info *ei = EXT3_I(inode); unsigned int flags; + unsigned short rsv_window_size; ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { case EXT3_IOC_GETFLAGS: flags = ei->i_flags & EXT3_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); + return put_user(flags, (int *) arg); case EXT3_IOC_SETFLAGS: { handle_t *handle = NULL; int err; @@ -40,7 +42,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EACCES; - if (get_user(flags, (int __user *) arg)) + if (get_user(flags, (int *) arg)) return -EFAULT; if (!S_ISDIR(inode->i_mode)) @@ -57,7 +59,9 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if ((oldflags & EXT3_IMMUTABLE_FL) || + ((flags ^ oldflags) & + (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } @@ -100,7 +104,7 @@ flags_err: } case EXT3_IOC_GETVERSION: case EXT3_IOC_GETVERSION_OLD: - return put_user(inode->i_generation, (int __user *) arg); + return put_user(inode->i_generation, (int *) arg); case EXT3_IOC_SETVERSION: case EXT3_IOC_SETVERSION_OLD: { handle_t *handle; @@ -112,7 +116,7 @@ flags_err: return -EPERM; if (IS_RDONLY(inode)) return -EROFS; - if (get_user(generation, (int __user *) arg)) + if (get_user(generation, (int *) arg)) return -EFAULT; handle = ext3_journal_start(inode, 1); @@ -150,6 +154,106 @@ flags_err: remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); return ret; } +#endif + case EXT3_IOC_GETRSVSZ: + if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) { + rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size); + return put_user(rsv_window_size, (int *)arg); + } + return -ENOTTY; + case EXT3_IOC_SETRSVSZ: + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) + return -ENOTTY; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(rsv_window_size, (int *)arg)) + return -EFAULT; + + if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; + atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size); + return 0; + case EXT3_IOC_GROUP_EXTEND: { + unsigned long n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EACCES; + + if (sb->s_flags & MS_RDONLY) + return -EROFS; + + if (get_user(n_blocks_count, (__u32 *)arg)) + return -EFAULT; + + err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + case EXT3_IOC_GROUP_ADD: { + struct ext3_new_group_data input; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EACCES; + + if (inode->i_sb->s_flags & MS_RDONLY) + return -EROFS; + + if (copy_from_user(&input, (struct ext3_new_group_input *)arg, + sizeof(input))) + return -EFAULT; + + err = ext3_group_add(sb, &input); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + + +#if defined(CONFIG_VSERVER_LEGACY) && !defined(CONFIG_INOXID_NONE) + case EXT3_IOC_SETXID: { + handle_t *handle; + struct ext3_iloc iloc; + int xid; + int err; + + /* fixme: if stealth, return -ENOTTY */ + if (!capable(CAP_CONTEXT)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (!(inode->i_sb->s_flags & MS_TAGXID)) + return -ENOSYS; + if (get_user(xid, (int *) arg)) + return -EFAULT; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + return err; + + inode->i_xid = (xid & 0xFFFF); + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + ext3_journal_stop(handle); + return err; + } #endif default: return -ENOTTY; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index d2ad34e13..a93119c4a 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1630,8 +1630,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, { handle_t *handle; struct inode * inode; - int err; + int err, retries = 0; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1650,6 +1651,8 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1658,11 +1661,12 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, { handle_t *handle; struct inode *inode; - int err; + int err, retries = 0; if (!new_valid_dev(rdev)) return -EINVAL; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1682,6 +1686,8 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1691,11 +1697,12 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) struct inode * inode; struct buffer_head * dir_block; struct ext3_dir_entry_2 * de; - int err; + int err, retries = 0; if (dir->i_nlink >= EXT3_LINK_MAX) return -EMLINK; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1753,6 +1760,8 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) d_instantiate(dentry, inode); out_stop: ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1962,6 +1971,8 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode) goto out_brelse; NEXT_ORPHAN(inode) = 0; err = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (err) + goto out_brelse; out_err: ext3_std_error(inode->i_sb, err); @@ -2092,12 +2103,13 @@ static int ext3_symlink (struct inode * dir, { handle_t *handle; struct inode * inode; - int l, err; + int l, err, retries = 0; l = strlen(symname)+1; if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -2136,6 +2148,8 @@ static int ext3_symlink (struct inode * dir, err = ext3_add_nondir(handle, dentry, inode); out_stop: ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -2144,11 +2158,12 @@ static int ext3_link (struct dentry * old_dentry, { handle_t *handle; struct inode *inode = old_dentry->d_inode; - int err; + int err, retries = 0; if (inode->i_nlink >= EXT3_LINK_MAX) return -EMLINK; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS); if (IS_ERR(handle)) @@ -2163,6 +2178,8 @@ static int ext3_link (struct dentry * old_dentry, err = ext3_add_nondir(handle, dentry, inode); ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } diff --git a/fs/ext3/super.c b/fs/ext3/super.c index ad0977b17..1aa5b0491 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -493,10 +493,9 @@ static void destroy_inodecache(void) printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n"); } -#ifdef CONFIG_EXT3_FS_POSIX_ACL - static void ext3_clear_inode(struct inode *inode) { +#ifdef CONFIG_EXT3_FS_POSIX_ACL if (EXT3_I(inode)->i_acl && EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { posix_acl_release(EXT3_I(inode)->i_acl); @@ -507,11 +506,10 @@ static void ext3_clear_inode(struct inode *inode) posix_acl_release(EXT3_I(inode)->i_default_acl); EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; } -} - -#else -# define ext3_clear_inode NULL #endif + if (!is_bad_inode(inode)) + ext3_discard_reservation(inode); +} #ifdef CONFIG_QUOTA @@ -561,7 +559,6 @@ static struct super_operations ext3_sops = { .read_inode = ext3_read_inode, .write_inode = ext3_write_inode, .dirty_inode = ext3_dirty_inode, - .put_inode = ext3_put_inode, .delete_inode = ext3_delete_inode, .put_super = ext3_put_super, .write_super = ext3_write_super, @@ -582,12 +579,13 @@ enum { Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_reservation, Opt_noreservation, Opt_noload, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, - Opt_ignore, Opt_err, + Opt_tagxid, Opt_ignore, Opt_err, Opt_resize, }; static match_table_t tokens = { @@ -614,6 +612,8 @@ static match_table_t tokens = { {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_reservation, "reservation"}, + {Opt_noreservation, "noreservation"}, {Opt_noload, "noload"}, {Opt_commit, "commit=%u"}, {Opt_journal_update, "journal=update"}, @@ -628,11 +628,14 @@ static match_table_t tokens = { {Opt_grpjquota, "grpjquota=%s"}, {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, + {Opt_tagxid, "tagxid"}, {Opt_ignore, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_ignore, "usrquota"}, - {Opt_err, NULL} + {Opt_err, NULL}, + {Opt_resize, "resize"} + }; static unsigned long get_sb_block(void **data) @@ -656,7 +659,7 @@ static unsigned long get_sb_block(void **data) } static int parse_options (char * options, struct super_block *sb, - unsigned long * inum, int is_remount) + unsigned long * inum, unsigned long *n_blocks_count, int is_remount) { struct ext3_sb_info *sbi = EXT3_SB(sb); char * p; @@ -721,6 +724,11 @@ static int parse_options (char * options, struct super_block *sb, case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + set_opt (sbi->s_mount_opt, TAG_XID); + break; +#endif case Opt_check: #ifdef CONFIG_EXT3_CHECK set_opt (sbi->s_mount_opt, CHECK); @@ -767,6 +775,12 @@ static int parse_options (char * options, struct super_block *sb, printk("EXT3 (no)acl options not supported\n"); break; #endif + case Opt_reservation: + set_opt(sbi->s_mount_opt, RESERVATION); + break; + case Opt_noreservation: + clear_opt(sbi->s_mount_opt, RESERVATION); + break; case Opt_journal_update: /* @@@ FIXME */ /* Eventually we will want to be able to create @@ -899,6 +913,15 @@ clear_qf_name: break; case Opt_ignore: break; + case Opt_resize: + if (!n_blocks_count) { + printk("EXT3-fs: resize option only available " + "for remount\n"); + return 0; + } + match_int(&args[0], &option); + *n_blocks_count = option; + break; default: printk (KERN_ERR "EXT3-fs: Unrecognized mount option \"%s\" " @@ -1288,9 +1311,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); - if (!parse_options ((char *) data, sb, &journal_inum, 0)) + set_opt(sbi->s_mount_opt, RESERVATION); + + if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0)) goto failed_mount; + if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAG_XID) + sb->s_flags |= MS_TAGXID; sb->s_flags |= MS_ONE_SECOND; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -1462,6 +1489,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); + /* per fileystem reservation list head & lock */ + spin_lock_init(&sbi->s_rsv_window_lock); + INIT_LIST_HEAD(&sbi->s_rsv_window_head.rsv_list); + sbi->s_rsv_window_head.rsv_start = 0; + sbi->s_rsv_window_head.rsv_end = 0; + sbi->s_rsv_window_head.rsv_alloc_hit = 0; + atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0); + /* * set up enough so that it can read an inode */ @@ -1643,7 +1678,6 @@ static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum) if (!journal) { printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); iput(journal_inode); - return NULL; } journal->j_private = sb; ext3_init_journal_params(EXT3_SB(sb), journal); @@ -1875,17 +1909,13 @@ static void ext3_commit_super (struct super_block * sb, static void ext3_mark_recovery_complete(struct super_block * sb, struct ext3_super_block * es) { - journal_t *journal = EXT3_SB(sb)->s_journal; - - journal_lock_updates(journal); - journal_flush(journal); + journal_flush(EXT3_SB(sb)->s_journal); if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && sb->s_flags & MS_RDONLY) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); sb->s_dirt = 0; ext3_commit_super(sb, es, 1); } - journal_unlock_updates(journal); } /* @@ -2013,11 +2043,12 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) struct ext3_super_block * es; struct ext3_sb_info *sbi = EXT3_SB(sb); unsigned long tmp; + unsigned long n_blocks_count = 0; /* * Allow the "check" option to be passed as a remount option. */ - if (!parse_options(data, sb, &tmp, 1)) + if (!parse_options(data, sb, &tmp, &n_blocks_count, 1)) return -EINVAL; if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) @@ -2030,7 +2061,8 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) ext3_init_journal_params(sbi, sbi->s_journal); - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || + n_blocks_count > le32_to_cpu(es->s_blocks_count)) { if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) return -EROFS; @@ -2069,6 +2101,8 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) */ ext3_clear_journal_err(sb, es); sbi->s_mount_state = le16_to_cpu(es->s_state); + if ((ret = ext3_group_extend(sb, es, n_blocks_count))) + return ret; if (!ext3_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c index ae092875b..65ce3ff33 100644 --- a/fs/ext3/symlink.c +++ b/fs/ext3/symlink.c @@ -22,22 +22,17 @@ #include #include "xattr.h" -static int -ext3_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); - return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data); -} - static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); - return vfs_follow_link(nd, (char*)ei->i_data); + nd_set_link(nd, (char*)ei->i_data); + return 0; } struct inode_operations ext3_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setxattr = ext3_setxattr, .getxattr = ext3_getxattr, .listxattr = ext3_listxattr, @@ -45,8 +40,8 @@ struct inode_operations ext3_symlink_inode_operations = { }; struct inode_operations ext3_fast_symlink_inode_operations = { - .readlink = ext3_readlink, /* BKL not held. Don't need */ - .follow_link = ext3_follow_link, /* BKL not held. Don't need */ + .readlink = generic_readlink, + .follow_link = ext3_follow_link, .setxattr = ext3_setxattr, .getxattr = ext3_getxattr, .listxattr = ext3_listxattr, diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 97b74fed6..b766908ea 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -787,7 +787,7 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb); int block = ext3_new_block(handle, - inode, goal, 0, 0, &error); + inode, goal, &error); if (error) goto cleanup; ea_idebug(inode, "creating block %d", block); @@ -875,8 +875,9 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) { handle_t *handle; - int error; + int error, retries = 0; +retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) { error = PTR_ERR(handle); @@ -886,6 +887,9 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, error = ext3_xattr_set_handle(handle, inode, name_index, name, value, value_len, flags); error2 = ext3_journal_stop(handle); + if (error == -ENOSPC && + ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; if (error == 0) error = error2; } diff --git a/fs/fcntl.c b/fs/fcntl.c index 13d351cba..4b75518ed 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -107,6 +107,8 @@ repeat: error = -EMFILE; if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; + if (!vx_files_avail(1)) + goto out; error = expand_files(files, newfd); if (error < 0) @@ -128,7 +130,7 @@ out: return error; } -static int dupfd(struct file *file, unsigned int start) +int dupfd(struct file *file, unsigned int start) { struct files_struct * files = current->files; int fd; @@ -139,6 +141,7 @@ static int dupfd(struct file *file, unsigned int start) FD_SET(fd, files->open_fds); FD_CLR(fd, files->close_on_exec); spin_unlock(&files->file_lock); + vx_openfd_inc(fd); fd_install(fd, file); } else { spin_unlock(&files->file_lock); @@ -148,6 +151,8 @@ static int dupfd(struct file *file, unsigned int start) return fd; } +EXPORT_SYMBOL_GPL(dupfd); + asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) { int err = -EBADF; @@ -186,6 +191,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) FD_SET(newfd, files->open_fds); FD_CLR(newfd, files->close_on_exec); spin_unlock(&files->file_lock); + vx_openfd_inc(newfd); if (tofree) filp_close(tofree, files); diff --git a/fs/file_table.c b/fs/file_table.c index 5d56ec5db..1894e3b34 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -87,6 +87,7 @@ static int old_max; f->f_owner.lock = RW_LOCK_UNLOCKED; /* f->f_version: 0 */ INIT_LIST_HEAD(&f->f_list); + vx_files_inc(f); return f; } } @@ -184,6 +185,7 @@ void fastcall __fput(struct file *file) fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); + vx_files_dec(file); file_kill(file); file->f_dentry = NULL; file->f_vfsmnt = NULL; diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index be243053a..993e8817f 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -37,7 +37,6 @@ #include "vxfs_inode.h" -static int vxfs_immed_readlink(struct dentry *, char __user *, int); static int vxfs_immed_follow_link(struct dentry *, struct nameidata *); static int vxfs_immed_readpage(struct file *, struct page *); @@ -49,7 +48,7 @@ static int vxfs_immed_readpage(struct file *, struct page *); * but do all work directly on the inode. */ struct inode_operations vxfs_immed_symlink_iops = { - .readlink = vxfs_immed_readlink, + .readlink = generic_readlink, .follow_link = vxfs_immed_follow_link, }; @@ -60,28 +59,6 @@ struct address_space_operations vxfs_immed_aops = { .readpage = vxfs_immed_readpage, }; - -/** - * vxfs_immed_readlink - read immed symlink - * @dp: dentry for the link - * @bp: output buffer - * @buflen: length of @bp - * - * Description: - * vxfs_immed_readlink calls vfs_readlink to read the link - * described by @dp into userspace. - * - * Returns: - * Number of bytes successfully copied to userspace. - */ -static int -vxfs_immed_readlink(struct dentry *dp, char __user *bp, int buflen) -{ - struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); - - return (vfs_readlink(dp, bp, buflen, vip->vii_immed.vi_immed)); -} - /** * vxfs_immed_follow_link - follow immed symlink * @dp: dentry for the link @@ -98,8 +75,8 @@ static int vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); - - return (vfs_follow_link(np, vip->vii_immed.vi_immed)); + nd_set_link(np, vip->vii_immed.vi_immed); + return 0; } /** diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5f3ccf989..0e73e3086 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -396,19 +396,9 @@ restart: sb = sb_entry(super_blocks.prev); for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) { - /* we're making our own get_super here */ sb->s_count++; spin_unlock(&sb_lock); - /* - * If we can't get the readlock, there's no sense in - * waiting around, most of the time the FS is going to - * be unmounted by the time it is released. - */ - if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) - sync_sb_inodes(sb, wbc); - up_read(&sb->s_umount); - } + sync_sb_inodes(sb, wbc); spin_lock(&sb_lock); if (__put_super(sb)) goto restart; @@ -433,15 +423,18 @@ restart: */ void sync_inodes_sb(struct super_block *sb, int wait) { + struct page_state ps; struct writeback_control wbc = { + .bdi = NULL, .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD, + .older_than_this = NULL, + .nr_to_write = 0, }; - unsigned long nr_dirty = read_page_state(nr_dirty); - unsigned long nr_unstable = read_page_state(nr_unstable); - wbc.nr_to_write = nr_dirty + nr_unstable + + get_page_state(&ps); + wbc.nr_to_write = ps.nr_dirty + ps.nr_unstable + (inodes_stat.nr_inodes - inodes_stat.nr_unused) + - nr_dirty + nr_unstable; + ps.nr_dirty + ps.nr_unstable; wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ spin_lock(&inode_lock); sync_sb_inodes(sb, &wbc); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index f2893bbc5..abfd24a7b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -43,8 +43,6 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = { .memory_backed = 1, /* Does not contribute to dirty memory */ }; -int sysctl_hugetlb_shm_group; - static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct inode *inode = file->f_dentry->d_inode; @@ -718,12 +716,6 @@ static unsigned long hugetlbfs_counter(void) return ret; } -static int can_do_hugetlb_shm(void) -{ - return likely(capable(CAP_IPC_LOCK) || - in_group_p(sysctl_hugetlb_shm_group)); -} - struct file *hugetlb_zero_setup(size_t size) { int error; @@ -733,7 +725,7 @@ struct file *hugetlb_zero_setup(size_t size) struct qstr quick_string; char buf[16]; - if (!can_do_hugetlb_shm()) + if (!can_do_mlock()) return ERR_PTR(-EPERM); if (!is_hugepage_mem_enough(size)) diff --git a/fs/inode.c b/fs/inode.c index 042e3bb45..7e1d502c5 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -98,13 +98,36 @@ struct inodes_stat_t inodes_stat; static kmem_cache_t * inode_cachep; +static void prune_icache(int nr_to_scan); + + +#define INODE_UNUSED_THRESHOLD 15000 +#define PRUNE_BATCH_COUNT 32 + +void try_to_clip_inodes(void) +{ + unsigned long count = 0; + /* if there are a LOT of unused inodes in cache, better shrink a few first */ + + /* check lockless first to not take the lock always here; racing occasionally isn't a big deal */ + if (inodes_stat.nr_unused > INODE_UNUSED_THRESHOLD) { + spin_lock(&inode_lock); + if (inodes_stat.nr_unused > INODE_UNUSED_THRESHOLD) + count = inodes_stat.nr_unused - INODE_UNUSED_THRESHOLD; + spin_unlock(&inode_lock); + if (count) + prune_icache(count); + } +} + + static struct inode *alloc_inode(struct super_block *sb) { static struct address_space_operations empty_aops; static struct inode_operations empty_iops; static struct file_operations empty_fops; struct inode *inode; - + if (sb->s_op->alloc_inode) inode = sb->s_op->alloc_inode(sb); else @@ -114,6 +137,11 @@ static struct inode *alloc_inode(struct super_block *sb) struct address_space * const mapping = &inode->i_data; inode->i_sb = sb; + if (sb->s_flags & MS_TAGXID) + inode->i_xid = current->xid; + else + inode->i_xid = 0; /* maybe xid -1 would be better? */ + // inode->i_dqh = dqhget(sb->s_dqh); inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); @@ -133,6 +161,7 @@ static struct inode *alloc_inode(struct super_block *sb) inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; + // inode->i_xid = 0; /* maybe not too wise ... */ inode->i_security = NULL; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { @@ -1363,6 +1392,9 @@ void __init inode_init(unsigned long mempages) ihash_entries *= sizeof(struct hlist_head); for (order = 0; ((1UL << order) << PAGE_SHIFT) < ihash_entries; order++) ; + + if (order > 5) + order = 5; do { unsigned long tmp; diff --git a/fs/intermezzo/Makefile b/fs/intermezzo/Makefile deleted file mode 100644 index 260c7af24..000000000 --- a/fs/intermezzo/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile 1.00 Peter Braam -# - -obj-$(CONFIG_INTERMEZZO_FS) += intermezzo.o - -intermezzo-objs := cache.o dcache.o dir.o ext_attr.o file.o fileset.o \ - inode.o journal.o journal_ext2.o journal_ext3.o \ - journal_obdfs.o journal_reiserfs.o journal_tmpfs.o journal_xfs.o \ - kml_reint.o kml_unpack.o methods.o presto.o psdev.o replicator.o \ - super.o sysctl.o upcall.o vfs.o diff --git a/fs/intermezzo/cache.c b/fs/intermezzo/cache.c deleted file mode 100644 index f97bc164d..000000000 --- a/fs/intermezzo/cache.c +++ /dev/null @@ -1,207 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -/* - This file contains the routines associated with managing a - cache of files for InterMezzo. These caches have two reqs: - - need to be found fast so they are hashed by the device, - with an attempt to have collision chains of length 1. - The methods for the cache are set up in methods. -*/ - -extern kmem_cache_t * presto_dentry_slab; - -/* the intent of this hash is to have collision chains of length 1 */ -#define CACHES_BITS 8 -#define CACHES_SIZE (1 << CACHES_BITS) -#define CACHES_MASK CACHES_SIZE - 1 -static struct list_head presto_caches[CACHES_SIZE]; - -static inline int presto_cache_hash(struct super_block *s) -{ - return (CACHES_MASK) & ((unsigned long)s >> L1_CACHE_SHIFT); -} - -inline void presto_cache_add(struct presto_cache *cache) -{ - list_add(&cache->cache_chain, - &presto_caches[presto_cache_hash(cache->cache_sb)]); -} - -inline void presto_cache_init_hash(void) -{ - int i; - for ( i = 0; i < CACHES_SIZE; i++ ) { - INIT_LIST_HEAD(&presto_caches[i]); - } -} - -int izo_ioctl_packlen(struct izo_ioctl_data *data) -{ - int len = sizeof(struct izo_ioctl_data); - len += size_round(data->ioc_inllen1); - len += size_round(data->ioc_inllen2); - return len; -} - -/* map a device to a cache */ -struct presto_cache *presto_cache_find(struct super_block *s) -{ - struct presto_cache *cache; - struct list_head *lh, *tmp; - - lh = tmp = &(presto_caches[presto_cache_hash(s)]); - while ( (tmp = lh->next) != lh ) { - cache = list_entry(tmp, struct presto_cache, cache_chain); - if (cache->cache_sb == s) - return cache; - } - return NULL; -} - - -/* map an inode to a cache */ -struct presto_cache *presto_get_cache(struct inode *inode) -{ - struct presto_cache *cache; - ENTRY; - /* find the correct presto_cache here, based on the device */ - cache = presto_cache_find(inode->i_sb); - if ( !cache ) { - CERROR("WARNING: no presto cache for %s, ino %ld\n", - inode->i_sb->s_id, inode->i_ino); - EXIT; - return NULL; - } - EXIT; - return cache; -} - -/* another debugging routine: check fs is InterMezzo fs */ -int presto_ispresto(struct inode *inode) -{ - struct presto_cache *cache; - - if ( !inode ) - return 0; - cache = presto_get_cache(inode); - if ( !cache ) - return 0; - return inode->i_sb == cache->cache_sb; -} - -/* setup a cache structure when we need one */ -struct presto_cache *presto_cache_init(void) -{ - struct presto_cache *cache; - - PRESTO_ALLOC(cache, sizeof(struct presto_cache)); - if ( cache ) { - memset(cache, 0, sizeof(struct presto_cache)); - INIT_LIST_HEAD(&cache->cache_chain); - INIT_LIST_HEAD(&cache->cache_fset_list); - cache->cache_lock = SPIN_LOCK_UNLOCKED; - cache->cache_reserved = 0; - } - return cache; -} - -/* free a cache structure and all of the memory it is pointing to */ -inline void presto_free_cache(struct presto_cache *cache) -{ - if (!cache) - return; - - list_del(&cache->cache_chain); - if (cache->cache_sb && cache->cache_sb->s_root && - presto_d2d(cache->cache_sb->s_root)) { - kmem_cache_free(presto_dentry_slab, - presto_d2d(cache->cache_sb->s_root)); - cache->cache_sb->s_root->d_fsdata = NULL; - } - - PRESTO_FREE(cache, sizeof(struct presto_cache)); -} - -int presto_reserve_space(struct presto_cache *cache, loff_t req) -{ - struct filter_fs *filter; - loff_t avail; - struct super_block *sb = cache->cache_sb; - filter = cache->cache_filter; - if (!filter ) { - EXIT; - return 0; - } - if (!filter->o_trops ) { - EXIT; - return 0; - } - if (!filter->o_trops->tr_avail ) { - EXIT; - return 0; - } - - spin_lock(&cache->cache_lock); - avail = filter->o_trops->tr_avail(cache, sb); - CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved, - (long) (cache->cache_reserved + req)); - CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail); - if (req + cache->cache_reserved > avail) { - spin_unlock(&cache->cache_lock); - EXIT; - return -ENOSPC; - } - cache->cache_reserved += req; - spin_unlock(&cache->cache_lock); - - EXIT; - return 0; -} - -void presto_release_space(struct presto_cache *cache, loff_t req) -{ - CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved, - (long) (cache->cache_reserved - req)); - spin_lock(&cache->cache_lock); - cache->cache_reserved -= req; - spin_unlock(&cache->cache_lock); -} diff --git a/fs/intermezzo/dcache.c b/fs/intermezzo/dcache.c deleted file mode 100644 index 8f8e2c516..000000000 --- a/fs/intermezzo/dcache.c +++ /dev/null @@ -1,342 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Original version: Copyright (C) 1996 P. Braam and M. Callahan - * Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University - * d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Directory operations for InterMezzo filesystem - */ - -/* inode dentry alias list walking code adapted from linux/fs/dcache.c - * - * fs/dcache.c - * - * (C) 1997 Thomas Schoebel-Theuer, - * with heavy changes by Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" - -kmem_cache_t * presto_dentry_slab; - -/* called when a cache lookup succeeds */ -static int presto_d_revalidate(struct dentry *de, struct nameidata *nd) -{ - struct inode *inode = de->d_inode; - struct presto_file_set * root_fset; - - ENTRY; - if (!inode) { - EXIT; - return 0; - } - - if (is_bad_inode(inode)) { - EXIT; - return 0; - } - - if (!presto_d2d(de)) { - presto_set_dd(de); - } - - if (!presto_d2d(de)) { - EXIT; - return 0; - } - - root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset; - if (root_fset->fset_flags & FSET_FLAT_BRANCH && - (presto_d2d(de)->dd_fset != root_fset )) { - presto_d2d(de)->dd_fset = root_fset; - } - - EXIT; - return 1; - -#if 0 - /* The following is needed for metadata on demand. */ - if ( S_ISDIR(inode->i_mode) ) { - EXIT; - return (presto_chk(de, PRESTO_DATA) && - (presto_chk(de, PRESTO_ATTR))); - } else { - EXIT; - return presto_chk(de, PRESTO_ATTR); - } -#endif -} - -static void presto_d_release(struct dentry *dentry) -{ - if (!presto_d2d(dentry)) { - /* This can happen for dentries from NFSd */ - return; - } - presto_d2d(dentry)->dd_count--; - - if (!presto_d2d(dentry)->dd_count) { - kmem_cache_free(presto_dentry_slab, presto_d2d(dentry)); - dentry->d_fsdata = NULL; - } -} - -struct dentry_operations presto_dentry_ops = -{ - .d_revalidate = presto_d_revalidate, - .d_release = presto_d_release -}; - -static inline int presto_is_dentry_ROOT (struct dentry *dentry) -{ - return(dentry_name_cmp(dentry,"ROOT") && - !dentry_name_cmp(dentry->d_parent,".intermezzo")); -} - -static struct presto_file_set* presto_try_find_fset(struct dentry* dentry, - int *is_under_d_intermezzo) -{ - struct dentry* temp_dentry; - struct presto_dentry_data *d_data; - int found_root=0; - - ENTRY; - CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry, - dentry->d_name.name); - - *is_under_d_intermezzo = 0; - - /* walk up through the branch to get the fileset */ - /* The dentry we are passed presumably does not have the correct - * fset information. However, we still want to start walking up - * the branch from this dentry to get our found_root and - * is_under_d_intermezzo decisions correct - */ - for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) { - CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry, - temp_dentry->d_name.len,temp_dentry->d_name.name); - if (presto_is_dentry_ROOT(temp_dentry)) - found_root = 1; - if (!found_root && - dentry_name_cmp(temp_dentry, ".intermezzo")) { - *is_under_d_intermezzo = 1; - } - d_data = presto_d2d(temp_dentry); - if (d_data) { - /* If we found a "ROOT" dentry while walking up the - * branch, we will journal regardless of whether - * we are under .intermezzo or not. - * If we are already under d_intermezzo don't reverse - * the decision here...even if we found a "ROOT" - * dentry above .intermezzo (if we were ever to - * modify the directory structure). - */ - if (!*is_under_d_intermezzo) - *is_under_d_intermezzo = !found_root && - (d_data->dd_flags & PRESTO_DONT_JOURNAL); - EXIT; - return d_data->dd_fset; - } - if (temp_dentry->d_parent == temp_dentry) { - break; - } - } - EXIT; - return NULL; -} - -/* Only call this function on positive dentries */ -static struct presto_dentry_data* presto_try_find_alias_with_dd ( - struct dentry* dentry) -{ - struct inode *inode=dentry->d_inode; - struct list_head *head, *next, *tmp; - struct dentry *tmp_dentry; - - /* Search through the alias list for dentries with d_fsdata */ - spin_lock(&dcache_lock); - head = &inode->i_dentry; - next = inode->i_dentry.next; - while (next != head) { - tmp = next; - next = tmp->next; - tmp_dentry = list_entry(tmp, struct dentry, d_alias); - if (!presto_d2d(tmp_dentry)) { - spin_unlock(&dcache_lock); - return presto_d2d(tmp_dentry); - } - } - spin_unlock(&dcache_lock); - return NULL; -} - -/* Only call this function on positive dentries */ -static void presto_set_alias_dd (struct dentry *dentry, - struct presto_dentry_data* dd) -{ - struct inode *inode=dentry->d_inode; - struct list_head *head, *next, *tmp; - struct dentry *tmp_dentry; - - /* Set d_fsdata for this dentry */ - dd->dd_count++; - dentry->d_fsdata = dd; - - /* Now set d_fsdata for all dentries in the alias list. */ - spin_lock(&dcache_lock); - head = &inode->i_dentry; - next = inode->i_dentry.next; - while (next != head) { - tmp = next; - next = tmp->next; - tmp_dentry = list_entry(tmp, struct dentry, d_alias); - if (!presto_d2d(tmp_dentry)) { - dd->dd_count++; - tmp_dentry->d_fsdata = dd; - } - } - spin_unlock(&dcache_lock); - return; -} - -inline struct presto_dentry_data *izo_alloc_ddata(void) -{ - struct presto_dentry_data *dd; - - dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL); - if (dd == NULL) { - CERROR("IZO: out of memory trying to allocate presto_dentry_data\n"); - return NULL; - } - memset(dd, 0, sizeof(*dd)); - dd->dd_count = 1; - - return dd; -} - -/* This uses the BKL! */ -int presto_set_dd(struct dentry * dentry) -{ - struct presto_file_set *fset; - struct presto_dentry_data *dd; - int is_under_d_izo; - int error=0; - - ENTRY; - - if (!dentry) - BUG(); - - lock_kernel(); - - /* Did we lose a race? */ - if (dentry->d_fsdata) { - CERROR("dentry %p already has d_fsdata set\n", dentry); - if (dentry->d_inode) - CERROR(" inode: %ld\n", dentry->d_inode->i_ino); - EXIT; - goto out_unlock; - } - - if (dentry->d_inode != NULL) { - /* NFSd runs find_fh_dentry which instantiates disconnected - * dentries which are then connected without a lookup(). - * So it is possible to have connected dentries that do not - * have d_fsdata set. So we walk the list trying to find - * an alias which has its d_fsdata set and then use that - * for all the other dentries as well. - * - SHP,Vinny. - */ - - /* If there is an alias with d_fsdata use it. */ - if ((dd = presto_try_find_alias_with_dd (dentry))) { - presto_set_alias_dd (dentry, dd); - EXIT; - goto out_unlock; - } - } else { - /* Negative dentry */ - CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry, - dentry->d_name.len, dentry->d_name.name); - } - - /* No pre-existing d_fsdata, we need to construct one. - * First, we must walk up the tree to find the fileset - * If a fileset can't be found, we leave a null fsdata - * and return EROFS to indicate that we can't journal - * updates. - */ - fset = presto_try_find_fset (dentry, &is_under_d_izo); - if (!fset) { -#ifdef PRESTO_NO_NFS - CERROR("No fileset for dentry %p: %*s\n", dentry, - dentry->d_name.len, dentry->d_name.name); -#endif - error = -EROFS; - EXIT; - goto out_unlock; - } - - dentry->d_fsdata = izo_alloc_ddata(); - if (!presto_d2d(dentry)) { - CERROR ("InterMezzo: out of memory allocating d_fsdata\n"); - error = -ENOMEM; - goto out_unlock; - } - presto_d2d(dentry)->dd_fset = fset; - if (is_under_d_izo) - presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL; - EXIT; - -out_unlock: - CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n", - dentry, dentry->d_name.len, dentry->d_name.name, - dentry->d_fsdata); - unlock_kernel(); - return error; -} - -int presto_init_ddata_cache(void) -{ - ENTRY; - presto_dentry_slab = - kmem_cache_create("presto_cache", - sizeof(struct presto_dentry_data), 0, - SLAB_HWCACHE_ALIGN, NULL, - NULL); - EXIT; - return (presto_dentry_slab != NULL); -} - -void presto_cleanup_ddata_cache(void) -{ - kmem_cache_destroy(presto_dentry_slab); -} diff --git a/fs/intermezzo/dir.c b/fs/intermezzo/dir.c deleted file mode 100644 index 3ec2e696a..000000000 --- a/fs/intermezzo/dir.c +++ /dev/null @@ -1,1333 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Tacitus Systems - * Copyright (C) 2000 Peter J. Braam - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -static inline void presto_relock_sem(struct inode *dir) -{ - /* the lock from sys_mkdir / lookup_create */ - down(&dir->i_sem); - /* the rest is done by the do_{create,mkdir, ...} */ -} - -static inline void presto_relock_other(struct inode *dir) -{ - /* vfs_mkdir locks */ - // down(&dir->i_zombie); - //lock_kernel(); -} - -static inline void presto_fulllock(struct inode *dir) -{ - /* the lock from sys_mkdir / lookup_create */ - down(&dir->i_sem); - /* vfs_mkdir locks */ - // down(&dir->i_zombie); - //lock_kernel(); -} - -static inline void presto_unlock(struct inode *dir) -{ - /* vfs_mkdir locks */ - //unlock_kernel(); - // up(&dir->i_zombie); - /* the lock from sys_mkdir / lookup_create */ - up(&dir->i_sem); -} - - -/* - * these are initialized in super.c - */ -extern int presto_permission(struct inode *inode, int mask, struct nameidata *nd); -static int izo_authorized_uid; - -int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id, - unsigned int *generation) -{ - char tmpname[64]; - char *next; - - ENTRY; - /* prefix is 7 characters: '...ino:' */ - if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 || - memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) { - EXIT; - return 0; - } - - memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7); - *(tmpname + dentry->d_name.len - 7) = '\0'; - - /* name is of the form ...ino:: */ - *id = simple_strtoul(tmpname, &next, 16); - if ( *next == PRESTO_ILOOKUP_SEP ) { - *generation = simple_strtoul(next + 1, 0, 16); - CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), " - "generation %x (%d)\n", - tmpname, *id, *id, *generation, *generation); - EXIT; - return 1; - } else { - EXIT; - return 0; - } -} - -struct dentry *presto_tmpfs_ilookup(struct inode *dir, - struct dentry *dentry, - ino_t ino, - unsigned int generation) -{ - return dentry; -} - - -inline int presto_can_ilookup(void) -{ - return (current->euid == izo_authorized_uid || - capable(CAP_DAC_READ_SEARCH)); -} - -struct dentry *presto_iget_ilookup(struct inode *dir, - struct dentry *dentry, - ino_t ino, - unsigned int generation) -{ - struct inode *inode; - int error; - - ENTRY; - - if ( !presto_can_ilookup() ) { - CERROR("ilookup denied: euid %u, authorized_uid %u\n", - current->euid, izo_authorized_uid); - return ERR_PTR(-EPERM); - } - error = -ENOENT; - inode = iget(dir->i_sb, ino); - if (!inode) { - CERROR("fatal: NULL inode ino %lu\n", ino); - goto cleanup_iput; - } - if (is_bad_inode(inode) || inode->i_nlink == 0) { - CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink); - goto cleanup_iput; - } - if (inode->i_generation != generation) { - CERROR("fatal: bad generation %u (want %u)\n", - inode->i_generation, generation); - goto cleanup_iput; - } - - d_instantiate(dentry, inode); - dentry->d_flags |= DCACHE_DISCONNECTED; /* NFS hack */ - - EXIT; - return NULL; - -cleanup_iput: - if (inode) - iput(inode); - return ERR_PTR(error); -} - -struct dentry *presto_add_ilookup_dentry(struct dentry *parent, - struct dentry *real) -{ - struct inode *inode = real->d_inode; - struct dentry *de; - char buf[32]; - char *ptr = buf; - struct dentry *inodir; - struct presto_dentry_data *dd; - - inodir = lookup_one_len("..iopen..", parent, strlen("..iopen..")); - if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) { - CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__); - return NULL; - } - inodir->d_inode->i_op = &presto_dir_iops; - - snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation); - - de = lookup_one_len(ptr, inodir, strlen(ptr)); - if (!de || IS_ERR(de)) { - CERROR("%s: bad ...ino lookup %ld\n", - __FUNCTION__, PTR_ERR(de)); - dput(inodir); - return NULL; - } - - dd = presto_d2d(real); - if (!dd) - BUG(); - - /* already exists */ - if (de->d_inode) - BUG(); -#if 0 - if (de->d_inode != inode ) { - CERROR("XX de->d_inode %ld, inode %ld\n", - de->d_inode->i_ino, inode->i_ino); - BUG(); - } - if (dd->dd_inodentry) { - CERROR("inodentry exists %ld \n", inode->i_ino); - BUG(); - } - dput(inodir); - return de; - } -#endif - - if (presto_d2d(de)) - BUG(); - - atomic_inc(&inode->i_count); - de->d_op = &presto_dentry_ops; - d_add(de, inode); - if (!de->d_op) - CERROR("DD: no ops dentry %p, dd %p\n", de, dd); - dd->dd_inodentry = de; - dd->dd_count++; - de->d_fsdata = dd; - - dput(inodir); - return de; -} - -struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) -{ - int rc = 0; - struct dentry *de; - struct presto_cache *cache; - int minor; - ino_t ino; - unsigned int generation; - struct inode_operations *iops; - int is_ilookup = 0; - - ENTRY; - cache = presto_get_cache(dir); - if (cache == NULL) { - CERROR("InterMezzo BUG: no cache in presto_lookup " - "(dir ino: %ld)!\n", dir->i_ino); - EXIT; - return NULL; - } - minor = presto_c2m(cache); - - iops = filter_c2cdiops(cache->cache_filter); - if (!iops || !iops->lookup) { - CERROR("InterMezzo BUG: filesystem has no lookup\n"); - EXIT; - return NULL; - } - - - CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n", - dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name, - ISLENTO(minor)); - - if (dentry->d_fsdata) - CERROR("DD -- BAD dentry %p has data\n", dentry); - - dentry->d_fsdata = NULL; -#if 0 - if (ext2_check_for_iopen(dir, dentry)) - de = NULL; - else { -#endif - if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) { - de = cache->cache_filter->o_trops->tr_ilookup - (dir, dentry, ino, generation); - is_ilookup = 1; - } else - de = iops->lookup(dir, dentry, nd); -#if 0 - } -#endif - - if ( IS_ERR(de) ) { - CERROR("dentry lookup error %ld\n", PTR_ERR(de)); - return de; - } - - /* some file systems have no read_inode: set methods here */ - if (dentry->d_inode) - presto_set_ops(dentry->d_inode, cache->cache_filter); - - filter_setup_dentry_ops(cache->cache_filter, - dentry->d_op, &presto_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - - /* In lookup we will tolerate EROFS return codes from presto_set_dd - * to placate NFS. EROFS indicates that a fileset was not found but - * we should still be able to continue through a lookup. - * Anything else is a hard error and must be returned to VFS. */ - if (!is_ilookup) - rc = presto_set_dd(dentry); - if (rc && rc != -EROFS) { - CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n", - dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc); - return ERR_PTR(rc); - } - - EXIT; - return NULL; -} - -static inline int presto_check_set_fsdata (struct dentry *de) -{ - if (presto_d2d(de) == NULL) { -#ifdef PRESTO_NO_NFS - CERROR("dentry without fsdata: %p: %*s\n", de, - de->d_name.len, de->d_name.name); - BUG(); -#endif - return presto_set_dd (de); - } - - return 0; -} - -int presto_setattr(struct dentry *de, struct iattr *iattr) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct lento_vfs_context info = { 0, {0}, 0 }; - - ENTRY; - - error = presto_prep(de, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - if (!iattr->ia_valid) - CDEBUG(D_INODE, "presto_setattr: iattr is not valid\n"); - - CDEBUG(D_INODE, "valid %#x, mode %#o, uid %u, gid %u, size %Lu, " - "atime %lu mtime %lu ctime %lu flags %d\n", - iattr->ia_valid, iattr->ia_mode, iattr->ia_uid, iattr->ia_gid, - iattr->ia_size, iattr->ia_atime.tv_sec, iattr->ia_mtime.tv_sec, - iattr->ia_ctime.tv_sec, iattr->ia_attr_flags); - - if ( presto_get_permit(de->d_inode) < 0 ) { - EXIT; - return -EROFS; - } - - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_setattr(fset, de, iattr, &info); - presto_put_permit(de->d_inode); - return error; -} - -/* - * Now the meat: the fs operations that require journaling - * - * - * XXX: some of these need modifications for hierarchical filesets - */ - -int presto_prep(struct dentry *dentry, struct presto_cache **cache, - struct presto_file_set **fset) -{ - int rc; - - /* NFS might pass us dentries which have not gone through lookup. - * Test and set d_fsdata for such dentries - */ - rc = presto_check_set_fsdata (dentry); - if (rc) return rc; - - *fset = presto_fset(dentry); - if ( *fset == NULL ) { - CERROR("No file set for dentry at %p: %*s\n", dentry, - dentry->d_name.len, dentry->d_name.name); - return -EROFS; - } - - *cache = (*fset)->fset_cache; - if ( *cache == NULL ) { - CERROR("PRESTO: BAD, BAD: cannot find cache\n"); - return -EBADF; - } - - CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n", - (*cache)->cache_flags, (*fset)->fset_flags); - if( presto_is_read_only(*fset) ) { - CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n", - presto_c2m(*cache)); - return -EROFS; - } - return 0; -} - -static int presto_create(struct inode * dir, struct dentry * dentry, int mode, - struct nameidata *nd) -{ - int error; - struct presto_cache *cache; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - struct presto_file_set *fset; - - ENTRY; - error = presto_check_set_fsdata(dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - presto_unlock(dir); - - /* Does blocking and non-blocking behavious need to be - checked for. Without blocking (return 1), the permit - was acquired without reintegration - */ - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - presto_relock_sem(dir); - parent = dentry->d_parent; - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_create(fset, parent, dentry, mode, &info); - - presto_relock_other(dir); - presto_put_permit(dir); - EXIT; - return error; -} - -static int presto_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry) -{ - int error; - struct presto_cache *cache, *new_cache; - struct presto_file_set *fset, *new_fset; - struct dentry *parent = new_dentry->d_parent; - struct lento_vfs_context info; - - ENTRY; - error = presto_prep(old_dentry, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - error = presto_check_set_fsdata(new_dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset); - if ( error ) { - EXIT; - return error; - } - - if (fset != new_fset) { - EXIT; - return -EXDEV; - } - - presto_unlock(dir); - if ( presto_get_permit(old_dentry->d_inode) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - presto_relock_sem(dir); - parent = new_dentry->d_parent; - - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_link(fset, old_dentry, parent, - new_dentry, &info); - -#if 0 - /* XXX for links this is not right */ - if (cache->cache_filter->o_trops->tr_add_ilookup ) { - struct dentry *d; - d = cache->cache_filter->o_trops->tr_add_ilookup - (dir->i_sb->s_root, new_dentry, 1); - } -#endif - - presto_relock_other(dir); - presto_put_permit(dir); - presto_put_permit(old_dentry->d_inode); - return error; -} - -static int presto_mkdir(struct inode * dir, struct dentry * dentry, int mode) -{ - int error; - struct presto_file_set *fset; - struct presto_cache *cache; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - - ENTRY; - - error = presto_check_set_fsdata(dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - presto_unlock(dir); - - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - - presto_relock_sem(dir); - parent = dentry->d_parent; - error = presto_do_mkdir(fset, parent, dentry, mode, &info); - presto_relock_other(dir); - presto_put_permit(dir); - return error; -} - - - -static int presto_symlink(struct inode *dir, struct dentry *dentry, - const char *name) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - - ENTRY; - error = presto_check_set_fsdata(dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - presto_unlock(dir); - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - presto_relock_sem(dir); - parent = dentry->d_parent; - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_symlink(fset, parent, dentry, name, &info); - presto_relock_other(dir); - presto_put_permit(dir); - return error; -} - -int presto_unlink(struct inode *dir, struct dentry *dentry) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - - ENTRY; - error = presto_check_set_fsdata(dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - presto_unlock(dir); - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - presto_relock_sem(dir); - parent = dentry->d_parent; - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - - error = presto_do_unlink(fset, parent, dentry, &info); - - presto_relock_other(dir); - presto_put_permit(dir); - return error; -} - -static int presto_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - - ENTRY; - CDEBUG(D_FILE, "prepping presto\n"); - error = presto_check_set_fsdata(dentry); - - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - CDEBUG(D_FILE, "unlocking\n"); - /* We need to dget() before the dput in double_unlock, to ensure we - * still have dentry references. double_lock doesn't do dget for us. - */ - if (d_unhashed(dentry)) - d_rehash(dentry); - // double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); - up(&dentry->d_inode->i_sem); - up(&dir->i_sem); - - CDEBUG(D_FILE, "getting permit\n"); - if ( presto_get_permit(parent->d_inode) < 0 ) { - EXIT; - down(&dir->i_sem); - down(&dentry->d_inode->i_sem); - // double_down(&dir->i_sem, &dentry->d_inode->i_sem); - // double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); - - lock_kernel(); - return -EROFS; - } - CDEBUG(D_FILE, "locking\n"); - - down(&dir->i_sem); - down(&dentry->d_inode->i_sem); - parent = dentry->d_parent; - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_rmdir(fset, parent, dentry, &info); - presto_put_permit(parent->d_inode); - lock_kernel(); - EXIT; - return error; -} - -static int presto_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct dentry *parent = dentry->d_parent; - struct lento_vfs_context info; - - if (!old_valid_dev(rdev)) - return -EINVAL; - - ENTRY; - error = presto_check_set_fsdata(dentry); - if ( error ) { - EXIT; - return error; - } - - error = presto_prep(dentry->d_parent, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - presto_unlock(dir); - if ( presto_get_permit(dir) < 0 ) { - EXIT; - presto_fulllock(dir); - return -EROFS; - } - - presto_relock_sem(dir); - parent = dentry->d_parent; - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info); - presto_relock_other(dir); - presto_put_permit(dir); - EXIT; - return error; -} - - - -// XXX this can be optimized: renamtes across filesets only require -// multiple KML records, but can locally be executed normally. -int presto_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - int error; - struct presto_cache *cache, *new_cache; - struct presto_file_set *fset, *new_fset; - struct lento_vfs_context info; - struct dentry *old_parent = old_dentry->d_parent; - struct dentry *new_parent = new_dentry->d_parent; - int triple; - - ENTRY; - error = presto_prep(old_dentry, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - error = presto_prep(new_parent, &new_cache, &new_fset); - if ( error ) { - EXIT; - return error; - } - - if ( fset != new_fset ) { - EXIT; - return -EXDEV; - } - - /* We need to do dget before the dput in double_unlock, to ensure we - * still have dentry references. double_lock doesn't do dget for us. - */ - - triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)? - 1:0; - - unlock_rename(new_dentry->d_parent, old_dentry->d_parent); - - if ( presto_get_permit(old_dir) < 0 ) { - EXIT; - return -EROFS; - } - if ( presto_get_permit(new_dir) < 0 ) { - EXIT; - return -EROFS; - } - - lock_rename(new_dentry->d_parent, old_dentry->d_parent); - memset(&info, 0, sizeof(info)); - if (!ISLENTO(presto_c2m(cache))) - info.flags = LENTO_FL_KML; - info.flags |= LENTO_FL_IGNORE_TIME; - error = do_rename(fset, old_parent, old_dentry, new_parent, - new_dentry, &info); - - presto_put_permit(new_dir); - presto_put_permit(old_dir); - return error; -} - -/* basically this allows the ilookup processes access to all files for - * reading, while not making ilookup totally insecure. This could all - * go away if we could set the CAP_DAC_READ_SEARCH capability for the client. - */ -/* If posix acls are available, the underlying cache fs will export the - * appropriate permission function. Thus we do not worry here about ACLs - * or EAs. -SHP - */ -int presto_permission(struct inode *inode, int mask, struct nameidata *nd) -{ - unsigned short mode = inode->i_mode; - struct presto_cache *cache; - int rc; - - ENTRY; - if ( presto_can_ilookup() && !(mask & S_IWOTH)) { - CDEBUG(D_CACHE, "ilookup on %ld OK\n", inode->i_ino); - EXIT; - return 0; - } - - cache = presto_get_cache(inode); - - if ( cache ) { - /* we only override the file/dir permission operations */ - struct inode_operations *fiops = filter_c2cfiops(cache->cache_filter); - struct inode_operations *diops = filter_c2cdiops(cache->cache_filter); - - if ( S_ISREG(mode) && fiops && fiops->permission ) { - EXIT; - return fiops->permission(inode, mask, nd); - } - if ( S_ISDIR(mode) && diops && diops->permission ) { - EXIT; - return diops->permission(inode, mask, nd); - } - } - - /* The cache filesystem doesn't have its own permission function, - * so we call the default one. - */ - rc = vfs_permission(inode, mask); - - EXIT; - return rc; -} - - -int presto_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - char buf[1024]; - struct izo_ioctl_data *data = NULL; - struct presto_dentry_data *dd; - int rc; - - ENTRY; - - /* Try the filesystem's ioctl first, and return if it succeeded. */ - dd = presto_d2d(file->f_dentry); - if (dd && dd->dd_fset) { - int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl; - rc = -ENOTTY; - if (cache_ioctl) - rc = cache_ioctl(inode, file, cmd, arg); - if (rc != -ENOTTY) { - EXIT; - return rc; - } - } - - if (current->euid != 0 && current->euid != izo_authorized_uid) { - EXIT; - return -EPERM; - } - - memset(buf, 0, sizeof(buf)); - - if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { - CERROR("intermezzo ioctl: data error\n"); - return -EINVAL; - } - data = (struct izo_ioctl_data *)buf; - - switch(cmd) { - case IZO_IOC_REINTKML: { - int rc; - int cperr; - rc = kml_reint_rec(file, data); - - EXIT; - cperr = copy_to_user((char *)arg, data, sizeof(*data)); - if (cperr) { - CERROR("WARNING: cperr %d\n", cperr); - rc = -EFAULT; - } - return rc; - } - - case IZO_IOC_GET_RCVD: { - struct izo_rcvd_rec rec; - struct presto_file_set *fset; - int rc; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - rc = izo_rcvd_get(&rec, fset, data->ioc_uuid); - if (rc < 0) { - EXIT; - return rc; - } - - EXIT; - return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0; - } - - case IZO_IOC_REPSTATUS: { - __u64 client_kmlsize; - struct izo_rcvd_rec *lr_client; - struct izo_rcvd_rec rec; - struct presto_file_set *fset; - int minor; - int rc; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - client_kmlsize = data->ioc_kmlsize; - lr_client = (struct izo_rcvd_rec *) data->ioc_pbuf1; - - rc = izo_repstatus(fset, client_kmlsize, - lr_client, &rec); - if (rc < 0) { - EXIT; - return rc; - } - - EXIT; - return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0; - } - - case IZO_IOC_GET_CHANNEL: { - struct presto_file_set *fset; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - - data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor; - CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); - EXIT; - return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0; - } - - case IZO_IOC_SET_IOCTL_UID: - izo_authorized_uid = data->ioc_uid; - EXIT; - return 0; - - case IZO_IOC_SET_PID: - rc = izo_psdev_setpid(data->ioc_dev); - EXIT; - return rc; - - case IZO_IOC_SET_CHANNEL: - rc = izo_psdev_setchannel(file, data->ioc_dev); - EXIT; - return rc; - - case IZO_IOC_GET_KML_SIZE: { - struct presto_file_set *fset; - __u64 kmlsize; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - - kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off; - - EXIT; - return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0; - } - - case IZO_IOC_PURGE_FILE_DATA: { - struct presto_file_set *fset; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - - rc = izo_purge_file(fset, data->ioc_inlbuf1); - EXIT; - return rc; - } - - case IZO_IOC_GET_FILEID: { - rc = izo_get_fileid(file, data); - EXIT; - if (rc) - return rc; - return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0; - } - - case IZO_IOC_SET_FILEID: { - rc = izo_set_fileid(file, data); - EXIT; - if (rc) - return rc; - return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0; - } - - case IZO_IOC_ADJUST_LML: { - struct lento_vfs_context *info; - info = (struct lento_vfs_context *)data->ioc_inlbuf1; - rc = presto_adjust_lml(file, info); - EXIT; - return rc; - } - - case IZO_IOC_CONNECT: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_connect(minor, data->ioc_ino, - data->ioc_generation, data->ioc_uuid, - data->ioc_flags); - EXIT; - return rc; - } - - case IZO_IOC_GO_FETCH_KML: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_go_fetch_kml(minor, fset->fset_name, - data->ioc_uuid, data->ioc_kmlsize); - EXIT; - return rc; - } - - case IZO_IOC_REVOKE_PERMIT: - if (data->ioc_flags) - rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid); - else - rc = izo_revoke_permit(file->f_dentry, NULL); - EXIT; - return rc; - - case IZO_IOC_CLEAR_FSET: - rc = izo_clear_fsetroot(file->f_dentry); - EXIT; - return rc; - - case IZO_IOC_CLEAR_ALL_FSETS: { - struct presto_file_set *fset; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - - rc = izo_clear_all_fsetroots(fset->fset_cache); - EXIT; - return rc; - } - - case IZO_IOC_SET_FSET: - /* - * Mark this dentry as being a fileset root. - */ - rc = presto_set_fsetroot_from_ioc(file->f_dentry, - data->ioc_inlbuf1, - data->ioc_flags); - EXIT; - return rc; - - - case IZO_IOC_MARK: { - int res = 0; /* resulting flags - returned to user */ - int error; - - CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n", - file->f_dentry->d_inode->i_ino, data->ioc_and_flag, - data->ioc_or_flag, data->ioc_mark_what); - - switch (data->ioc_mark_what) { - case MARK_DENTRY: - error = izo_mark_dentry(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, &res); - break; - case MARK_FSET: - error = izo_mark_fset(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, &res); - break; - case MARK_CACHE: - error = izo_mark_cache(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, &res); - break; - case MARK_GETFL: { - int fflags, cflags; - data->ioc_and_flag = 0xffffffff; - data->ioc_or_flag = 0; - error = izo_mark_dentry(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, &res); - if (error) - break; - error = izo_mark_fset(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, &fflags); - if (error) - break; - error = izo_mark_cache(file->f_dentry, - data->ioc_and_flag, - data->ioc_or_flag, - &cflags); - - if (error) - break; - data->ioc_and_flag = fflags; - data->ioc_or_flag = cflags; - break; - } - default: - error = -EINVAL; - } - - if (error) { - EXIT; - return error; - } - data->ioc_mark_what = res; - CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n", - file->f_dentry->d_inode->i_ino, data->ioc_and_flag, - data->ioc_or_flag, data->ioc_mark_what); - - EXIT; - return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0; - } -#if 0 - case IZO_IOC_CLIENT_MAKE_BRANCH: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_client_make_branch(minor, fset->fset_name, - data->ioc_inlbuf1, - data->ioc_inlbuf2); - EXIT; - return rc; - } -#endif - case IZO_IOC_SERVER_MAKE_BRANCH: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - izo_upc_server_make_branch(minor, data->ioc_inlbuf1); - EXIT; - return 0; - } - case IZO_IOC_SET_KMLSIZE: { - struct presto_file_set *fset; - int minor; - struct izo_rcvd_rec rec; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid, - data->ioc_kmlsize); - - if (rc != 0) { - EXIT; - return rc; - } - - rc = izo_rcvd_get(&rec, fset, data->ioc_uuid); - if (rc == -EINVAL) { - /* We don't know anything about this uuid yet; no - * worries. */ - memset(&rec, 0, sizeof(rec)); - } else if (rc <= 0) { - CERROR("InterMezzo: error reading last_rcvd: %d\n", rc); - EXIT; - return rc; - } - rec.lr_remote_offset = data->ioc_kmlsize; - rc = izo_rcvd_write(fset, &rec); - if (rc <= 0) { - CERROR("InterMezzo: error writing last_rcvd: %d\n", rc); - EXIT; - return rc; - } - EXIT; - return rc; - } - case IZO_IOC_BRANCH_UNDO: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_branch_undo(minor, fset->fset_name, - data->ioc_inlbuf1); - EXIT; - return rc; - } - case IZO_IOC_BRANCH_REDO: { - struct presto_file_set *fset; - int minor; - - fset = presto_fset(file->f_dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - minor = presto_f2m(fset); - - rc = izo_upc_branch_redo(minor, fset->fset_name, - data->ioc_inlbuf1); - EXIT; - return rc; - } - - default: - EXIT; - return -ENOTTY; - - } - EXIT; - return 0; -} - -struct file_operations presto_dir_fops = { - .ioctl = presto_ioctl -}; - -struct inode_operations presto_dir_iops = { - .create = presto_create, - .lookup = presto_lookup, - .link = presto_link, - .unlink = presto_unlink, - .symlink = presto_symlink, - .mkdir = presto_mkdir, - .rmdir = presto_rmdir, - .mknod = presto_mknod, - .rename = presto_rename, - .permission = presto_permission, - .setattr = presto_setattr, -#ifdef CONFIG_FS_EXT_ATTR - .set_ext_attr = presto_set_ext_attr, -#endif -}; - - diff --git a/fs/intermezzo/ext_attr.c b/fs/intermezzo/ext_attr.c deleted file mode 100644 index be91417c1..000000000 --- a/fs/intermezzo/ext_attr.c +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Tacit Networks, Inc. - * Author: Shirish H. Phatak - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Extended attribute handling for presto. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#ifdef CONFIG_FS_EXT_ATTR -#include - -extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset, - unsigned long value); - - -/* VFS interface */ -/* XXX! Fixme test for user defined attributes */ -int presto_set_ext_attr(struct inode *inode, - const char *name, void *buffer, - size_t buffer_len, int flags) -{ - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct lento_vfs_context info; - struct dentry *dentry; - int minor = presto_i2m(inode); - char *buf = NULL; - - ENTRY; - if (minor < 0) { - EXIT; - return -1; - } - - if ( ISLENTO(minor) ) { - EXIT; - return -EINVAL; - } - - /* BAD...vfs should really pass down the dentry to use, especially - * since every other operation in iops does. But for now - * we do a reverse mapping from inode to the first dentry - */ - if (list_empty(&inode->i_dentry)) { - CERROR("No alias for inode %d\n", (int) inode->i_ino); - EXIT; - return -EINVAL; - } - - dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); - - error = presto_prep(dentry, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - if ((buffer != NULL) && (buffer_len != 0)) { - /* If buffer is a user space pointer copy it to kernel space - * and reset the flag. We do this since the journal functions need - * access to the contents of the buffer, and the file system - * does not care. When we actually invoke the function, we remove - * the EXT_ATTR_FLAG_USER flag. - * - * XXX:Check if the "fs does not care" assertion is always true -SHP - * (works for ext3) - */ - if (flags & EXT_ATTR_FLAG_USER) { - PRESTO_ALLOC(buf, buffer_len); - if (!buf) { - CERROR("InterMezzo: out of memory!!!\n"); - return -ENOMEM; - } - error = copy_from_user(buf, buffer, buffer_len); - if (error) - return -EFAULT; - } else - buf = buffer; - } else - buf = buffer; - - if ( presto_get_permit(inode) < 0 ) { - EXIT; - if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) - PRESTO_FREE(buf, buffer_len); - return -EROFS; - } - - /* Simulate presto_setup_info */ - memset(&info, 0, sizeof(info)); - /* For now redundant..but we keep it around just in case */ - info.flags = LENTO_FL_IGNORE_TIME; - if (!ISLENTO(cache->cache_psdev->uc_minor)) - info.flags |= LENTO_FL_KML; - - /* We pass in the kernel space pointer and reset the - * EXT_ATTR_FLAG_USER flag. - * See comments above. - */ - /* Note that mode is already set by VFS so we send in a NULL */ - error = presto_do_set_ext_attr(fset, dentry, name, buf, - buffer_len, flags & ~EXT_ATTR_FLAG_USER, - NULL, &info); - presto_put_permit(inode); - - if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) - PRESTO_FREE(buf, buffer_len); - EXIT; - return error; -} - -/* Lento Interface */ -/* XXX: ignore flags? We should be forcing these operations through? -SHP*/ -int lento_set_ext_attr(const char *path, const char *name, - void *buffer, size_t buffer_len, int flags, mode_t mode, - struct lento_vfs_context *info) -{ - int error; - char * pathname; - struct nameidata nd; - struct dentry *dentry; - struct presto_file_set *fset; - - ENTRY; - lock_kernel(); - - pathname=getname(path); - error = PTR_ERR(pathname); - if (IS_ERR(pathname)) { - EXIT; - goto exit; - } - - /* Note that ext_attrs apply to both files and directories..*/ - error=presto_walk(pathname,&nd); - if (error) - goto exit; - dentry = nd.dentry; - - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit_dentry; - } - - if (buffer==NULL) buffer_len=0; - - error = presto_do_set_ext_attr(fset, dentry, name, buffer, - buffer_len, flags, &mode, info); -exit_dentry: - path_release(&nd); -exit_path: - putname(pathname); -exit: - unlock_kernel(); - return error; -} - -#endif /*CONFIG_FS_EXT_ATTR*/ diff --git a/fs/intermezzo/file.c b/fs/intermezzo/file.c deleted file mode 100644 index f6256427b..000000000 --- a/fs/intermezzo/file.c +++ /dev/null @@ -1,534 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory. - * Copyright (C) 2000, 2001 Tacit Networks, Inc. - * Copyright (C) 2000 Peter J. Braam - * Copyright (C) 2001 Mountain View Data, Inc. - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This file manages file I/O - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" -/* - * these are initialized in super.c - */ -extern int presto_permission(struct inode *inode, int mask, struct nameidata *nd); - - -static int presto_open_upcall(int minor, struct dentry *de) -{ - int rc = 0; - char *path, *buffer; - struct presto_file_set *fset; - int pathlen; - struct lento_vfs_context info; - struct presto_dentry_data *dd = presto_d2d(de); - - PRESTO_ALLOC(buffer, PAGE_SIZE); - if ( !buffer ) { - CERROR("PRESTO: out of memory!\n"); - return -ENOMEM; - } - fset = presto_fset(de); - path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE); - pathlen = MYPATHLEN(buffer, path); - - CDEBUG(D_FILE, "de %p, dd %p\n", de, dd); - if (dd->remote_ino == 0) { - rc = presto_get_fileid(minor, fset, de); - } - memset (&info, 0, sizeof(info)); - if (dd->remote_ino > 0) { - info.remote_ino = dd->remote_ino; - info.remote_generation = dd->remote_generation; - } else - CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc, - (unsigned long long) dd->remote_ino); - - rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info); - PRESTO_FREE(buffer, PAGE_SIZE); - return rc; -} - -static inline int open_check_dod(struct file *file, - struct presto_file_set *fset) -{ - int gen, is_iopen = 0, minor; - struct presto_cache *cache = fset->fset_cache; - ino_t inum; - - minor = presto_c2m(cache); - - if ( ISLENTO(minor) ) { - CDEBUG(D_CACHE, "is lento, not doing DOD.\n"); - return 0; - } - - /* Files are only ever opened by inode during backfetches, when by - * definition we have the authoritative copy of the data. No DOD. */ - is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen); - - if (is_iopen) { - CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n"); - return 0; - } - - if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) { - CDEBUG(D_CACHE, "fileset not on demand.\n"); - return 0; - } - - if (file->f_flags & O_TRUNC) { - CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n"); - return 0; - } - - if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) { - CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n"); - return 0; - } - - if (presto_chk(file->f_dentry, PRESTO_DATA)) { - CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n"); - return 0; - } - - if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) { - CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n"); - return 0; - } - - return 1; -} - -static int presto_file_open(struct inode *inode, struct file *file) -{ - int rc = 0; - struct file_operations *fops; - struct presto_cache *cache; - struct presto_file_set *fset; - struct presto_file_data *fdata; - int writable = (file->f_flags & (O_RDWR | O_WRONLY)); - int minor, i; - - ENTRY; - - if (presto_prep(file->f_dentry, &cache, &fset) < 0) { - EXIT; - return -EBADF; - } - - minor = presto_c2m(cache); - - CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n", - presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino, - ISLENTO(minor)); - - if ( !ISLENTO(minor) && (file->f_flags & O_RDWR || - file->f_flags & O_WRONLY)) { - CDEBUG(D_CACHE, "calling presto_get_permit\n"); - if ( presto_get_permit(inode) < 0 ) { - EXIT; - return -EROFS; - } - presto_put_permit(inode); - } - - if (open_check_dod(file, fset)) { - CDEBUG(D_CACHE, "presto_open_upcall\n"); - CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry); - presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA); - rc = presto_open_upcall(minor, file->f_dentry); - if (rc) { - EXIT; - CERROR("%s: returning error %d\n", __FUNCTION__, rc); - return rc; - } - - } - - /* file was truncated upon open: do not refetch */ - if (file->f_flags & O_TRUNC) { - CDEBUG(D_CACHE, "setting DATA, ATTR\n"); - presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA); - } - - fops = filter_c2cffops(cache->cache_filter); - if ( fops->open ) { - CDEBUG(D_CACHE, "calling fs open\n"); - rc = fops->open(inode, file); - - if (rc) { - EXIT; - return rc; - } - } - - if (writable) { - PRESTO_ALLOC(fdata, sizeof(*fdata)); - if (!fdata) { - EXIT; - return -ENOMEM; - } - /* LOCK: XXX check that the kernel lock protects this alloc */ - fdata->fd_do_lml = 0; - fdata->fd_bytes_written = 0; - fdata->fd_fsuid = current->fsuid; - fdata->fd_fsgid = current->fsgid; - fdata->fd_mode = file->f_dentry->d_inode->i_mode; - fdata->fd_uid = file->f_dentry->d_inode->i_uid; - fdata->fd_gid = file->f_dentry->d_inode->i_gid; - fdata->fd_ngroups = current->group_info->ngroups; - for (i=0 ; i < current->group_info->ngroups ; i++) - fdata->fd_groups[i] = GROUP_AT(current->group_info,i); - if (!ISLENTO(minor)) - fdata->fd_info.flags = LENTO_FL_KML; - else { - /* this is for the case of DOD, - reint_close will adjust flags if needed */ - fdata->fd_info.flags = 0; - } - - presto_getversion(&fdata->fd_version, inode); - file->private_data = fdata; - } else { - file->private_data = NULL; - } - - EXIT; - return 0; -} - -int presto_adjust_lml(struct file *file, struct lento_vfs_context *info) -{ - struct presto_file_data *fdata = - (struct presto_file_data *) file->private_data; - - if (!fdata) { - EXIT; - return -EINVAL; - } - - memcpy(&fdata->fd_info, info, sizeof(*info)); - EXIT; - return 0; -} - - -static int presto_file_release(struct inode *inode, struct file *file) -{ - int rc; - struct file_operations *fops; - struct presto_cache *cache; - struct presto_file_set *fset; - struct presto_file_data *fdata = - (struct presto_file_data *)file->private_data; - ENTRY; - - rc = presto_prep(file->f_dentry, &cache, &fset); - if ( rc ) { - EXIT; - return rc; - } - - fops = filter_c2cffops(cache->cache_filter); - if (fops && fops->release) - rc = fops->release(inode, file); - - CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n", - ISLENTO(cache->cache_psdev->uc_minor), - cache->cache_psdev->uc_minor, rc, fdata); - - /* this file was modified: ignore close errors, write KML */ - if (fdata && fdata->fd_do_lml) { - /* XXX: remove when lento gets file granularity cd */ - if ( presto_get_permit(inode) < 0 ) { - EXIT; - return -EROFS; - } - - fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime; - rc = presto_do_close(fset, file); - presto_put_permit(inode); - } - - if (!rc && fdata) { - PRESTO_FREE(fdata, sizeof(*fdata)); - file->private_data = NULL; - } - - EXIT; - return rc; -} - -static void presto_apply_write_policy(struct file *file, - struct presto_file_set *fset, loff_t res) -{ - struct presto_file_data *fdata = - (struct presto_file_data *)file->private_data; - struct presto_cache *cache = fset->fset_cache; - struct presto_version new_file_ver; - int error; - struct rec_info rec; - - /* Here we do a journal close after a fixed or a specified - amount of KBytes, currently a global parameter set with - sysctl. If files are open for a long time, this gives added - protection. (XXX todo: per cache, add ioctl, handle - journaling in a thread, add more options etc.) - */ - - if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) && - (!ISLENTO(cache->cache_psdev->uc_minor))) { - fdata->fd_bytes_written += res; - - if (fdata->fd_bytes_written >= fset->fset_file_maxio) { - presto_getversion(&new_file_ver, - file->f_dentry->d_inode); - /* This is really heavy weight and should be fixed - ASAP. At most we should be recording the number - of bytes written and not locking the kernel, - wait for permits, etc, on the write path. SHP - */ - lock_kernel(); - if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) { - EXIT; - /* we must be disconnected, not to worry */ - unlock_kernel(); - return; - } - error = presto_journal_close(&rec, fset, fdata, - file->f_dentry, - &fdata->fd_version, - &new_file_ver); - presto_put_permit(file->f_dentry->d_inode); - unlock_kernel(); - if ( error ) { - CERROR("presto_close: cannot journal close\n"); - /* XXX these errors are really bad */ - /* panic(); */ - return; - } - fdata->fd_bytes_written = 0; - } - } -} - -static ssize_t presto_file_write(struct file *file, const char *buf, - size_t size, loff_t *off) -{ - struct rec_info rec; - int error; - struct presto_cache *cache; - struct presto_file_set *fset; - struct file_operations *fops; - ssize_t res; - int do_lml_here; - void *handle = NULL; - unsigned long blocks; - struct presto_file_data *fdata; - loff_t res_size; - - error = presto_prep(file->f_dentry, &cache, &fset); - if ( error ) { - EXIT; - return error; - } - - blocks = (size >> file->f_dentry->d_inode->i_sb->s_blocksize_bits) + 1; - /* XXX 3 is for ext2 indirect blocks ... */ - res_size = 2 * PRESTO_REQHIGH + ((blocks+3) - << file->f_dentry->d_inode->i_sb->s_blocksize_bits); - - error = presto_reserve_space(fset->fset_cache, res_size); - CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); - if ( error ) { - EXIT; - return -ENOSPC; - } - - CDEBUG(D_INODE, "islento %d, minor: %d\n", - ISLENTO(cache->cache_psdev->uc_minor), - cache->cache_psdev->uc_minor); - - /* - * XXX this lock should become a per inode lock when - * Vinny's changes are in; we could just use i_sem. - */ - read_lock(&fset->fset_lml.fd_lock); - fdata = (struct presto_file_data *)file->private_data; - do_lml_here = size && (fdata->fd_do_lml == 0) && - !presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL); - - if (do_lml_here) - fdata->fd_do_lml = 1; - read_unlock(&fset->fset_lml.fd_lock); - - /* XXX - There might be a bug here. We need to make - absolutely sure that the ext3_file_write commits - after our transaction that writes the LML record. - Nesting the file write helps if new blocks are allocated. - */ - res = 0; - if (do_lml_here) { - struct presto_version file_version; - /* handle different space reqs from file system below! */ - handle = presto_trans_start(fset, file->f_dentry->d_inode, - KML_OPCODE_WRITE); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, res_size); - CERROR("presto_write: no space for transaction\n"); - return -ENOSPC; - } - - presto_getversion(&file_version, file->f_dentry->d_inode); - res = presto_write_lml_close(&rec, fset, file, - fdata->fd_info.remote_ino, - fdata->fd_info.remote_generation, - &fdata->fd_info.remote_version, - &file_version); - fdata->fd_lml_offset = rec.offset; - if ( res ) { - CERROR("intermezzo: PANIC failed to write LML\n"); - *(int *)0 = 1; - EXIT; - goto exit_write; - } - presto_trans_commit(fset, handle); - } - - fops = filter_c2cffops(cache->cache_filter); - res = fops->write(file, buf, size, off); - if ( res != size ) { - CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); - } - - if ( (res > 0) && fdata ) - presto_apply_write_policy(file, fset, res); - - exit_write: - presto_release_space(fset->fset_cache, res_size); - return res; -} - -struct file_operations presto_file_fops = { - .write = presto_file_write, - .open = presto_file_open, - .release = presto_file_release, - .ioctl = presto_ioctl -}; - -struct inode_operations presto_file_iops = { - .permission = presto_permission, - .setattr = presto_setattr, -#ifdef CONFIG_FS_EXT_ATTR - .set_ext_attr = presto_set_ext_attr, -#endif -}; - -/* FIXME: I bet we want to add a lock here and in presto_file_open. */ -int izo_purge_file(struct presto_file_set *fset, char *file) -{ -#if 0 - void *handle = NULL; - char *path = NULL; - struct nameidata nd; - struct dentry *dentry; - int rc = 0, len; - loff_t oldsize; - - /* FIXME: not mtpt it's gone */ - len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1; - PRESTO_ALLOC(path, len + 1); - if (path == NULL) - return -1; - - sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file); - rc = izo_lookup_file(fset, path, &nd); - if (rc) - goto error; - dentry = nd.dentry; - - /* FIXME: take a lock here */ - - if (dentry->d_inode->i_atime.tv_sec > get_seconds() - 5) { - /* We lost the race; this file was accessed while we were doing - * ioctls and lookups and whatnot. */ - rc = -EBUSY; - goto error_unlock; - } - - /* FIXME: Check if this file is open. */ - - handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC); - if (IS_ERR(handle)) { - rc = -ENOMEM; - goto error_unlock; - } - - /* FIXME: Write LML record */ - - oldsize = dentry->d_inode->i_size; - rc = izo_do_truncate(fset, dentry, 0, oldsize); - if (rc != 0) - goto error_clear; - rc = izo_do_truncate(fset, dentry, oldsize, 0); - if (rc != 0) - goto error_clear; - - error_clear: - /* FIXME: clear LML record */ - - error_unlock: - /* FIXME: release the lock here */ - - error: - if (handle != NULL && !IS_ERR(handle)) - presto_trans_commit(fset, handle); - if (path != NULL) - PRESTO_FREE(path, len + 1); - return rc; -#else - return 0; -#endif -} diff --git a/fs/intermezzo/fileset.c b/fs/intermezzo/fileset.c deleted file mode 100644 index 9db8cab51..000000000 --- a/fs/intermezzo/fileset.c +++ /dev/null @@ -1,674 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Managing filesets - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry) -{ - if (presto_d2d(dentry) == NULL) { - EXIT; - return NULL; - } - return presto_d2d(dentry)->dd_fset; -} - -/* find the fileset dentry for this dentry */ -struct presto_file_set *presto_fset(struct dentry *de) -{ - struct dentry *fsde; - ENTRY; - if ( !de->d_inode ) { - /* FIXME: is this ok to be NULL? */ - CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n", - de->d_name.len, de->d_name.name); - } - for (fsde = de;; fsde = fsde->d_parent) { - if ( presto_dentry2fset(fsde) ) { - EXIT; - return presto_dentry2fset(fsde); - } - if (fsde->d_parent == fsde) - break; - } - EXIT; - return NULL; -} - -int presto_get_lastrecno(char *path, off_t *recno) -{ - struct nameidata nd; - struct presto_file_set *fset; - struct dentry *dentry; - int error; - ENTRY; - - error = presto_walk(path, &nd); - if (error) { - EXIT; - return error; - } - - dentry = nd.dentry; - - error = -ENXIO; - if ( !presto_ispresto(dentry->d_inode) ) { - EXIT; - goto kml_out; - } - - error = -EINVAL; - if ( ! presto_dentry2fset(dentry)) { - EXIT; - goto kml_out; - } - - fset = presto_dentry2fset(dentry); - if (!fset) { - EXIT; - goto kml_out; - } - error = 0; - *recno = fset->fset_kml.fd_recno; - - kml_out: - path_release(&nd); - return error; -} - -static char * _izo_make_path(char *fsetname, char *name) -{ - char *path = NULL; - int len; - - len = strlen("/.intermezzo/") + strlen(fsetname) - + 1 + strlen(name) + 1; - - PRESTO_ALLOC(path, len); - if (path == NULL) - return NULL; - - sprintf(path, "/.intermezzo/%s/%s", fsetname, name); - - return path; -} - -char * izo_make_path(struct presto_file_set *fset, char *name) -{ - return _izo_make_path(fset->fset_name, name); -} - -static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) -{ - char *path; - struct file *f; - int error; - ENTRY; - - path = _izo_make_path(fsetname, name); - if (path == NULL) { - EXIT; - return ERR_PTR(-ENOMEM); - } - - CDEBUG(D_INODE, "opening file %s\n", path); - f = filp_open(path, flags, mode); - error = PTR_ERR(f); - if (IS_ERR(f)) { - CDEBUG(D_INODE, "Error %d\n", error); - } - - PRESTO_FREE(path, strlen(path)); - - EXIT; - return f; - -} - -struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) -{ - return _izo_fset_open(fset->fset_name, name, flags, mode); -} - - - -/* - * note: this routine "pins" a dentry for a fileset root - */ -int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname, - unsigned int flags) -{ - struct presto_file_set *fset = NULL; - struct presto_cache *cache; - int error; - struct file *fset_root; - struct dentry *dentry; - - ENTRY; - - fset_root = _izo_fset_open(fsetname, "ROOT", O_RDONLY, 000); - if (IS_ERR(fset_root)) { - CERROR("Can't open %s/ROOT\n", fsetname); - EXIT; - error = PTR_ERR(fset_root); - goto out; - } - dentry = dget(fset_root->f_dentry); - filp_close(fset_root, NULL); - - dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op; - dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop; - dentry->d_op = ioctl_dentry->d_op; - fset = presto_dentry2fset(dentry); - if (fset && (fset->fset_dentry == dentry) ) { - CERROR("Fsetroot already set (inode %ld)\n", - dentry->d_inode->i_ino); - /* XXX: ignore because clear_fsetroot is broken */ -#if 0 - dput(dentry); - EXIT; - error = -EEXIST; - goto out; -#endif - } - - cache = presto_get_cache(dentry->d_inode); - if (!cache) { - CERROR("No cache found for inode %ld\n", - dentry->d_inode->i_ino); - EXIT; - error = -ENODEV; - goto out_free; - } - - PRESTO_ALLOC(fset, sizeof(*fset)); - if ( !fset ) { - CERROR("No memory allocating fset for %s\n", fsetname); - EXIT; - error = -ENOMEM; - goto out_free; - } - CDEBUG(D_INODE, "fset at %p\n", fset); - - CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n", - dentry->d_inode->i_ino, fsetname); - - fset->fset_mnt = mntget(current->fs->pwdmnt); - fset->fset_cache = cache; - fset->fset_dentry = dentry; - fset->fset_name = strdup(fsetname); - fset->fset_chunkbits = CHUNK_BITS; - fset->fset_flags = flags; - fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; - fset->fset_permit_lock = SPIN_LOCK_UNLOCKED; - PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024); - if (fset->fset_reint_buf == NULL) { - EXIT; - error = -ENOMEM; - goto out_free; - } - init_waitqueue_head(&fset->fset_permit_queue); - - if (presto_d2d(dentry) == NULL) { - dentry->d_fsdata = izo_alloc_ddata(); - } - if (presto_d2d(dentry) == NULL) { - CERROR("InterMezzo: %s: no memory\n", __FUNCTION__); - EXIT; - error = -ENOMEM; - goto out_free; - } - presto_d2d(dentry)->dd_fset = fset; - list_add(&fset->fset_list, &cache->cache_fset_list); - - error = izo_init_kml_file(fset, &fset->fset_kml); - if ( error ) { - EXIT; - CDEBUG(D_JOURNAL, "Error init_kml %d\n", error); - goto out_list_del; - } - - error = izo_init_lml_file(fset, &fset->fset_lml); - if ( error ) { - int rc; - EXIT; - rc = izo_log_close(&fset->fset_kml); - CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc); - goto out_list_del; - } - - /* init_last_rcvd_file could trigger a presto_file_write(), which - * requires that the lml structure be initialized. -phil */ - error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd); - if ( error ) { - int rc; - EXIT; - rc = izo_log_close(&fset->fset_kml); - rc = izo_log_close(&fset->fset_lml); - CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc); - goto out_list_del; - } - - CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p," - "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n", - fset, dentry, fset->fset_dentry, fset->fset_name, cache, - presto_d2d(dentry)->dd_fset); - - EXIT; - return 0; - - out_list_del: - list_del(&fset->fset_list); - presto_d2d(dentry)->dd_fset = NULL; - out_free: - if (fset) { - mntput(fset->fset_mnt); - if (fset->fset_reint_buf != NULL) - PRESTO_FREE(fset->fset_reint_buf, 64 * 1024); - PRESTO_FREE(fset, sizeof(*fset)); - } - dput(dentry); - out: - return error; -} - -static int izo_cleanup_fset(struct presto_file_set *fset) -{ - int error; - struct presto_cache *cache; - - ENTRY; - - CERROR("Cleaning up fset %s\n", fset->fset_name); - - error = izo_log_close(&fset->fset_kml); - if (error) - CERROR("InterMezzo: Closing kml for fset %s: %d\n", - fset->fset_name, error); - error = izo_log_close(&fset->fset_lml); - if (error) - CERROR("InterMezzo: Closing lml for fset %s: %d\n", - fset->fset_name, error); - error = izo_log_close(&fset->fset_rcvd); - if (error) - CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n", - fset->fset_name, error); - - cache = fset->fset_cache; - - list_del(&fset->fset_list); - - presto_d2d(fset->fset_dentry)->dd_fset = NULL; - dput(fset->fset_dentry); - mntput(fset->fset_mnt); - - PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1); - PRESTO_FREE(fset->fset_reint_buf, 64 * 1024); - PRESTO_FREE(fset, sizeof(*fset)); - EXIT; - return error; -} - -int izo_clear_fsetroot(struct dentry *dentry) -{ - struct presto_file_set *fset; - - ENTRY; - - fset = presto_dentry2fset(dentry); - if (!fset) { - EXIT; - return -EINVAL; - } - - izo_cleanup_fset(fset); - EXIT; - return 0; -} - -int izo_clear_all_fsetroots(struct presto_cache *cache) -{ - struct presto_file_set *fset; - struct list_head *tmp,*tmpnext; - int error; - - error = 0; - tmp = &cache->cache_fset_list; - tmpnext = tmp->next; - while ( tmpnext != &cache->cache_fset_list) { - tmp = tmpnext; - tmpnext = tmp->next; - fset = list_entry(tmp, struct presto_file_set, fset_list); - - error = izo_cleanup_fset(fset); - if (error) - break; - } - return error; -} - -static struct vfsmount *izo_alloc_vfsmnt(void) -{ - struct vfsmount *mnt; - PRESTO_ALLOC(mnt, sizeof(*mnt)); - if (mnt) { - memset(mnt, 0, sizeof(struct vfsmount)); - atomic_set(&mnt->mnt_count,1); - INIT_LIST_HEAD(&mnt->mnt_hash); - INIT_LIST_HEAD(&mnt->mnt_child); - INIT_LIST_HEAD(&mnt->mnt_mounts); - INIT_LIST_HEAD(&mnt->mnt_list); - } - return mnt; -} - - -static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt, - struct run_ctxt *save) -{ - struct run_ctxt new; - - mnt->mnt_root = root; - mnt->mnt_sb = root->d_inode->i_sb; - unlock_super(mnt->mnt_sb); - - new.rootmnt = mnt; - new.root = root; - new.pwdmnt = mnt; - new.pwd = root; - new.fsuid = 0; - new.fsgid = 0; - new.fs = get_fs(); - /* XXX where can we get the groups from? */ - new.group_info = groups_alloc(0); - - push_ctxt(save, &new); -} - -static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) -{ - lock_super(mnt->mnt_sb); - pop_ctxt(save); -} - -static int izo_simple_mkdir(struct dentry *dir, char *name, int mode) -{ - struct dentry *dchild; - int err; - ENTRY; - - dchild = lookup_one_len(name, dir, strlen(name)); - if (IS_ERR(dchild)) { - EXIT; - return PTR_ERR(dchild); - } - - if (dchild->d_inode) { - dput(dchild); - EXIT; - return -EEXIST; - } - - err = vfs_mkdir(dir->d_inode, dchild, mode); - dput(dchild); - - EXIT; - return err; -} - -static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt) -{ - struct dentry *dchild; - int err; - ENTRY; - - dchild = lookup_one_len(name, dir, strlen(name)); - if (IS_ERR(dchild)) { - EXIT; - return PTR_ERR(dchild); - } - - if (dchild->d_inode) { - dput(dchild); - EXIT; - return -EEXIST; - } - - err = vfs_symlink(dir->d_inode, dchild, tgt); - dput(dchild); - - EXIT; - return err; -} - -/* - * run set_fsetroot in chroot environment - */ -int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname, - unsigned int flags) -{ - int rc; - struct presto_cache *cache; - struct vfsmount *mnt; - struct run_ctxt save; - - if (root != root->d_inode->i_sb->s_root) { - CERROR ("IOC_SET_FSET must be called on mount point\n"); - return -ENODEV; - } - - cache = presto_get_cache(root->d_inode); - mnt = cache->cache_vfsmount; - if (!mnt) { - EXIT; - return -ENOMEM; - } - - izo_setup_ctxt(root, mnt, &save); - rc = presto_set_fsetroot(root, fsetname, flags); - izo_cleanup_ctxt(mnt, &save); - return rc; -} - -/* XXX: this function should detect if fsetname is already in use for - the cache under root -*/ -int izo_prepare_fileset(struct dentry *root, char *fsetname) -{ - int err; - struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; - struct presto_cache *cache; - struct vfsmount *mnt; - struct run_ctxt save; - - cache = presto_get_cache(root->d_inode); - mnt = cache->cache_vfsmount = izo_alloc_vfsmnt(); - if (!mnt) { - EXIT; - return -ENOMEM; - } - - if (!fsetname) - fsetname = "rootfset"; - - izo_setup_ctxt(root, mnt, &save); - - err = izo_simple_mkdir(root, ".intermezzo", 0755); - CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); - - err = izo_simple_mkdir(root, "..iopen..", 0755); - CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); - - dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen..")); - if (IS_ERR(dotiopen)) { - EXIT; - goto out; - } - dotiopen->d_inode->i_op = &presto_dir_iops; - dput(dotiopen); - - - dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo")); - if (IS_ERR(dotizo)) { - EXIT; - goto out; - } - - - err = izo_simple_mkdir(dotizo, fsetname, 0755); - CDEBUG(D_CACHE, "mkdir err %d\n", err); - - /* XXX find the dentry of the root of the fileset (root for now) */ - fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname)); - if (IS_ERR(fsetdir)) { - EXIT; - goto out; - } - - err = izo_simple_symlink(fsetdir, "ROOT", "../.."); - - /* XXX read flags from flags file */ - err = presto_set_fsetroot(root, fsetname, 0); - CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); - - out: - if (dotizo && !IS_ERR(dotizo)) - dput(dotizo); - if (fsetdir && !IS_ERR(fsetdir)) - dput(fsetdir); - izo_cleanup_ctxt(mnt, &save); - return err; -} - -int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data) -{ - int rc = 0; - struct presto_cache *cache; - struct vfsmount *mnt; - struct run_ctxt save; - struct nameidata nd; - struct dentry *dentry; - struct presto_dentry_data *dd; - struct dentry *root; - char *buf = NULL; - - ENTRY; - - - root = dir->f_dentry; - - /* actually, needs to be called on ROOT of fset, not mount point - if (root != root->d_inode->i_sb->s_root) { - CERROR ("IOC_SET_FSET must be called on mount point\n"); - return -ENODEV; - } - */ - - cache = presto_get_cache(root->d_inode); - mnt = cache->cache_vfsmount; - if (!mnt) { - EXIT; - return -ENOMEM; - } - - izo_setup_ctxt(root, mnt, &save); - - PRESTO_ALLOC(buf, data->ioc_plen1); - if (!buf) { - rc = -ENOMEM; - EXIT; - goto out; - } - if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { - rc = -EFAULT; - EXIT; - goto out; - } - - rc = presto_walk(buf, &nd); - if (rc) { - CERROR("Unable to open: %s\n", buf); - EXIT; - goto out; - } - dentry = nd.dentry; - if (!dentry) { - CERROR("no dentry!\n"); - rc = -EINVAL; - EXIT; - goto out_close; - } - dd = presto_d2d(dentry); - if (!dd) { - CERROR("no dentry_data!\n"); - rc = -EINVAL; - EXIT; - goto out_close; - } - - CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd); - - if (dd->remote_ino != 0) { - CERROR("remote_ino already set? %Lx:%Lx\n", - (unsigned long long) dd->remote_ino, - (unsigned long long) dd->remote_generation); - rc = 0; - EXIT; - goto out_close; - } - - - CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, - buf, - (unsigned long long) data->ioc_ino, - (unsigned long long) data->ioc_generation); - dd->remote_ino = data->ioc_ino; - dd->remote_generation = data->ioc_generation; - - EXIT; - out_close: - path_release(&nd); - out: - if (buf) - PRESTO_FREE(buf, data->ioc_plen1); - izo_cleanup_ctxt(mnt, &save); - return rc; -} diff --git a/fs/intermezzo/inode.c b/fs/intermezzo/inode.c deleted file mode 100644 index fda188bab..000000000 --- a/fs/intermezzo/inode.c +++ /dev/null @@ -1,179 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1996 Peter J. Braam and - * Michael Callahan - * Copyright (C) 1999 Carnegie Mellon University - * Rewritten for Linux 2.1. Peter Braam - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Super block/filesystem wide operations - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -extern void presto_free_cache(struct presto_cache *); - -void presto_set_ops(struct inode *inode, struct filter_fs *filter) -{ - ENTRY; - - if (!inode || is_bad_inode(inode)) - return; - - if (S_ISREG(inode->i_mode)) { - if ( !filter_c2cfiops(filter) ) { - filter_setup_file_ops(filter, - inode, &presto_file_iops, - &presto_file_fops); - } - inode->i_op = filter_c2ufiops(filter); - inode->i_fop = filter_c2uffops(filter); - CDEBUG(D_INODE, "set file methods for %ld to %p\n", - inode->i_ino, inode->i_op); - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = filter_c2udiops(filter); - inode->i_fop = filter_c2udfops(filter); - CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n", - inode->i_ino, inode->i_op, inode->i_fop->ioctl); - } else if (S_ISLNK(inode->i_mode)) { - if ( !filter_c2csiops(filter)) { - filter_setup_symlink_ops(filter, - inode, - &presto_sym_iops, - &presto_sym_fops); - } - inode->i_op = filter_c2usiops(filter); - inode->i_fop = filter_c2usfops(filter); - CDEBUG(D_INODE, "set link methods for %ld to %p\n", - inode->i_ino, inode->i_op); - } - EXIT; -} - -void presto_read_inode(struct inode *inode) -{ - struct presto_cache *cache; - - cache = presto_get_cache(inode); - if ( !cache ) { - CERROR("PRESTO: BAD, BAD: cannot find cache\n"); - make_bad_inode(inode); - return ; - } - - filter_c2csops(cache->cache_filter)->read_inode(inode); - - CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n", - inode->i_ino, inode->i_gid); - - presto_set_ops(inode, cache->cache_filter); - /* XXX handle special inodes here or not - probably not? */ -} - -static void presto_put_super(struct super_block *sb) -{ - struct presto_cache *cache; - struct upc_channel *channel; - struct super_operations *sops; - struct list_head *lh; - int err; - - ENTRY; - cache = presto_cache_find(sb); - if (!cache) { - EXIT; - goto exit; - } - channel = &izo_channels[presto_c2m(cache)]; - sops = filter_c2csops(cache->cache_filter); - err = izo_clear_all_fsetroots(cache); - if (err) { - CERROR("%s: err %d\n", __FUNCTION__, err); - } - PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount)); - - /* look at kill_super - fsync_super is not exported GRRR but - probably not needed */ - unlock_super(sb); - shrink_dcache_parent(cache->cache_root); - dput(cache->cache_root); - //fsync_super(sb); - lock_super(sb); - - if (sops->write_super) - sops->write_super(sb); - - if (sops->put_super) - sops->put_super(sb); - - /* free any remaining async upcalls when the filesystem is unmounted */ - spin_lock(&channel->uc_lock); - lh = channel->uc_pending.next; - while ( lh != &channel->uc_pending) { - struct upc_req *req; - req = list_entry(lh, struct upc_req, rq_chain); - - /* assignment must be here: we are about to free &lh */ - lh = lh->next; - if ( ! (req->rq_flags & REQ_ASYNC) ) - continue; - list_del(&(req->rq_chain)); - PRESTO_FREE(req->rq_data, req->rq_bufsize); - PRESTO_FREE(req, sizeof(struct upc_req)); - } - list_del(&cache->cache_channel_list); - spin_unlock(&channel->uc_lock); - - presto_free_cache(cache); - -exit: - CDEBUG(D_MALLOC, "after umount: kmem %ld, vmem %ld\n", - presto_kmemory, presto_vmemory); - return ; -} - -struct super_operations presto_super_ops = { - .read_inode = presto_read_inode, - .put_super = presto_put_super, -}; - - -/* symlinks can be chowned */ -struct inode_operations presto_sym_iops = { - .setattr = presto_setattr -}; - -/* NULL for now */ -struct file_operations presto_sym_fops; diff --git a/fs/intermezzo/intermezzo_fs.h b/fs/intermezzo/intermezzo_fs.h deleted file mode 100644 index 350036517..000000000 --- a/fs/intermezzo/intermezzo_fs.h +++ /dev/null @@ -1,923 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001, 2002 Cluster File Systems, Inc. - * Copyright (C) 2001 Tacitus Systems, Inc. - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __INTERMEZZO_FS_H_ -#define __INTERMEZZO_FS_H_ 1 - -#include "intermezzo_lib.h" -#include "intermezzo_idl.h" - - -#ifdef __KERNEL__ -typedef __u8 uuid_t[16]; -#else -# include -#endif - -struct lento_vfs_context { - __u64 kml_offset; - struct timespec updated_time; - __u64 remote_ino; - __u64 remote_generation; - __u32 slot_offset; - __u32 recno; - __u32 flags; - uuid_t uuid; - struct presto_version remote_version; -}; - -#ifdef __KERNEL__ -# include -# include -# include -# include -# include -# include - -/* fixups for fs.h */ -# ifndef fs_down -# define fs_down(sem) down(sem) -# endif - -# ifndef fs_up -# define fs_up(sem) up(sem) -# endif - -# define KML_IDLE 0 -# define KML_DECODE 1 -# define KML_OPTIMIZE 2 -# define KML_REINT 3 - -# define KML_OPEN_REINT 0x0100 -# define KML_REINT_BEGIN 0x0200 -# define KML_BACKFETCH 0x0400 -# define KML_REINT_END 0x0800 -# define KML_CLOSE_REINT 0x1000 -# define KML_REINT_MAXBUF (64 * 1024) - -# define CACHE_CLIENT_RO 0x4 -# define CACHE_LENTO_RO 0x8 - -/* global variables */ -extern int presto_debug; -extern int presto_print_entry; -extern long presto_kmemory; -extern long presto_vmemory; - -# define PRESTO_DEBUG -# ifdef PRESTO_DEBUG -/* debugging masks */ -# define D_SUPER 1 -# define D_INODE 2 -# define D_FILE 4 -# define D_CACHE 8 /* cache debugging */ -# define D_MALLOC 16 /* print malloc, de-alloc information */ -# define D_JOURNAL 32 -# define D_UPCALL 64 /* up and downcall debugging */ -# define D_PSDEV 128 -# define D_PIOCTL 256 -# define D_SPECIAL 512 -# define D_TIMING 1024 -# define D_DOWNCALL 2048 -# define D_KML 4096 -# define D_FSDATA 8192 - -# define CDEBUG(mask, format, a...) \ - do { \ - if (presto_debug & mask) { \ - printk("(%s:%s,l. %d %d): " format, __FILE__, \ - __FUNCTION__, __LINE__, current->pid \ - , ## a); \ - } \ - } while (0) - -#define CERROR(format, a...) \ -do { \ - printk("(%s:%s,l. %d %d): " format, __FILE__, __FUNCTION__, \ - __LINE__, current->pid , ## a); \ -} while (0) - -# define ENTRY \ - if (presto_print_entry) \ - printk("Process %d entered %s\n", current->pid, __FUNCTION__) - -# define EXIT \ - if (presto_print_entry) \ - printk("Process %d leaving %s at %d\n", current->pid, \ - __FUNCTION__, __LINE__) - -# define presto_kmem_inc(ptr, size) presto_kmemory += (size) -# define presto_kmem_dec(ptr, size) presto_kmemory -= (size) -# define presto_vmem_inc(ptr, size) presto_vmemory += (size) -# define presto_vmem_dec(ptr, size) presto_vmemory -= (size) -# else /* !PRESTO_DEBUG */ -# define CDEBUG(mask, format, a...) do {} while (0) -# define ENTRY do {} while (0) -# define EXIT do {} while (0) -# define presto_kmem_inc(ptr, size) do {} while (0) -# define presto_kmem_dec(ptr, size) do {} while (0) -# define presto_vmem_inc(ptr, size) do {} while (0) -# define presto_vmem_dec(ptr, size) do {} while (0) -# endif /* PRESTO_DEBUG */ - - -struct run_ctxt { - struct vfsmount *pwdmnt; - struct dentry *pwd; - struct vfsmount *rootmnt; - struct dentry *root; - uid_t fsuid; - gid_t fsgid; - mm_segment_t fs; - struct group_info * group_info; -/* int ngroups; - gid_t groups[NGROUPS];*/ - -}; - -static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new) -{ - save->fs = get_fs(); - save->pwd = dget(current->fs->pwd); - save->pwdmnt = mntget(current->fs->pwdmnt); - save->fsgid = current->fsgid; - save->fsuid = current->fsuid; - save->root = current->fs->root; - save->rootmnt = current->fs->rootmnt; - save->group_info = current->group_info; -/* save->ngroups = current->ngroups; - for (i = 0; i< current->ngroups; i++) - save->groups[i] = current->groups[i];*/ - - set_fs(new->fs); - lock_kernel(); - set_fs_pwd(current->fs, new->pwdmnt, new->pwd); - if (new->root) - set_fs_root(current->fs, new->rootmnt, new->root); - unlock_kernel(); - current->fsuid = new->fsuid; - current->fsgid = new->fsgid; - /*if (new->ngroups > 0) { - current->ngroups = new->ngroups; - for (i = 0; i< new->ngroups; i++) - current->groups[i] = new->groups[i]; - }*/ - current->group_info = new->group_info; - -} - -static inline void pop_ctxt(struct run_ctxt *saved) -{ - set_fs(saved->fs); - lock_kernel(); - set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd); - if (saved->root) - set_fs_root(current->fs, saved->rootmnt, saved->root); - unlock_kernel(); - current->fsuid = saved->fsuid; - current->fsgid = saved->fsgid; - current->group_info = saved->group_info; -/* - current->ngroups = saved->ngroups; - for (i = 0; i< saved->ngroups; i++) - current->groups[i] = saved->groups[i]; -*/ - mntput(saved->pwdmnt); - dput(saved->pwd); -} - -static inline struct presto_dentry_data *presto_d2d(struct dentry *dentry) -{ - return (struct presto_dentry_data *)(dentry->d_fsdata); -} - -struct presto_cache { - spinlock_t cache_lock; - loff_t cache_reserved; - struct vfsmount *cache_vfsmount; - struct super_block *cache_sb; - struct dentry *cache_root; - struct list_head cache_chain; /* for the dev/cache hash */ - - int cache_flags; - - char *cache_type; /* filesystem type of cache */ - struct filter_fs *cache_filter; - - struct upc_channel *cache_psdev; /* points to channel used */ - struct list_head cache_channel_list; - struct list_head cache_fset_list; /* filesets mounted in cache */ -}; - -struct presto_log_fd { - rwlock_t fd_lock; - loff_t fd_offset; /* offset where next record should go */ - struct file *fd_file; - int fd_truncating; - unsigned int fd_recno; /* last recno written */ - struct list_head fd_reservations; -}; - -/* file sets */ -# define CHUNK_BITS 16 - -struct presto_file_set { - struct list_head fset_list; - struct presto_log_fd fset_kml; - struct presto_log_fd fset_lml; - struct presto_log_fd fset_rcvd; - struct list_head *fset_clients; /* cache of clients */ - struct dentry *fset_dentry; - struct vfsmount *fset_mnt; - struct presto_cache *fset_cache; - - unsigned int fset_lento_recno; /* last recno mentioned to lento */ - loff_t fset_lento_off; /* last offset mentioned to lento */ - loff_t fset_kml_logical_off; /* logical offset of kml file byte 0 */ - char * fset_name; - - int fset_flags; - int fset_chunkbits; - char *fset_reint_buf; /* temporary buffer holds kml during reint */ - - spinlock_t fset_permit_lock; - int fset_permit_count; - int fset_permit_upcall_count; - /* This queue is used both for processes waiting for the kernel to give - * up the permit as well as processes waiting for the kernel to be given - * the permit, depending on the state of FSET_HASPERMIT. */ - wait_queue_head_t fset_permit_queue; - - loff_t fset_file_maxio; /* writing more than this causes a close */ - unsigned long int kml_truncate_size; -}; - -/* This is the default number of bytes written before a close is recorded*/ -#define FSET_DEFAULT_MAX_FILEIO (1024<<10) - -struct dentry *presto_tmpfs_ilookup(struct inode *dir, struct dentry *dentry, - ino_t ino, unsigned int generation); -struct dentry *presto_iget_ilookup(struct inode *dir, struct dentry *dentry, - ino_t ino, unsigned int generation); -struct dentry *presto_add_ilookup_dentry(struct dentry *parent, - struct dentry *real); - -struct journal_ops { - int (*tr_all_data)(struct inode *); - loff_t (*tr_avail)(struct presto_cache *fset, struct super_block *); - void *(*tr_start)(struct presto_file_set *, struct inode *, int op); - void (*tr_commit)(struct presto_file_set *, void *handle); - void (*tr_journal_data)(struct inode *); - struct dentry *(*tr_ilookup)(struct inode *dir, struct dentry *dentry, ino_t ino, unsigned int generation); - struct dentry *(*tr_add_ilookup)(struct dentry *parent, struct dentry *real); -}; - -extern struct journal_ops presto_ext2_journal_ops; -extern struct journal_ops presto_ext3_journal_ops; -extern struct journal_ops presto_tmpfs_journal_ops; -extern struct journal_ops presto_xfs_journal_ops; -extern struct journal_ops presto_reiserfs_journal_ops; -extern struct journal_ops presto_obdfs_journal_ops; - -# define LENTO_FL_KML 0x0001 -# define LENTO_FL_EXPECT 0x0002 -# define LENTO_FL_VFSCHECK 0x0004 -# define LENTO_FL_JUSTLOG 0x0008 -# define LENTO_FL_WRITE_KML 0x0010 -# define LENTO_FL_CANCEL_LML 0x0020 -# define LENTO_FL_WRITE_EXPECT 0x0040 -# define LENTO_FL_IGNORE_TIME 0x0080 -# define LENTO_FL_TOUCH_PARENT 0x0100 -# define LENTO_FL_TOUCH_NEWOBJ 0x0200 -# define LENTO_FL_SET_DDFILEID 0x0400 - -struct presto_cache *presto_get_cache(struct inode *inode); -int presto_sprint_mounts(char *buf, int buflen, int minor); -struct presto_file_set *presto_fset(struct dentry *de); -int presto_journal(struct dentry *dentry, char *buf, size_t size); -int presto_fwrite(struct file *file, const char *str, int len, loff_t *off); -int presto_ispresto(struct inode *); - -/* super.c */ -extern struct file_system_type presto_fs_type; -extern int init_intermezzo_fs(void); - -/* fileset.c */ -extern int izo_prepare_fileset(struct dentry *root, char *fsetname); -char * izo_make_path(struct presto_file_set *fset, char *name); -struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode); - -/* psdev.c */ -int izo_psdev_get_free_channel(void); -int presto_psdev_init(void); -int izo_psdev_setpid(int minor); -extern void presto_psdev_cleanup(void); -int presto_lento_up(int minor); -int izo_psdev_setchannel(struct file *file, int fd); - -/* inode.c */ -extern struct super_operations presto_super_ops; -void presto_set_ops(struct inode *inode, struct filter_fs *filter); - -/* dcache.c */ -void presto_frob_dop(struct dentry *de); -char *presto_path(struct dentry *dentry, struct dentry *root, - char *buffer, int buflen); -struct presto_dentry_data *izo_alloc_ddata(void); -int presto_set_dd(struct dentry *); -int presto_init_ddata_cache(void); -void presto_cleanup_ddata_cache(void); -extern struct dentry_operations presto_dentry_ops; - -/* dir.c */ -extern struct inode_operations presto_dir_iops; -extern struct inode_operations presto_file_iops; -extern struct inode_operations presto_sym_iops; -extern struct file_operations presto_dir_fops; -extern struct file_operations presto_file_fops; -extern struct file_operations presto_sym_fops; -int presto_setattr(struct dentry *de, struct iattr *iattr); -int presto_settime(struct presto_file_set *fset, struct dentry *newobj, - struct dentry *parent, struct dentry *target, - struct lento_vfs_context *ctx, int valid); -int presto_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - -extern int presto_ilookup_uid; -# define PRESTO_ILOOKUP_MAGIC "...ino:" -# define PRESTO_ILOOKUP_SEP ':' -int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation); -struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd); - -struct presto_dentry_data { - int dd_count; /* how mnay dentries are using this dentry */ - struct presto_file_set *dd_fset; - struct dentry *dd_inodentry; - loff_t dd_kml_offset; - int dd_flags; - __u64 remote_ino; - __u64 remote_generation; -}; - -struct presto_file_data { - int fd_do_lml; - loff_t fd_lml_offset; - size_t fd_bytes_written; - /* authorization related data of file at open time */ - uid_t fd_uid; - gid_t fd_gid; - mode_t fd_mode; - /* identification data of calling process */ - uid_t fd_fsuid; - gid_t fd_fsgid; - int fd_ngroups; - gid_t fd_groups[NGROUPS_SMALL]; - /* information how to complete the close operation */ - struct lento_vfs_context fd_info; - struct presto_version fd_version; -}; - -/* presto.c and Lento::Downcall */ - -int presto_walk(const char *name, struct nameidata *nd); -int izo_clear_fsetroot(struct dentry *dentry); -int izo_clear_all_fsetroots(struct presto_cache *cache); -int presto_get_kmlsize(char *path, __u64 *size); -int presto_get_lastrecno(char *path, off_t *size); -int presto_set_fsetroot(struct dentry *dentry, char *fsetname, - unsigned int flags); -int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname, - unsigned int flags); -int presto_is_read_only(struct presto_file_set *); -int presto_truncate_lml(struct presto_file_set *fset); -int lento_write_lml(char *path, - __u64 remote_ino, - __u32 remote_generation, - __u32 remote_version, - struct presto_version *remote_file_version); -int lento_complete_closes(char *path); -int presto_f2m(struct presto_file_set *fset); -int presto_prep(struct dentry *, struct presto_cache **, - struct presto_file_set **); -/* cache.c */ -extern struct presto_cache *presto_cache_init(void); -extern void presto_cache_add(struct presto_cache *cache); -extern void presto_cache_init_hash(void); - -struct presto_cache *presto_cache_find(struct super_block *sb); - -#define PRESTO_REQLOW (3 * 4096) -#define PRESTO_REQHIGH (6 * 4096) -void presto_release_space(struct presto_cache *cache, loff_t req); -int presto_reserve_space(struct presto_cache *cache, loff_t req); - -#define PRESTO_DATA 0x00000002 /* cached data is valid */ -#define PRESTO_ATTR 0x00000004 /* attributes cached */ -#define PRESTO_DONT_JOURNAL 0x00000008 /* things like .intermezzo/ */ - -struct presto_file_set *presto_path2fileset(const char *name); -int izo_revoke_permit(struct dentry *, uuid_t uuid); -int presto_chk(struct dentry *dentry, int flag); -void presto_set(struct dentry *dentry, int flag); -int presto_get_permit(struct inode *inode); -int presto_put_permit(struct inode *inode); -int presto_set_max_kml_size(const char *path, unsigned long max_size); -int izo_mark_dentry(struct dentry *dentry, int and, int or, int *res); -int izo_mark_cache(struct dentry *dentry, int and_bits, int or_bits, int *); -int izo_mark_fset(struct dentry *dentry, int and_bits, int or_bits, int *); -void presto_getversion(struct presto_version *pv, struct inode *inode); -int presto_i2m(struct inode *inode); -int presto_c2m(struct presto_cache *cache); - - -/* file.c */ -int izo_purge_file(struct presto_file_set *fset, char *file); -int presto_adjust_lml(struct file *file, struct lento_vfs_context *info); - -/* journal.c */ -struct rec_info { - loff_t offset; - int size; - int recno; - int is_kml; -}; - -void presto_trans_commit(struct presto_file_set *fset, void *handle); -void *presto_trans_start(struct presto_file_set *fset, struct inode *inode, - int op); -int presto_fread(struct file *file, char *str, int len, loff_t *off); -int presto_clear_lml_close(struct presto_file_set *fset, - loff_t lml_offset); -int presto_complete_lml(struct presto_file_set *fset); -int presto_read_kml_logical_offset(struct rec_info *recinfo, - struct presto_file_set *fset); -int presto_write_kml_logical_offset(struct presto_file_set *fset); -struct file *presto_copy_kml_tail(struct presto_file_set *fset, - unsigned long int start); -int presto_finish_kml_truncate(struct presto_file_set *fset, - unsigned long int offset); -int izo_lookup_file(struct presto_file_set *fset, char *path, - struct nameidata *nd); -int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry, - loff_t length, loff_t size_check); -int izo_log_close(struct presto_log_fd *logfd); -struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags); -int izo_init_kml_file(struct presto_file_set *, struct presto_log_fd *); -int izo_init_lml_file(struct presto_file_set *, struct presto_log_fd *); -int izo_init_last_rcvd_file(struct presto_file_set *, struct presto_log_fd *); - -/* vfs.c */ - -/* Extra data needed in the KML for rollback operations; this structure is - * passed around during the KML-writing process. */ -struct izo_rollback_data { - __u32 rb_mode; - __u32 rb_rdev; - __u64 rb_uid; - __u64 rb_gid; -}; - -int presto_write_last_rcvd(struct rec_info *recinfo, - struct presto_file_set *fset, - struct lento_vfs_context *info); -void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb); -int presto_do_close(struct presto_file_set *fset, struct file *file); -int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry, - struct iattr *iattr, struct lento_vfs_context *info); -int presto_do_create(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, - struct lento_vfs_context *info); -int presto_do_link(struct presto_file_set *fset, struct dentry *dir, - struct dentry *old_dentry, struct dentry *new_dentry, - struct lento_vfs_context *info); -int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, struct lento_vfs_context *info); -int presto_do_symlink(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, const char *name, - struct lento_vfs_context *info); -int presto_do_mkdir(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, - struct lento_vfs_context *info); -int presto_do_rmdir(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, struct lento_vfs_context *info); -int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, dev_t dev, - struct lento_vfs_context *info); -int do_rename(struct presto_file_set *fset, struct dentry *old_dir, - struct dentry *old_dentry, struct dentry *new_dir, - struct dentry *new_dentry, struct lento_vfs_context *info); -int presto_do_statfs (struct presto_file_set *fset, - struct kstatfs * buf); - -int lento_setattr(const char *name, struct iattr *iattr, - struct lento_vfs_context *info); -int lento_create(const char *name, int mode, struct lento_vfs_context *info); -int lento_link(const char *oldname, const char *newname, - struct lento_vfs_context *info); -int lento_unlink(const char *name, struct lento_vfs_context *info); -int lento_symlink(const char *oldname,const char *newname, - struct lento_vfs_context *info); -int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info); -int lento_rmdir(const char *name, struct lento_vfs_context *info); -int lento_mknod(const char *name, int mode, dev_t dev, - struct lento_vfs_context *info); -int lento_rename(const char *oldname, const char *newname, - struct lento_vfs_context *info); -int lento_iopen(const char *name, ino_t ino, unsigned int generation,int flags); - -/* journal.c */ - -#define JOURNAL_PAGE_SZ PAGE_SIZE - -int presto_no_journal(struct presto_file_set *fset); -int journal_fetch(int minor); -int presto_log(struct presto_file_set *fset, struct rec_info *rec, - const char *buf, size_t size, - const char *string1, int len1, - const char *string2, int len2, - const char *string3, int len3); -int presto_get_fileid(int minor, struct presto_file_set *fset, - struct dentry *dentry); -int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, struct presto_version *old_ver, - struct izo_rollback_data *, struct iattr *iattr); -int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *new_file_ver, int mode); -int presto_journal_link(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *src, struct dentry *tgt, - struct presto_version *tgt_dir_ver, - struct presto_version *new_link_ver); -int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dir, - struct presto_version *tgt_dir_ver, - struct presto_version *old_file_ver, - struct izo_rollback_data *, struct dentry *dentry, - char *old_target, int old_targetlen); -int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, const char *target, - struct presto_version *tgt_dir_ver, - struct presto_version *new_link_ver); -int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *new_dir_ver, int mode); -int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *old_dir_ver, - struct izo_rollback_data *, int len, const char *name); -int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *new_node_ver, int mode, - int dmajor, int dminor); -int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *src, struct dentry *tgt, - struct presto_version *src_dir_ver, - struct presto_version *tgt_dir_ver); -int presto_journal_open(struct rec_info *, struct presto_file_set *, - struct dentry *, struct presto_version *old_ver); -int presto_journal_close(struct rec_info *rec, struct presto_file_set *, - struct presto_file_data *, struct dentry *, - struct presto_version *old_file_ver, - struct presto_version *new_file_ver); -int presto_write_lml_close(struct rec_info *rec, - struct presto_file_set *fset, - struct file *file, - __u64 remote_ino, - __u64 remote_generation, - struct presto_version *remote_version, - struct presto_version *new_file_ver); -void presto_log_op(void *data, int len); -loff_t presto_kml_offset(struct presto_file_set *fset); - -/* upcall.c */ -#define SYNCHRONOUS 0 -#define ASYNCHRONOUS 1 -/* asynchronous calls */ -int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, - __u32 last_recno, char *fsetname); -int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, - char *fsetname); -int izo_upc_go_fetch_kml(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize); -int izo_upc_backfetch(int minor, char *path, char *fileset, - struct lento_vfs_context *); - -/* synchronous calls */ -int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, - __u32 pathlen, char *path, char *fsetname); -int izo_upc_permit(int minor, struct dentry *, __u32 pathlen, char *path, - char *fset); -int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, - struct lento_vfs_context *info); -int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16], - int client_flag); -int izo_upc_revoke_permit(int minor, char *fsetname, uuid_t uuid); -int izo_upc_set_kmlsize(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize); -int izo_upc_client_make_branch(int minor, char *fsetname); -int izo_upc_server_make_branch(int minor, char *fsetname); -int izo_upc_branch_undo(int minor, char *fsetname, char *branchname); -int izo_upc_branch_redo(int minor, char *fsetname, char *branchname); -int izo_upc_repstatus(int minor, char * fsetname, struct izo_rcvd_rec *lr_server); - -/* general mechanism */ -int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *, int async); - -/* replicator.c */ -int izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, - struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server); -int izo_rep_cache_init(struct presto_file_set *); -loff_t izo_rcvd_get(struct izo_rcvd_rec *, struct presto_file_set *, char *uuid); -loff_t izo_rcvd_write(struct presto_file_set *, struct izo_rcvd_rec *); -loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid, __u64 remote_recno, - __u64 remote_offset); - -int izo_ioctl_packlen(struct izo_ioctl_data *data); - -/* sysctl.c */ -int init_intermezzo_sysctl(void); -void cleanup_intermezzo_sysctl(void); - -/* ext_attr.c */ -/* We will be more tolerant than the default ea patch with attr name sizes and - * the size of value. If these come via VFS from the default ea patches, the - * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr. - */ -#define PRESTO_EXT_ATTR_NAME_MAX 128 -#define PRESTO_EXT_ATTR_VALUE_MAX 8192 - -#define PRESTO_ALLOC(ptr, size) \ -do { \ - long s = (size); \ - (ptr) = kmalloc(s, GFP_KERNEL); \ - if ((ptr) == NULL) \ - CERROR("IZO: out of memory at %s:%d (trying to " \ - "allocate %ld)\n", __FILE__, __LINE__, s); \ - else { \ - presto_kmem_inc((ptr), s); \ - memset((ptr), 0, s); \ - } \ - CDEBUG(D_MALLOC, "kmalloced: %ld at %p (tot %ld).\n", \ - s, (ptr), presto_kmemory); \ -} while (0) - -#define PRESTO_FREE(ptr, size) \ -do { \ - long s = (size); \ - if ((ptr) == NULL) { \ - CERROR("IZO: free NULL pointer (%ld bytes) at " \ - "%s:%d\n", s, __FILE__, __LINE__); \ - break; \ - } \ - kfree(ptr); \ - CDEBUG(D_MALLOC, "kfreed: %ld at %p (tot %ld).\n", \ - s, (ptr), presto_kmemory); \ - presto_kmem_dec((ptr), s); \ -} while (0) - -static inline int dentry_name_cmp(struct dentry *dentry, char *name) -{ - return (strlen(name) == dentry->d_name.len && - memcmp(name, dentry->d_name.name, dentry->d_name.len) == 0); -} - -static inline char *strdup(char *str) -{ - char *tmp; - tmp = kmalloc(strlen(str) + 1, GFP_KERNEL); - if (tmp) - memcpy(tmp, str, strlen(str) + 1); - - return tmp; -} - -static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data) -{ - if (data->ioc_len > (1<<30)) { - CERROR("IZO ioctl: ioc_len larger than 1<<30\n"); - return 1; - } - if (data->ioc_inllen1 > (1<<30)) { - CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n"); - return 1; - } - if (data->ioc_inllen2 > (1<<30)) { - CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n"); - return 1; - } - if (data->ioc_inlbuf1 && !data->ioc_inllen1) { - CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n"); - return 1; - } - if (data->ioc_inlbuf2 && !data->ioc_inllen2) { - CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n"); - return 1; - } - if (data->ioc_pbuf1 && !data->ioc_plen1) { - CERROR("IZO ioctl: pbuf1 pointer but 0 length\n"); - return 1; - } - if (data->ioc_pbuf2 && !data->ioc_plen2) { - CERROR("IZO ioctl: pbuf2 pointer but 0 length\n"); - return 1; - } - if (izo_ioctl_packlen(data) != data->ioc_len ) { - CERROR("IZO ioctl: packlen exceeds ioc_len\n"); - return 1; - } - if (data->ioc_inllen1 && - data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') { - CERROR("IZO ioctl: inlbuf1 not 0 terminated\n"); - return 1; - } - if (data->ioc_inllen2 && - data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2 - - 1] != '\0') { - CERROR("IZO ioctl: inlbuf2 not 0 terminated\n"); - return 1; - } - return 0; -} - -/* buffer MUST be at least the size of izo_ioctl_hdr */ -static inline int izo_ioctl_getdata(char *buf, char *end, void *arg) -{ - struct izo_ioctl_hdr *hdr; - struct izo_ioctl_data *data; - int err; - ENTRY; - - hdr = (struct izo_ioctl_hdr *)buf; - data = (struct izo_ioctl_data *)buf; - - err = copy_from_user(buf, (void *)arg, sizeof(*hdr)); - if ( err ) { - EXIT; - return err; - } - - if (hdr->ioc_version != IZO_IOCTL_VERSION) { - CERROR("IZO: version mismatch kernel vs application\n"); - return -EINVAL; - } - - if (hdr->ioc_len + buf >= end) { - CERROR("IZO: user buffer exceeds kernel buffer\n"); - return -EINVAL; - } - - if (hdr->ioc_len < sizeof(struct izo_ioctl_data)) { - CERROR("IZO: user buffer too small for ioctl\n"); - return -EINVAL; - } - - err = copy_from_user(buf, (void *)arg, hdr->ioc_len); - if ( err ) { - EXIT; - return err; - } - - if (izo_ioctl_is_invalid(data)) { - CERROR("IZO: ioctl not correctly formatted\n"); - return -EINVAL; - } - - if (data->ioc_inllen1) { - data->ioc_inlbuf1 = &data->ioc_bulk[0]; - } - - if (data->ioc_inllen2) { - data->ioc_inlbuf2 = &data->ioc_bulk[0] + - size_round(data->ioc_inllen1); - } - - EXIT; - return 0; -} - -# define MYPATHLEN(buffer, path) ((buffer) + PAGE_SIZE - (path)) - -# define free kfree -# define malloc(a) kmalloc(a, GFP_KERNEL) -# define printf printk -int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data); -int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data); -int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data); - -#else /* __KERNEL__ */ -# include -# include -# include -# include -# include - -# define printk printf -# ifndef CERROR -# define CERROR printf -# endif -# define kmalloc(a,b) malloc(a) - -void init_fsreintdata (void); -int kml_fsreint(struct kml_rec *rec, char *basedir); -int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird, - uuid_t uuid, __u32 generate_kml); - -static inline void izo_ioctl_init(struct izo_ioctl_data *data) -{ - memset(data, 0, sizeof(*data)); - data->ioc_len = sizeof(*data); - data->ioc_version = IZO_IOCTL_VERSION; -} - -static inline int -izo_ioctl_pack(struct izo_ioctl_data *data, char **pbuf, int max) -{ - char *ptr; - struct izo_ioctl_data *overlay; - data->ioc_len = izo_ioctl_packlen(data); - data->ioc_version = IZO_IOCTL_VERSION; - - if (*pbuf && izo_ioctl_packlen(data) > max) - return 1; - if (*pbuf == NULL) - *pbuf = malloc(data->ioc_len); - if (*pbuf == NULL) - return 1; - overlay = (struct izo_ioctl_data *)*pbuf; - memcpy(*pbuf, data, sizeof(*data)); - - ptr = overlay->ioc_bulk; - if (data->ioc_inlbuf1) - LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr); - if (data->ioc_inlbuf2) - LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr); - if (izo_ioctl_is_invalid(overlay)) - return 1; - - return 0; -} - -#endif /* __KERNEL__*/ - -#define IZO_ERROR_NAME 1 -#define IZO_ERROR_UPDATE 2 -#define IZO_ERROR_DELETE 3 -#define IZO_ERROR_RENAME 4 - -static inline char *izo_error(int err) -{ -#ifndef __KERNEL__ - if (err <= 0) - return strerror(-err); -#endif - switch (err) { - case IZO_ERROR_NAME: - return "InterMezzo name/name conflict"; - case IZO_ERROR_UPDATE: - return "InterMezzo update/update conflict"; - case IZO_ERROR_DELETE: - return "InterMezzo update/delete conflict"; - case IZO_ERROR_RENAME: - return "InterMezzo rename/rename conflict"; - } - return "Unknown InterMezzo error"; -} - -/* kml_unpack.c */ -char *kml_print_rec(struct kml_rec *rec, int brief); -int kml_unpack(struct kml_rec *rec, char **buf, char *end); - -/* fs 2.5 compat */ - -/* is_read_only() is replaced by bdev_read_only which takes struct - block_device *. Since this is only needed for debugging, it can be - safely ignored now. -*/ -#define is_read_only(dev) 0 - -#endif diff --git a/fs/intermezzo/intermezzo_idl.h b/fs/intermezzo/intermezzo_idl.h deleted file mode 100644 index 4371b161d..000000000 --- a/fs/intermezzo/intermezzo_idl.h +++ /dev/null @@ -1,304 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001, 2002 Cluster File Systems, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __INTERMEZZO_IDL_H__ -#define __INTERMEZZO_IDL_H__ - -#include -#include - -/* this file contains all data structures used in InterMezzo's interfaces: - * - upcalls - * - ioctl's - * - KML records - * - RCVD records - * - rpc's - */ - -/* UPCALL */ -#define INTERMEZZO_MINOR 248 - - -#define IZO_UPC_VERSION 0x00010002 -#define IZO_UPC_PERMIT 1 -#define IZO_UPC_CONNECT 2 -#define IZO_UPC_GO_FETCH_KML 3 -#define IZO_UPC_OPEN 4 -#define IZO_UPC_REVOKE_PERMIT 5 -#define IZO_UPC_KML 6 -#define IZO_UPC_BACKFETCH 7 -#define IZO_UPC_KML_TRUNC 8 -#define IZO_UPC_SET_KMLSIZE 9 -#define IZO_UPC_BRANCH_UNDO 10 -#define IZO_UPC_BRANCH_REDO 11 -#define IZO_UPC_GET_FILEID 12 -#define IZO_UPC_CLIENT_MAKE_BRANCH 13 -#define IZO_UPC_SERVER_MAKE_BRANCH 14 -#define IZO_UPC_REPSTATUS 15 - -#define IZO_UPC_LARGEST_OPCODE 15 - -struct izo_upcall_hdr { - __u32 u_len; - __u32 u_version; - __u32 u_opc; - __u32 u_uniq; - __u32 u_pid; - __u32 u_uid; - __u32 u_pathlen; - __u32 u_fsetlen; - __u64 u_offset; - __u64 u_length; - __u32 u_first_recno; - __u32 u_last_recno; - __u32 u_async; - __u32 u_reclen; - __u8 u_uuid[16]; -}; - -/* This structure _must_ sit at the beginning of the buffer */ -struct izo_upcall_resp { - __u32 opcode; - __u32 unique; - __u32 result; -}; - - -/* IOCTL */ - -#define IZO_IOCTL_VERSION 0x00010003 - -/* maximum size supported for ioc_pbuf1 */ -#define KML_MAX_BUF (64*1024) - -struct izo_ioctl_hdr { - __u32 ioc_len; - __u32 ioc_version; -}; - -struct izo_ioctl_data { - __u32 ioc_len; - __u32 ioc_version; - __u32 ioc_izodev; - __u32 ioc_kmlrecno; - __u64 ioc_kmlsize; - __u32 ioc_flags; - __s32 ioc_inofd; - __u64 ioc_ino; - __u64 ioc_generation; - __u32 ioc_mark_what; - __u32 ioc_and_flag; - __u32 ioc_or_flag; - __u32 ioc_dev; - __u32 ioc_offset; - __u32 ioc_slot; - __u64 ioc_uid; - __u8 ioc_uuid[16]; - - __u32 ioc_inllen1; /* path */ - char *ioc_inlbuf1; - __u32 ioc_inllen2; /* fileset */ - char *ioc_inlbuf2; - - __u32 ioc_plen1; /* buffers in user space (KML) */ - char *ioc_pbuf1; - __u32 ioc_plen2; /* buffers in user space (KML) */ - char *ioc_pbuf2; - - char ioc_bulk[0]; -}; - -#define IZO_IOC_DEVICE _IOW ('p',0x50, void *) -#define IZO_IOC_REINTKML _IOW ('p',0x51, void *) -#define IZO_IOC_GET_RCVD _IOW ('p',0x52, void *) -#define IZO_IOC_SET_IOCTL_UID _IOW ('p',0x53, void *) -#define IZO_IOC_GET_KML_SIZE _IOW ('p',0x54, void *) -#define IZO_IOC_PURGE_FILE_DATA _IOW ('p',0x55, void *) -#define IZO_IOC_CONNECT _IOW ('p',0x56, void *) -#define IZO_IOC_GO_FETCH_KML _IOW ('p',0x57, void *) -#define IZO_IOC_MARK _IOW ('p',0x58, void *) -#define IZO_IOC_CLEAR_FSET _IOW ('p',0x59, void *) -#define IZO_IOC_CLEAR_ALL_FSETS _IOW ('p',0x60, void *) -#define IZO_IOC_SET_FSET _IOW ('p',0x61, void *) -#define IZO_IOC_REVOKE_PERMIT _IOW ('p',0x62, void *) -#define IZO_IOC_SET_KMLSIZE _IOW ('p',0x63, void *) -#define IZO_IOC_CLIENT_MAKE_BRANCH _IOW ('p',0x64, void *) -#define IZO_IOC_SERVER_MAKE_BRANCH _IOW ('p',0x65, void *) -#define IZO_IOC_BRANCH_UNDO _IOW ('p',0x66, void *) -#define IZO_IOC_BRANCH_REDO _IOW ('p',0x67, void *) -#define IZO_IOC_SET_PID _IOW ('p',0x68, void *) -#define IZO_IOC_SET_CHANNEL _IOW ('p',0x69, void *) -#define IZO_IOC_GET_CHANNEL _IOW ('p',0x70, void *) -#define IZO_IOC_GET_FILEID _IOW ('p',0x71, void *) -#define IZO_IOC_ADJUST_LML _IOW ('p',0x72, void *) -#define IZO_IOC_SET_FILEID _IOW ('p',0x73, void *) -#define IZO_IOC_REPSTATUS _IOW ('p',0x74, void *) - -/* marking flags for fsets */ -#define FSET_CLIENT_RO 0x00000001 -#define FSET_LENTO_RO 0x00000002 -#define FSET_HASPERMIT 0x00000004 /* we have a permit to WB */ -#define FSET_INSYNC 0x00000008 /* this fileset is in sync */ -#define FSET_PERMIT_WAITING 0x00000010 /* Lento is waiting for permit */ -#define FSET_STEAL_PERMIT 0x00000020 /* take permit if Lento is dead */ -#define FSET_JCLOSE_ON_WRITE 0x00000040 /* Journal closes on writes */ -#define FSET_DATA_ON_DEMAND 0x00000080 /* update data on file_open() */ -#define FSET_PERMIT_EXCLUSIVE 0x00000100 /* only one permitholder allowed */ -#define FSET_HAS_BRANCHES 0x00000200 /* this fileset contains branches */ -#define FSET_IS_BRANCH 0x00000400 /* this fileset is a branch */ -#define FSET_FLAT_BRANCH 0x00000800 /* this fileset is ROOT with branches */ - -/* what to mark indicator (ioctl parameter) */ -#define MARK_DENTRY 101 -#define MARK_FSET 102 -#define MARK_CACHE 103 -#define MARK_GETFL 104 - -/* KML */ - -#define KML_MAJOR_VERSION 0x00010000 -#define KML_MINOR_VERSION 0x00000002 -#define KML_OPCODE_NOOP 0 -#define KML_OPCODE_CREATE 1 -#define KML_OPCODE_MKDIR 2 -#define KML_OPCODE_UNLINK 3 -#define KML_OPCODE_RMDIR 4 -#define KML_OPCODE_CLOSE 5 -#define KML_OPCODE_SYMLINK 6 -#define KML_OPCODE_RENAME 7 -#define KML_OPCODE_SETATTR 8 -#define KML_OPCODE_LINK 9 -#define KML_OPCODE_OPEN 10 -#define KML_OPCODE_MKNOD 11 -#define KML_OPCODE_WRITE 12 -#define KML_OPCODE_RELEASE 13 -#define KML_OPCODE_TRUNC 14 -#define KML_OPCODE_SETEXTATTR 15 -#define KML_OPCODE_DELEXTATTR 16 -#define KML_OPCODE_KML_TRUNC 17 -#define KML_OPCODE_GET_FILEID 18 -#define KML_OPCODE_NUM 19 -/* new stuff */ -struct presto_version { - __u32 pv_mtime_sec; - __u32 pv_mtime_nsec; - __u32 pv_ctime_sec; - __u32 pv_ctime_nsec; - __u64 pv_size; -}; - -struct kml_prefix_hdr { - __u32 len; - __u32 version; - __u32 pid; - __u32 auid; - __u32 fsuid; - __u32 fsgid; - __u32 opcode; - __u32 ngroups; -}; - -struct kml_prefix { - struct kml_prefix_hdr *hdr; - __u32 *groups; -}; - -struct kml_suffix { - __u32 prevrec; - __u32 recno; - __u32 time; - __u32 len; -}; - -struct kml_rec { - char *buf; - struct kml_prefix prefix; - __u64 offset; - char *path; - int pathlen; - char *name; - int namelen; - char *target; - int targetlen; - struct presto_version *old_objectv; - struct presto_version *new_objectv; - struct presto_version *old_parentv; - struct presto_version *new_parentv; - struct presto_version *old_targetv; - struct presto_version *new_targetv; - __u32 valid; - __u32 mode; - __u32 uid; - __u32 gid; - __u64 size; - __u32 mtime_sec; - __u32 mtime_nsec; - __u32 ctime_sec; - __u32 ctime_nsec; - __u32 flags; - __u32 ino; - __u32 rdev; - __u32 major; - __u32 minor; - __u32 generation; - __u32 old_mode; - __u32 old_rdev; - __u64 old_uid; - __u64 old_gid; - char *old_target; - int old_targetlen; - struct kml_suffix *suffix; -}; - - -/* RCVD */ - -/* izo_rcvd_rec fills the .intermezzo/fset/last_rcvd file and provides data about - * our view of reintegration offsets for a given peer. - * - * The only exception is the last_rcvd record which has a UUID consisting of all - * zeroes; this record's lr_local_offset field is the logical byte offset of our - * KML, which is updated when KML truncation takes place. All other fields are - * reserved. */ - -/* XXX - document how clean shutdowns are recorded */ - -struct izo_rcvd_rec { - __u8 lr_uuid[16]; /* which peer? */ - __u64 lr_remote_recno; /* last confirmed remote recno */ - __u64 lr_remote_offset; /* last confirmed remote offset */ - __u64 lr_local_recno; /* last locally reinted recno */ - __u64 lr_local_offset; /* last locally reinted offset */ - __u64 lr_last_ctime; /* the largest ctime that has reintegrated */ -}; - -/* Cache purge database - * - * Each DB entry is this structure followed by the path name, no trailing NUL. */ -struct izo_purge_entry { - __u64 p_atime; - __u32 p_pathlen; -}; - -/* RPC */ - -#endif diff --git a/fs/intermezzo/intermezzo_journal.h b/fs/intermezzo/intermezzo_journal.h deleted file mode 100644 index 99d588d48..000000000 --- a/fs/intermezzo/intermezzo_journal.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __PRESTO_JOURNAL_H -#define __PRESTO_JOURNAL_H - - -struct journal_prefix { - int len; - u32 version; - int pid; - int uid; - int fsuid; - int fsgid; - int opcode; - u32 ngroups; - u32 groups[0]; -}; - -struct journal_suffix { - unsigned long prevrec; /* offset of previous record for dentry */ - int recno; - int time; - int len; -}; - -#endif diff --git a/fs/intermezzo/intermezzo_kml.h b/fs/intermezzo/intermezzo_kml.h deleted file mode 100644 index ca612e615..000000000 --- a/fs/intermezzo/intermezzo_kml.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef __INTERMEZZO_KML_H -#define __INTERMEZZO_KML_H - -#include "intermezzo_psdev.h" -#include -#include "intermezzo_journal.h" - -#define PRESTO_KML_MAJOR_VERSION 0x00010000 -#define PRESTO_KML_MINOR_VERSION 0x00002001 -#define PRESTO_OP_NOOP 0 -#define PRESTO_OP_CREATE 1 -#define PRESTO_OP_MKDIR 2 -#define PRESTO_OP_UNLINK 3 -#define PRESTO_OP_RMDIR 4 -#define PRESTO_OP_CLOSE 5 -#define PRESTO_OP_SYMLINK 6 -#define PRESTO_OP_RENAME 7 -#define PRESTO_OP_SETATTR 8 -#define PRESTO_OP_LINK 9 -#define PRESTO_OP_OPEN 10 -#define PRESTO_OP_MKNOD 11 -#define PRESTO_OP_WRITE 12 -#define PRESTO_OP_RELEASE 13 -#define PRESTO_OP_TRUNC 14 -#define PRESTO_OP_SETEXTATTR 15 -#define PRESTO_OP_DELEXTATTR 16 - -#define PRESTO_LML_DONE 1 /* flag to get first write to do LML */ -#define KML_KOP_MARK 0xffff - -struct presto_lml_data { - loff_t rec_offset; -}; - -struct big_journal_prefix { - u32 len; - u32 version; - u32 pid; - u32 uid; - u32 fsuid; - u32 fsgid; - u32 opcode; - u32 ngroups; - u32 groups[NGROUPS_SMALL]; -}; - -enum kml_opcode { - KML_CREATE = 1, - KML_MKDIR, - KML_UNLINK, - KML_RMDIR, - KML_CLOSE, - KML_SYMLINK, - KML_RENAME, - KML_SETATTR, - KML_LINK, - KML_OPEN, - KML_MKNOD, - KML_ENDMARK = 0xff -}; - -struct kml_create { - char *path; - struct presto_version new_objectv, - old_parentv, - new_parentv; - int mode; - int uid; - int gid; -}; - -struct kml_open { -}; - -struct kml_mkdir { - char *path; - struct presto_version new_objectv, - old_parentv, - new_parentv; - int mode; - int uid; - int gid; -}; - -struct kml_unlink { - char *path, - *name; - struct presto_version old_tgtv, - old_parentv, - new_parentv; -}; - -struct kml_rmdir { - char *path, - *name; - struct presto_version old_tgtv, - old_parentv, - new_parentv; -}; - -struct kml_close { - int open_mode, - open_uid, - open_gid; - char *path; - struct presto_version new_objectv; - __u64 ino; - int generation; -}; - -struct kml_symlink { - char *sourcepath, - *targetpath; - struct presto_version new_objectv, - old_parentv, - new_parentv; - int uid; - int gid; -}; - -struct kml_rename { - char *sourcepath, - *targetpath; - struct presto_version old_objectv, - new_objectv, - old_tgtv, - new_tgtv; -}; - -struct kml_setattr { - char *path; - struct presto_version old_objectv; - struct iattr iattr; -}; - -struct kml_link { - char *sourcepath, - *targetpath; - struct presto_version new_objectv, - old_parentv, - new_parentv; -}; - -struct kml_mknod { - char *path; - struct presto_version new_objectv, - old_parentv, - new_parentv; - int mode; - int uid; - int gid; - int major; - int minor; -}; - -/* kml record items for optimizing */ -struct kml_kop_node -{ - u32 kml_recno; - u32 kml_flag; - u32 kml_op; - nlink_t i_nlink; - u32 i_ino; -}; - -struct kml_kop_lnode -{ - struct list_head chains; - struct kml_kop_node node; -}; - -struct kml_endmark { - u32 total; - struct kml_kop_node *kop; -}; - -/* kml_flag */ -#define KML_REC_DELETE 1 -#define KML_REC_EXIST 0 - -struct kml_optimize { - struct list_head kml_chains; - u32 kml_flag; - u32 kml_op; - nlink_t i_nlink; - u32 i_ino; -}; - -struct kml_rec { - /* attribute of this record */ - int rec_size; - int rec_kml_offset; - - struct big_journal_prefix rec_head; - union { - struct kml_create create; - struct kml_open open; - struct kml_mkdir mkdir; - struct kml_unlink unlink; - struct kml_rmdir rmdir; - struct kml_close close; - struct kml_symlink symlink; - struct kml_rename rename; - struct kml_setattr setattr; - struct kml_mknod mknod; - struct kml_link link; - struct kml_endmark endmark; - } rec_kml; - struct journal_suffix rec_tail; - - /* for kml optimize only */ - struct kml_optimize kml_optimize; -}; - -/* kml record items for optimizing */ -extern void kml_kop_init (struct presto_file_set *fset); -extern void kml_kop_addrec (struct presto_file_set *fset, - struct inode *ino, u32 op, u32 flag); -extern int kml_kop_flush (struct presto_file_set *fset); - -/* defined in kml_setup.c */ -extern int kml_init (struct presto_file_set *fset); -extern int kml_cleanup (struct presto_file_set *fset); - -/* defined in kml.c */ -extern int begin_kml_reint (struct file *file, unsigned long arg); -extern int do_kml_reint (struct file *file, unsigned long arg); -extern int end_kml_reint (struct file *file, unsigned long arg); - -/* kml_utils.c */ -extern char *dlogit (void *tbuf, const void *sbuf, int size); -extern char * bdup_printf (char *format, ...); - -/* defined in kml_decode.c */ -/* printop */ -#define PRINT_KML_PREFIX 0x1 -#define PRINT_KML_SUFFIX 0x2 -#define PRINT_KML_REC 0x4 -#define PRINT_KML_OPTIMIZE 0x8 -#define PRINT_KML_EXIST 0x10 -#define PRINT_KML_DELETE 0x20 -extern void kml_printrec (struct kml_rec *rec, int printop); -extern int print_allkmlrec (struct list_head *head, int printop); -extern int delete_kmlrec (struct list_head *head); -extern int kml_decoderec (char *buf, int pos, int buflen, int *size, - struct kml_rec **newrec); -extern int decode_kmlrec (struct list_head *head, char *kml_buf, int buflen); -extern void kml_freerec (struct kml_rec *rec); - -/* defined in kml_reint.c */ -#define KML_CLOSE_BACKFETCH 1 -extern int kml_reintbuf (struct kml_fsdata *kml_fsdata, - char *mtpt, struct kml_rec **rec); - -/* defined in kml_setup.c */ -extern int kml_init (struct presto_file_set *fset); -extern int kml_cleanup (struct presto_file_set *fset); - -#endif - diff --git a/fs/intermezzo/intermezzo_lib.h b/fs/intermezzo/intermezzo_lib.h deleted file mode 100644 index 21cc0b94a..000000000 --- a/fs/intermezzo/intermezzo_lib.h +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Data structures unpacking/packing macros & inlines - * - */ - -#ifndef _INTERMEZZO_LIB_H -#define _INTERMEZZO_LIB_H - -#ifdef __KERNEL__ -# include -#else -# include -# include -#endif - -static inline int size_round (int val) -{ - return (val + 3) & (~0x3); -} - -static inline int size_round0(int val) -{ - if (!val) - return 0; - return (val + 1 + 3) & (~0x3); -} - -static inline size_t round_strlen(char *fset) -{ - return size_round(strlen(fset) + 1); -} - -#ifdef __KERNEL__ -# define NTOH__u32(var) le32_to_cpu(var) -# define NTOH__u64(var) le64_to_cpu(var) -# define HTON__u32(var) cpu_to_le32(var) -# define HTON__u64(var) cpu_to_le64(var) -#else -# include -# define NTOH__u32(var) GUINT32_FROM_LE(var) -# define NTOH__u64(var) GUINT64_FROM_LE(var) -# define HTON__u32(var) GUINT32_TO_LE(var) -# define HTON__u64(var) GUINT64_TO_LE(var) -#endif - -/* - * copy sizeof(type) bytes from pointer to var and move ptr forward. - * return EFAULT if pointer goes beyond end - */ -#define UNLOGV(var,type,ptr,end) \ -do { \ - var = *(type *)ptr; \ - ptr += sizeof(type); \ - if (ptr > end ) \ - return -EFAULT; \ -} while (0) - -/* the following two macros convert to little endian */ -/* type MUST be __u32 or __u64 */ -#define LUNLOGV(var,type,ptr,end) \ -do { \ - var = NTOH##type(*(type *)ptr); \ - ptr += sizeof(type); \ - if (ptr > end ) \ - return -EFAULT; \ -} while (0) - -/* now log values */ -#define LOGV(var,type,ptr) \ -do { \ - *((type *)ptr) = var; \ - ptr += sizeof(type); \ -} while (0) - -/* and in network order */ -#define LLOGV(var,type,ptr) \ -do { \ - *((type *)ptr) = HTON##type(var); \ - ptr += sizeof(type); \ -} while (0) - - -/* - * set var to point at (type *)ptr, move ptr forward with sizeof(type) - * return from function with EFAULT if ptr goes beyond end - */ -#define UNLOGP(var,type,ptr,end) \ -do { \ - var = (type *)ptr; \ - ptr += sizeof(type); \ - if (ptr > end ) \ - return -EFAULT; \ -} while (0) - -#define LOGP(var,type,ptr) \ -do { \ - memcpy(ptr, var, sizeof(type)); \ - ptr += sizeof(type); \ -} while (0) - -/* - * set var to point at (char *)ptr, move ptr forward by size_round(len); - * return from function with EFAULT if ptr goes beyond end - */ -#define UNLOGL(var,type,len,ptr,end) \ -do { \ - if (len == 0) \ - var = (type *)0; \ - else { \ - var = (type *)ptr; \ - ptr += size_round(len * sizeof(type)); \ - } \ - if (ptr > end ) \ - return -EFAULT; \ -} while (0) - -#define UNLOGL0(var,type,len,ptr,end) \ -do { \ - UNLOGL(var,type,len+1,ptr,end); \ - if ( *((char *)ptr - size_round(len+1) + len) != '\0') \ - return -EFAULT; \ -} while (0) - -#define LOGL(var,len,ptr) \ -do { \ - size_t __fill = size_round(len); \ - /* Prevent data leakage. */ \ - if (__fill > 0) \ - memset((char *)ptr, 0, __fill); \ - memcpy((char *)ptr, (const char *)var, len); \ - ptr += __fill; \ -} while (0) - -#define LOGL0(var,len,ptr) \ -do { \ - if (!len) break; \ - memcpy((char *)ptr, (const char *)var, len); \ - *((char *)(ptr) + len) = 0; \ - ptr += size_round(len + 1); \ -} while (0) - -#endif /* _INTERMEZZO_LIB_H */ - diff --git a/fs/intermezzo/intermezzo_psdev.h b/fs/intermezzo/intermezzo_psdev.h deleted file mode 100644 index fff728ad8..000000000 --- a/fs/intermezzo/intermezzo_psdev.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - */ - -#ifndef __PRESTO_PSDEV_H -#define __PRESTO_PSDEV_H - -#define MAX_CHANNEL 16 -#define PROCNAME_SIZE 32 -#include - -/* represents state of an instance reached with /dev/intermezzo */ -/* communication pending & processing queues */ -struct upc_channel { - unsigned int uc_seq; - wait_queue_head_t uc_waitq; /* Lento wait queue */ - struct list_head uc_pending; - struct list_head uc_processing; - spinlock_t uc_lock; - int uc_pid; /* Lento's pid */ - int uc_hard; /* allows signals during upcalls */ - int uc_no_filter; - int uc_no_journal; - int uc_no_upcall; - int uc_timeout; /* . sec: signals will dequeue upc */ - long uc_errorval; /* for testing I/O failures */ - struct list_head uc_cache_list; - int uc_minor; -}; - -#define ISLENTO(minor) (current->pid == izo_channels[minor].uc_pid \ - || current->real_parent->pid == izo_channels[minor].uc_pid \ - || current->real_parent->real_parent->pid == izo_channels[minor].uc_pid) - -extern struct upc_channel izo_channels[MAX_CHANNEL]; - -/* message types between presto filesystem in kernel */ -#define REQ_READ 1 -#define REQ_WRITE 2 -#define REQ_ASYNC 4 -#define REQ_DEAD 8 - -struct upc_req { - struct list_head rq_chain; - caddr_t rq_data; - int rq_flags; - int rq_bufsize; - int rq_rep_size; - int rq_opcode; /* copied from data to save lookup */ - int rq_unique; - wait_queue_head_t rq_sleep; /* process' wait queue */ - unsigned long rq_posttime; -}; - -#endif diff --git a/fs/intermezzo/intermezzo_upcall.h b/fs/intermezzo/intermezzo_upcall.h deleted file mode 100644 index 0b3e6ff74..000000000 --- a/fs/intermezzo/intermezzo_upcall.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Based on cfs.h from Coda, but revamped for increased simplicity. - * Linux modifications by Peter Braam, Aug 1996 - * Rewritten for InterMezzo - */ - -#ifndef _PRESTO_HEADER_ -#define _PRESTO_HEADER_ - - -/* upcall.c */ -#define SYNCHRONOUS 0 -#define ASYNCHRONOUS 1 - -int lento_permit(int minor, int pathlen, int fsetnamelen, char *path, char *fset); -int lento_opendir(int minor, int pathlen, char *path, int async); -int lento_kml(int minor, unsigned int offset, unsigned int first_recno, - unsigned int length, unsigned int last_recno, int namelen, - char *fsetname); -int lento_open(int minor, int pathlen, char *path); -int lento_journal(int minor, char *page, int async); -int lento_release_permit(int minor, int cookie); - -/* - * Kernel <--> Lento communications. - */ -/* upcalls */ -#define LENTO_PERMIT 1 -#define LENTO_JOURNAL 2 -#define LENTO_OPENDIR 3 -#define LENTO_OPEN 4 -#define LENTO_SIGNAL 5 -#define LENTO_KML 6 -#define LENTO_COOKIE 7 - -/* Lento <-> Presto RPC arguments */ -struct lento_up_hdr { - unsigned int opcode; - unsigned int unique; /* Keep multiple outstanding msgs distinct */ - u_short pid; /* Common to all */ - u_short uid; -}; - -/* This structure _must_ sit at the beginning of the buffer */ -struct lento_down_hdr { - unsigned int opcode; - unsigned int unique; - unsigned int result; -}; - -/* lento_permit: */ -struct lento_permit_in { - struct lento_up_hdr uh; - int pathlen; - int fsetnamelen; - char path[0]; -}; -struct lento_permit_out { - struct lento_down_hdr dh; -}; - - -/* lento_opendir: */ -struct lento_opendir_in { - struct lento_up_hdr uh; - int async; - int pathlen; - char path[0]; -}; -struct lento_opendir_out { - struct lento_down_hdr dh; -}; - - -/* lento_kml: */ -struct lento_kml_in { - struct lento_up_hdr uh; - unsigned int offset; - unsigned int first_recno; - unsigned int length; - unsigned int last_recno; - int namelen; - char fsetname[0]; -}; - -struct lento_kml_out { - struct lento_down_hdr dh; -}; - - -/* lento_open: */ -struct lento_open_in { - struct lento_up_hdr uh; - int pathlen; - char path[0]; -}; -struct lento_open_out { - struct lento_down_hdr dh; -}; - -/* lento_response_cookie */ -struct lento_response_cookie_in { - struct lento_up_hdr uh; - int cookie; -}; - -struct lento_response_cookie_out { - struct lento_down_hdr dh; -}; - - -struct lento_mknod { - struct lento_down_hdr dh; - int major; - int minor; - int mode; - char path[0]; -}; - - -/* NB: every struct below begins with an up_hdr */ -union up_args { - struct lento_up_hdr uh; - struct lento_permit_in lento_permit; - struct lento_open_in lento_open; - struct lento_opendir_in lento_opendir; - struct lento_kml_in lento_kml; - struct lento_response_cookie_in lento_response_cookie; -}; - -union down_args { - struct lento_down_hdr dh; - struct lento_permit_out lento_permit; - struct lento_open_out lento_open; - struct lento_opendir_out lento_opendir; - struct lento_kml_out lento_kml; - struct lento_response_cookie_out lento_response_cookie; -}; - -#include "intermezzo_psdev.h" - -int lento_upcall(int minor, int read_size, int *rep_size, - union up_args *buffer, int async, - struct upc_req *rq ); -#endif - diff --git a/fs/intermezzo/journal.c b/fs/intermezzo/journal.c deleted file mode 100644 index 2beda3863..000000000 --- a/fs/intermezzo/journal.c +++ /dev/null @@ -1,2452 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2001 Cluster File Systems, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * Support for journalling extended attributes - * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -struct presto_reservation_data { - unsigned int ri_recno; - loff_t ri_offset; - loff_t ri_size; - struct list_head ri_list; -}; - -/* - * Locking Semantics - * - * write lock in struct presto_log_fd: - * - name: fd_lock - * - required for: accessing any field in a presto_log_fd - * - may not be held across I/O - * - - * - */ - -/* - * reserve record space and/or atomically request state of the log - * rec will hold the location reserved record upon return - * this reservation will be placed in the queue - */ -static void presto_reserve_record(struct presto_file_set *fset, - struct presto_log_fd *fd, - struct rec_info *rec, - struct presto_reservation_data *rd) -{ - int chunked_record = 0; - ENTRY; - - write_lock(&fd->fd_lock); - if ( rec->is_kml ) { - int chunk = 1 << fset->fset_chunkbits; - int chunk_mask = ~(chunk -1); - loff_t boundary; - - boundary = (fd->fd_offset + chunk - 1) & chunk_mask; - if ( fd->fd_offset + rec->size >= boundary ) { - chunked_record = 1; - fd->fd_offset = boundary; - } - } - - fd->fd_recno++; - - /* this moves the fd_offset back after truncation */ - if ( list_empty(&fd->fd_reservations) && - !chunked_record) { - fd->fd_offset = fd->fd_file->f_dentry->d_inode->i_size; - } - - rec->offset = fd->fd_offset; - if (rec->is_kml) - rec->offset += fset->fset_kml_logical_off; - - rec->recno = fd->fd_recno; - - /* add the reservation data to the end of the list */ - rd->ri_offset = fd->fd_offset; - rd->ri_size = rec->size; - rd->ri_recno = rec->recno; - list_add(&rd->ri_list, fd->fd_reservations.prev); - - fd->fd_offset += rec->size; - - write_unlock(&fd->fd_lock); - - EXIT; -} - -static inline void presto_release_record(struct presto_log_fd *fd, - struct presto_reservation_data *rd) -{ - write_lock(&fd->fd_lock); - list_del(&rd->ri_list); - write_unlock(&fd->fd_lock); -} - -/* XXX should we ask for do_truncate to be exported? */ -int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry, - loff_t length, loff_t size_check) -{ - struct inode *inode = dentry->d_inode; - int error; - struct iattr newattrs; - - ENTRY; - - if (length < 0) { - EXIT; - return -EINVAL; - } - - down(&inode->i_sem); - lock_kernel(); - - if (size_check != inode->i_size) { - unlock_kernel(); - up(&inode->i_sem); - EXIT; - return -EALREADY; - } - - newattrs.ia_size = length; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - - if (inode->i_op && inode->i_op->setattr) - error = inode->i_op->setattr(dentry, &newattrs); - else { - inode_setattr(dentry->d_inode, &newattrs); - error = 0; - } - - unlock_kernel(); - up(&inode->i_sem); - EXIT; - return error; -} - -static void presto_kml_truncate(struct presto_file_set *fset) -{ - int rc; - ENTRY; - - write_lock(&fset->fset_kml.fd_lock); - if (fset->fset_kml.fd_truncating == 1 ) { - write_unlock(&fset->fset_kml.fd_lock); - EXIT; - return; - } - - fset->fset_kml.fd_truncating = 1; - write_unlock(&fset->fset_kml.fd_lock); - - CERROR("islento: %d, count: %d\n", - ISLENTO(presto_i2m(fset->fset_dentry->d_inode)), - fset->fset_permit_count); - - rc = izo_upc_kml_truncate(fset->fset_cache->cache_psdev->uc_minor, - fset->fset_lento_off, fset->fset_lento_recno, - fset->fset_name); - - /* Userspace is the only permitholder now, and will retain an exclusive - * hold on the permit until KML truncation completes. */ - /* FIXME: double check this code path now that the precise semantics of - * fset->fset_permit_count have changed. */ - - if (rc != 0) { - write_lock(&fset->fset_kml.fd_lock); - fset->fset_kml.fd_truncating = 0; - write_unlock(&fset->fset_kml.fd_lock); - } - - EXIT; -} - -void *presto_trans_start(struct presto_file_set *fset, struct inode *inode, - int op) -{ - ENTRY; - if ( !fset->fset_cache->cache_filter->o_trops ) { - EXIT; - return NULL; - } - EXIT; - return fset->fset_cache->cache_filter->o_trops->tr_start - (fset, inode, op); -} - -void presto_trans_commit(struct presto_file_set *fset, void *handle) -{ - ENTRY; - if (!fset->fset_cache->cache_filter->o_trops ) { - EXIT; - return; - } - - fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle); - - /* Check to see if the KML needs truncated. */ - if (fset->kml_truncate_size > 0 && - !fset->fset_kml.fd_truncating && - fset->fset_kml.fd_offset > fset->kml_truncate_size) { - CDEBUG(D_JOURNAL, "kml size: %lu; truncating\n", - (unsigned long)fset->fset_kml.fd_offset); - presto_kml_truncate(fset); - } - EXIT; -} - -inline int presto_no_journal(struct presto_file_set *fset) -{ - int minor = fset->fset_cache->cache_psdev->uc_minor; - return izo_channels[minor].uc_no_journal; -} - -#define size_round(x) (((x)+3) & ~0x3) - -#define BUFF_FREE(buf) PRESTO_FREE(buf, PAGE_SIZE) -#define BUFF_ALLOC(newbuf, oldbuf) \ - PRESTO_ALLOC(newbuf, PAGE_SIZE); \ - if ( !newbuf ) { \ - if (oldbuf) \ - BUFF_FREE(oldbuf); \ - return -ENOMEM; \ - } - -/* - * "buflen" should be PAGE_SIZE or more. - * Give relative path wrt to a fsetroot - */ -char * presto_path(struct dentry *dentry, struct dentry *root, - char *buffer, int buflen) -{ - char * end = buffer+buflen; - char * retval; - - *--end = '\0'; - buflen--; - if (dentry->d_parent != dentry && d_unhashed(dentry)) { - buflen -= 10; - end -= 10; - memcpy(end, " (deleted)", 10); - } - - /* Get '/' right */ - retval = end-1; - *retval = '/'; - - for (;;) { - struct dentry * parent; - int namelen; - - if (dentry == root) - break; - parent = dentry->d_parent; - if (dentry == parent) - break; - namelen = dentry->d_name.len; - buflen -= namelen + 1; - if (buflen < 0) - break; - end -= namelen; - memcpy(end, dentry->d_name.name, namelen); - *--end = '/'; - retval = end; - dentry = parent; - } - return retval; -} - -static inline char *logit(char *buf, const void *value, int size) -{ - char *ptr = (char *)value; - - memcpy(buf, ptr, size); - buf += size; - return buf; -} - - -static inline char * -journal_log_prefix_with_groups_and_ids(char *buf, int opcode, - struct rec_info *rec, - __u32 ngroups, gid_t *groups, - __u32 fsuid, __u32 fsgid) -{ - struct kml_prefix_hdr p; - u32 loggroups[NGROUPS_SMALL]; - - int i; - - p.len = cpu_to_le32(rec->size); - p.version = KML_MAJOR_VERSION | KML_MINOR_VERSION; - p.pid = cpu_to_le32(current->pid); - p.auid = cpu_to_le32(current->uid); - p.fsuid = cpu_to_le32(fsuid); - p.fsgid = cpu_to_le32(fsgid); - p.ngroups = cpu_to_le32(ngroups); - p.opcode = cpu_to_le32(opcode); - for (i=0 ; i < ngroups ; i++) - loggroups[i] = cpu_to_le32((__u32) groups[i]); - - buf = logit(buf, &p, sizeof(struct kml_prefix_hdr)); - buf = logit(buf, &loggroups, sizeof(__u32) * ngroups); - return buf; -} - -static inline char * -journal_log_prefix(char *buf, int opcode, struct rec_info *rec) -{ - __u32 groups[NGROUPS_SMALL]; - int i; - - /* convert 16 bit gid's to 32 bit gid's */ - for (i=0; igroup_info->ngroups; i++) - groups[i] = GROUP_AT(current->group_info,i); - - return journal_log_prefix_with_groups_and_ids(buf, opcode, rec, - (__u32)current->group_info->ngroups, - groups, - (__u32)current->fsuid, - (__u32)current->fsgid); -} - -static inline char * -journal_log_prefix_with_groups(char *buf, int opcode, struct rec_info *rec, - __u32 ngroups, gid_t *groups) -{ - return journal_log_prefix_with_groups_and_ids(buf, opcode, rec, - ngroups, groups, - (__u32)current->fsuid, - (__u32)current->fsgid); -} - -static inline char *log_dentry_version(char *buf, struct dentry *dentry) -{ - struct presto_version version; - - presto_getversion(&version, dentry->d_inode); - - version.pv_mtime_sec = HTON__u32(version.pv_mtime_sec); - version.pv_ctime_sec = HTON__u32(version.pv_ctime_sec); - version.pv_mtime_nsec = HTON__u32(version.pv_mtime_nsec); - version.pv_ctime_nsec = HTON__u32(version.pv_ctime_nsec); - version.pv_size = HTON__u64(version.pv_size); - - return logit(buf, &version, sizeof(version)); -} - -static inline char *log_version(char *buf, struct presto_version *pv) -{ - struct presto_version version; - - memcpy(&version, pv, sizeof(version)); - - version.pv_mtime_sec = HTON__u32(version.pv_mtime_sec); - version.pv_mtime_nsec = HTON__u32(version.pv_mtime_nsec); - version.pv_ctime_sec = HTON__u32(version.pv_ctime_sec); - version.pv_ctime_nsec = HTON__u32(version.pv_ctime_nsec); - version.pv_size = HTON__u64(version.pv_size); - - return logit(buf, &version, sizeof(version)); -} - -static inline char *log_rollback(char *buf, struct izo_rollback_data *rb) -{ - struct izo_rollback_data rollback; - - rollback.rb_mode = HTON__u32(rb->rb_mode); - rollback.rb_rdev = HTON__u32(rb->rb_rdev); - rollback.rb_uid = HTON__u64(rb->rb_uid); - rollback.rb_gid = HTON__u64(rb->rb_gid); - - return logit(buf, &rollback, sizeof(rollback)); -} - -static inline char *journal_log_suffix(char *buf, char *log, - struct presto_file_set *fset, - struct dentry *dentry, - struct rec_info *rec) -{ - struct kml_suffix s; - struct kml_prefix_hdr *p = (struct kml_prefix_hdr *)log; - -#if 0 - /* XXX needs to be done after reservation, - disable ths until version 1.2 */ - if ( dentry ) { - s.prevrec = cpu_to_le32(rec->offset - - presto_d2d(dentry)->dd_kml_offset); - presto_d2d(dentry)->dd_kml_offset = rec->offset; - } else { - s.prevrec = -1; - } -#endif - s.prevrec = 0; - - /* record number needs to be filled in after reservation - s.recno = cpu_to_le32(rec->recno); */ - s.time = cpu_to_le32(get_seconds()); - s.len = p->len; - return logit(buf, &s, sizeof(s)); -} - -int izo_log_close(struct presto_log_fd *logfd) -{ - int rc = 0; - - if (logfd->fd_file) { - rc = filp_close(logfd->fd_file, 0); - logfd->fd_file = NULL; - } else - CERROR("InterMezzo: %s: no filp\n", __FUNCTION__); - if (rc != 0) - CERROR("InterMezzo: close files: filp won't close: %d\n", rc); - - return rc; -} - -int presto_fwrite(struct file *file, const char *str, int len, loff_t *off) -{ - int rc; - mm_segment_t old_fs; - ENTRY; - - rc = -EINVAL; - if ( !off ) { - EXIT; - return rc; - } - - if ( ! file ) { - EXIT; - return rc; - } - - if ( ! file->f_op ) { - EXIT; - return rc; - } - - if ( ! file->f_op->write ) { - EXIT; - return rc; - } - - old_fs = get_fs(); - set_fs(get_ds()); - rc = file->f_op->write(file, str, len, off); - if (rc != len) { - CERROR("presto_fwrite: wrote %d bytes instead of " - "%d at %ld\n", rc, len, (long)*off); - rc = -EIO; - } - set_fs(old_fs); - EXIT; - return rc; -} - -int presto_fread(struct file *file, char *str, int len, loff_t *off) -{ - int rc; - mm_segment_t old_fs; - ENTRY; - - if (len > 512) - CERROR("presto_fread: read at %Ld for %d bytes, ino %ld\n", - *off, len, file->f_dentry->d_inode->i_ino); - - rc = -EINVAL; - if ( !off ) { - EXIT; - return rc; - } - - if ( ! file ) { - EXIT; - return rc; - } - - if ( ! file->f_op ) { - EXIT; - return rc; - } - - if ( ! file->f_op->read ) { - EXIT; - return rc; - } - - old_fs = get_fs(); - set_fs(get_ds()); - rc = file->f_op->read(file, str, len, off); - if (rc != len) { - CDEBUG(D_FILE, "presto_fread: read %d bytes instead of " - "%d at %Ld\n", rc, len, *off); - rc = -EIO; - } - set_fs(old_fs); - EXIT; - return rc; -} - -loff_t presto_kml_offset(struct presto_file_set *fset) -{ - unsigned int kml_recno; - struct presto_log_fd *fd = &fset->fset_kml; - loff_t offset; - ENTRY; - - write_lock(&fd->fd_lock); - - /* Determine the largest valid offset, i.e. up until the first - * reservation held on the file. */ - if ( !list_empty(&fd->fd_reservations) ) { - struct presto_reservation_data *rd; - rd = list_entry(fd->fd_reservations.next, - struct presto_reservation_data, - ri_list); - offset = rd->ri_offset; - kml_recno = rd->ri_recno; - } else { - offset = fd->fd_file->f_dentry->d_inode->i_size; - kml_recno = fset->fset_kml.fd_recno; - } - write_unlock(&fd->fd_lock); - return offset; -} - -static int presto_kml_dispatch(struct presto_file_set *fset) -{ - int rc = 0; - unsigned int kml_recno; - struct presto_log_fd *fd = &fset->fset_kml; - loff_t offset; - ENTRY; - - write_lock(&fd->fd_lock); - - /* Determine the largest valid offset, i.e. up until the first - * reservation held on the file. */ - if ( !list_empty(&fd->fd_reservations) ) { - struct presto_reservation_data *rd; - rd = list_entry(fd->fd_reservations.next, - struct presto_reservation_data, - ri_list); - offset = rd->ri_offset; - kml_recno = rd->ri_recno; - } else { - offset = fd->fd_file->f_dentry->d_inode->i_size; - kml_recno = fset->fset_kml.fd_recno; - } - - if ( kml_recno < fset->fset_lento_recno ) { - CERROR("presto_kml_dispatch: smoke is coming\n"); - write_unlock(&fd->fd_lock); - EXIT; - return 0; - } else if ( kml_recno == fset->fset_lento_recno ) { - write_unlock(&fd->fd_lock); - EXIT; - return 0; - /* XXX add a further "if" here to delay the KML upcall */ -#if 0 - } else if ( kml_recno < fset->fset_lento_recno + 100) { - write_unlock(&fd->fd_lock); - EXIT; - return 0; -#endif - } - CDEBUG(D_PIOCTL, "fset: %s\n", fset->fset_name); - - rc = izo_upc_kml(fset->fset_cache->cache_psdev->uc_minor, - fset->fset_lento_off, fset->fset_lento_recno, - offset + fset->fset_kml_logical_off, kml_recno, - fset->fset_name); - - if ( rc ) { - write_unlock(&fd->fd_lock); - EXIT; - return rc; - } - - fset->fset_lento_off = offset; - fset->fset_lento_recno = kml_recno; - write_unlock(&fd->fd_lock); - EXIT; - return 0; -} - -int izo_lookup_file(struct presto_file_set *fset, char *path, - struct nameidata *nd) -{ - int error = 0; - - CDEBUG(D_CACHE, "looking up: %s\n", path); - - error = path_lookup(path, LOOKUP_PARENT, nd); - if (error) { - EXIT; - return error; - } - - return 0; -} - -/* FIXME: this function is a mess of locking and error handling. There's got to - * be a better way. */ -static int do_truncate_rename(struct presto_file_set *fset, char *oldname, - char *newname) -{ - struct dentry *old_dentry, *new_dentry; - struct nameidata oldnd, newnd; - char *oldpath, *newpath; - int error; - - ENTRY; - - oldpath = izo_make_path(fset, oldname); - if (oldpath == NULL) { - EXIT; - return -ENOENT; - } - - newpath = izo_make_path(fset, newname); - if (newpath == NULL) { - error = -ENOENT; - EXIT; - goto exit; - } - - if ((error = izo_lookup_file(fset, oldpath, &oldnd)) != 0) { - EXIT; - goto exit1; - } - - if ((error = izo_lookup_file(fset, newpath, &newnd)) != 0) { - EXIT; - goto exit2; - } - - lock_rename(newnd.dentry, oldnd.dentry); - old_dentry = lookup_hash(&oldnd.last, oldnd.dentry); - error = PTR_ERR(old_dentry); - if (IS_ERR(old_dentry)) { - EXIT; - goto exit3; - } - error = -ENOENT; - if (!old_dentry->d_inode) { - EXIT; - goto exit4; - } - new_dentry = lookup_hash(&newnd.last, newnd.dentry); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) { - EXIT; - goto exit4; - } - - { - extern int presto_rename(struct inode *old_dir,struct dentry *old_dentry, - struct inode *new_dir,struct dentry *new_dentry); - error = presto_rename(old_dentry->d_parent->d_inode, old_dentry, - new_dentry->d_parent->d_inode, new_dentry); - } - - dput(new_dentry); - EXIT; - exit4: - dput(old_dentry); - exit3: - unlock_rename(newnd.dentry, oldnd.dentry); - path_release(&newnd); - exit2: - path_release(&oldnd); - exit1: - PRESTO_FREE(newpath, strlen(newpath) + 1); - exit: - PRESTO_FREE(oldpath, strlen(oldpath) + 1); - return error; -} - -/* This function is called with the fset->fset_kml.fd_lock held */ -int presto_finish_kml_truncate(struct presto_file_set *fset, - unsigned long int offset) -{ - struct lento_vfs_context info; - void *handle; - struct file *f; - struct dentry *dentry; - int error = 0, len; - struct nameidata nd; - char *kmlpath = NULL, *smlpath = NULL; - ENTRY; - - if (offset == 0) { - /* Lento couldn't do what it needed to; abort the truncation. */ - fset->fset_kml.fd_truncating = 0; - EXIT; - return 0; - } - - /* someone is about to write to the end of the KML; try again later. */ - if ( !list_empty(&fset->fset_kml.fd_reservations) ) { - EXIT; - return -EAGAIN; - } - - f = presto_copy_kml_tail(fset, offset); - if (IS_ERR(f)) { - EXIT; - return PTR_ERR(f); - } - - /* In a single transaction: - * - * - unlink 'kml' - * - rename 'kml_tmp' to 'kml' - * - unlink 'sml' - * - rename 'sml_tmp' to 'sml' - * - rewrite the first record of last_rcvd with the new kml - * offset. - */ - handle = presto_trans_start(fset, fset->fset_dentry->d_inode, - KML_OPCODE_KML_TRUNC); - if (IS_ERR(handle)) { - presto_release_space(fset->fset_cache, PRESTO_REQLOW); - CERROR("ERROR: presto_finish_kml_truncate: no space for transaction\n"); - EXIT; - return -ENOMEM; - } - - memset(&info, 0, sizeof(info)); - info.flags = LENTO_FL_IGNORE_TIME; - - kmlpath = izo_make_path(fset, "kml"); - if (kmlpath == NULL) { - error = -ENOMEM; - CERROR("make_path failed: ENOMEM\n"); - EXIT; - goto exit_commit; - } - - if ((error = izo_lookup_file(fset, kmlpath, &nd)) != 0) { - CERROR("izo_lookup_file(kml) failed: %d.\n", error); - EXIT; - goto exit_commit; - } - down(&nd.dentry->d_inode->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); - CERROR("lookup_hash failed\n"); - EXIT; - goto exit_commit; - } - error = presto_do_unlink(fset, dentry->d_parent, dentry, &info); - dput(dentry); - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); - - if (error != 0) { - CERROR("presto_do_unlink(kml) failed: %d.\n", error); - EXIT; - goto exit_commit; - } - - smlpath = izo_make_path(fset, "sml"); - if (smlpath == NULL) { - error = -ENOMEM; - CERROR("make_path() failed: ENOMEM\n"); - EXIT; - goto exit_commit; - } - - if ((error = izo_lookup_file(fset, smlpath, &nd)) != 0) { - CERROR("izo_lookup_file(sml) failed: %d.\n", error); - EXIT; - goto exit_commit; - } - down(&nd.dentry->d_inode->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); - CERROR("lookup_hash failed\n"); - EXIT; - goto exit_commit; - } - error = presto_do_unlink(fset, dentry->d_parent, dentry, &info); - dput(dentry); - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); - - if (error != 0) { - CERROR("presto_do_unlink(sml) failed: %d.\n", error); - EXIT; - goto exit_commit; - } - - error = do_truncate_rename(fset, "kml_tmp", "kml"); - if (error != 0) - CERROR("do_truncate_rename(kml_tmp, kml) failed: %d\n", error); - error = do_truncate_rename(fset, "sml_tmp", "sml"); - if (error != 0) - CERROR("do_truncate_rename(sml_tmp, sml) failed: %d\n", error); - - /* Write a new 'last_rcvd' record with the new KML offset */ - fset->fset_kml_logical_off += offset; - CDEBUG(D_CACHE, "new kml_logical_offset: %Lu\n", - fset->fset_kml_logical_off); - if (presto_write_kml_logical_offset(fset) != 0) { - CERROR("presto_write_kml_logical_offset failed\n"); - } - - presto_trans_commit(fset, handle); - - /* Everything was successful, so swap the KML file descriptors */ - filp_close(fset->fset_kml.fd_file, NULL); - fset->fset_kml.fd_file = f; - fset->fset_kml.fd_offset -= offset; - fset->fset_kml.fd_truncating = 0; - - EXIT; - return 0; - - exit_commit: - presto_trans_commit(fset, handle); - len = strlen("/.intermezzo/") + strlen(fset->fset_name) +strlen("sml"); - if (kmlpath != NULL) - PRESTO_FREE(kmlpath, len); - if (smlpath != NULL) - PRESTO_FREE(smlpath, len); - return error; -} - -/* structure of an extended log record: - - buf-prefix buf-body [string1 [string2 [string3]]] buf-suffix - - note: moves offset forward -*/ -static inline int presto_write_record(struct file *f, loff_t *off, - const char *buf, size_t size, - const char *string1, int len1, - const char *string2, int len2, - const char *string3, int len3) -{ - size_t prefix_size; - int rc; - - prefix_size = size - sizeof(struct kml_suffix); - rc = presto_fwrite(f, buf, prefix_size, off); - if ( rc != prefix_size ) { - CERROR("Write error!\n"); - EXIT; - return -EIO; - } - - if ( string1 && len1 ) { - rc = presto_fwrite(f, string1, len1, off); - if ( rc != len1 ) { - CERROR("Write error!\n"); - EXIT; - return -EIO; - } - } - - if ( string2 && len2 ) { - rc = presto_fwrite(f, string2, len2, off); - if ( rc != len2 ) { - CERROR("Write error!\n"); - EXIT; - return -EIO; - } - } - - if ( string3 && len3 ) { - rc = presto_fwrite(f, string3, len3, off); - if ( rc != len3 ) { - CERROR("Write error!\n"); - EXIT; - return -EIO; - } - } - - rc = presto_fwrite(f, buf + prefix_size, - sizeof(struct kml_suffix), off); - if ( rc != sizeof(struct kml_suffix) ) { - CERROR("Write error!\n"); - EXIT; - return -EIO; - } - return 0; -} - - -/* - * rec->size must be valid prior to calling this function. - * - * had to export this for branch_reinter in kml_reint.c - */ -int presto_log(struct presto_file_set *fset, struct rec_info *rec, - const char *buf, size_t size, - const char *string1, int len1, - const char *string2, int len2, - const char *string3, int len3) -{ - int rc; - struct presto_reservation_data rd; - loff_t offset; - struct presto_log_fd *fd; - struct kml_suffix *s; - int prefix_size; - - ENTRY; - - /* buf is NULL when no_journal is in effect */ - if (!buf) { - EXIT; - return -EINVAL; - } - - if (rec->is_kml) { - fd = &fset->fset_kml; - } else { - fd = &fset->fset_lml; - } - - presto_reserve_record(fset, fd, rec, &rd); - - if (rec->is_kml) { - if (rec->offset < fset->fset_kml_logical_off) { - CERROR("record with pre-trunc offset. tell phil.\n"); - BUG(); - } - offset = rec->offset - fset->fset_kml_logical_off; - } else { - offset = rec->offset; - } - - /* now we know the record number */ - prefix_size = size - sizeof(struct kml_suffix); - s = (struct kml_suffix *) (buf + prefix_size); - s->recno = cpu_to_le32(rec->recno); - - rc = presto_write_record(fd->fd_file, &offset, buf, size, - string1, len1, string2, len2, string3, len3); - if (rc) { - CERROR("presto: error writing record to %s\n", - rec->is_kml ? "KML" : "LML"); - return rc; - } - presto_release_record(fd, &rd); - - rc = presto_kml_dispatch(fset); - - EXIT; - return rc; -} - -/* read from the record at tail */ -static int presto_last_record(struct presto_log_fd *fd, loff_t *size, - loff_t *tail_offset, __u32 *recno, loff_t tail) -{ - struct kml_suffix suffix; - int rc; - loff_t zeroes; - - *recno = 0; - *tail_offset = 0; - *size = 0; - - if (tail < sizeof(struct kml_prefix_hdr) + sizeof(suffix)) { - EXIT; - return 0; - } - - zeroes = tail - sizeof(int); - while ( zeroes >= 0 ) { - int data; - rc = presto_fread(fd->fd_file, (char *)&data, sizeof(data), - &zeroes); - if ( rc != sizeof(data) ) { - rc = -EIO; - return rc; - } - if (data) - break; - zeroes -= 2 * sizeof(data); - } - - /* zeroes at the begining of file. this is needed to prevent - presto_fread errors -SHP - */ - if (zeroes <= 0) return 0; - - zeroes -= sizeof(suffix) + sizeof(int); - rc = presto_fread(fd->fd_file, (char *)&suffix, sizeof(suffix), &zeroes); - if ( rc != sizeof(suffix) ) { - EXIT; - return rc; - } - if ( suffix.len > 500 ) { - CERROR("InterMezzo: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", - (long) zeroes, (long)*tail_offset, suffix.len); - } - - *recno = suffix.recno; - *size = suffix.len; - *tail_offset = zeroes; - return 0; -} - -static int izo_kml_last_recno(struct presto_log_fd *logfd) -{ - int rc; - loff_t size; - loff_t tail_offset; - int recno; - loff_t tail = logfd->fd_file->f_dentry->d_inode->i_size; - - rc = presto_last_record(logfd, &size, &tail_offset, &recno, tail); - if (rc != 0) { - EXIT; - return rc; - } - - logfd->fd_offset = tail_offset; - logfd->fd_recno = recno; - CDEBUG(D_JOURNAL, "setting fset_kml->fd_recno to %d, offset %Ld\n", - recno, tail_offset); - EXIT; - return 0; -} - -struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags) -{ - struct presto_cache *cache = fset->fset_cache; - struct file *f; - int error; - ENTRY; - - f = izo_fset_open(fset, name, flags, 0644); - error = PTR_ERR(f); - if (IS_ERR(f)) { - EXIT; - return f; - } - - error = -EINVAL; - if ( cache != presto_get_cache(f->f_dentry->d_inode) ) { - CERROR("InterMezzo: %s cache does not match fset cache!\n",name); - fset->fset_kml.fd_file = NULL; - filp_close(f, NULL); - f = NULL; - EXIT; - return f; - } - - if (cache->cache_filter && cache->cache_filter->o_trops && - cache->cache_filter->o_trops->tr_journal_data) { - cache->cache_filter->o_trops->tr_journal_data - (f->f_dentry->d_inode); - } else { - CERROR("InterMezzo WARNING: no file data logging!\n"); - } - - EXIT; - - return f; -} - -int izo_init_kml_file(struct presto_file_set *fset, struct presto_log_fd *logfd) -{ - int error = 0; - struct file *f; - - ENTRY; - if (logfd->fd_file) { - CDEBUG(D_INODE, "fset already has KML open\n"); - EXIT; - return 0; - } - - logfd->fd_lock = RW_LOCK_UNLOCKED; - INIT_LIST_HEAD(&logfd->fd_reservations); - f = izo_log_open(fset, "kml", O_RDWR | O_CREAT); - if (IS_ERR(f)) { - error = PTR_ERR(f); - return error; - } - - logfd->fd_file = f; - error = izo_kml_last_recno(logfd); - - if (error) { - logfd->fd_file = NULL; - filp_close(f, NULL); - CERROR("InterMezzo: IO error in KML of fset %s\n", - fset->fset_name); - EXIT; - return error; - } - fset->fset_lento_off = logfd->fd_offset; - fset->fset_lento_recno = logfd->fd_recno; - - EXIT; - return error; -} - -int izo_init_last_rcvd_file(struct presto_file_set *fset, struct presto_log_fd *logfd) -{ - int error = 0; - struct file *f; - struct rec_info recinfo; - - ENTRY; - if (logfd->fd_file != NULL) { - CDEBUG(D_INODE, "fset already has last_rcvd open\n"); - EXIT; - return 0; - } - - logfd->fd_lock = RW_LOCK_UNLOCKED; - INIT_LIST_HEAD(&logfd->fd_reservations); - f = izo_log_open(fset, "last_rcvd", O_RDWR | O_CREAT); - if (IS_ERR(f)) { - error = PTR_ERR(f); - return error; - } - - logfd->fd_file = f; - logfd->fd_offset = f->f_dentry->d_inode->i_size; - - error = izo_rep_cache_init(fset); - - if (presto_read_kml_logical_offset(&recinfo, fset) == 0) { - fset->fset_kml_logical_off = recinfo.offset; - } else { - /* The 'last_rcvd' file doesn't contain a kml offset record, - * probably because we just created 'last_rcvd'. Write one. */ - fset->fset_kml_logical_off = 0; - presto_write_kml_logical_offset(fset); - } - - EXIT; - return error; -} - -int izo_init_lml_file(struct presto_file_set *fset, struct presto_log_fd *logfd) -{ - int error = 0; - struct file *f; - - ENTRY; - if (logfd->fd_file) { - CDEBUG(D_INODE, "fset already has lml open\n"); - EXIT; - return 0; - } - - logfd->fd_lock = RW_LOCK_UNLOCKED; - INIT_LIST_HEAD(&logfd->fd_reservations); - f = izo_log_open(fset, "lml", O_RDWR | O_CREAT); - if (IS_ERR(f)) { - error = PTR_ERR(f); - return error; - } - - logfd->fd_file = f; - logfd->fd_offset = f->f_dentry->d_inode->i_size; - - EXIT; - return error; -} - -/* Get the KML-offset record from the last_rcvd file */ -int presto_read_kml_logical_offset(struct rec_info *recinfo, - struct presto_file_set *fset) -{ - loff_t off; - struct izo_rcvd_rec rec; - char uuid[16] = {0}; - - off = izo_rcvd_get(&rec, fset, uuid); - if (off < 0) - return -1; - - recinfo->offset = rec.lr_local_offset; - return 0; -} - -int presto_write_kml_logical_offset(struct presto_file_set *fset) -{ - loff_t rc; - struct izo_rcvd_rec rec; - char uuid[16] = {0}; - - rc = izo_rcvd_get(&rec, fset, uuid); - if (rc < 0) - memset(&rec, 0, sizeof(rec)); - - rec.lr_local_offset = - cpu_to_le64(fset->fset_kml_logical_off); - - return izo_rcvd_write(fset, &rec); -} - -struct file * presto_copy_kml_tail(struct presto_file_set *fset, - unsigned long int start) -{ - struct file *f; - int len; - loff_t read_off, write_off, bytes; - - ENTRY; - - /* Copy the tail of 'kml' to 'kml_tmp' */ - f = izo_log_open(fset, "kml_tmp", O_RDWR); - if (IS_ERR(f)) { - EXIT; - return f; - } - - write_off = 0; - read_off = start; - bytes = fset->fset_kml.fd_offset - start; - while (bytes > 0) { - char buf[4096]; - int toread; - - if (bytes > sizeof(buf)) - toread = sizeof(buf); - else - toread = bytes; - - len = presto_fread(fset->fset_kml.fd_file, buf, toread, - &read_off); - if (len <= 0) - break; - - if (presto_fwrite(f, buf, len, &write_off) != len) { - filp_close(f, NULL); - EXIT; - return ERR_PTR(-EIO); - } - - bytes -= len; - } - - EXIT; - return f; -} - - -/* LML records here */ -/* this writes an LML record to the LML file (rec->is_kml =0) */ -int presto_write_lml_close(struct rec_info *rec, - struct presto_file_set *fset, - struct file *file, - __u64 remote_ino, - __u64 remote_generation, - struct presto_version *remote_version, - struct presto_version *new_file_ver) -{ - int opcode = KML_OPCODE_CLOSE; - char *buffer; - struct dentry *dentry = file->f_dentry; - __u64 ino; - __u32 pathlen; - char *path; - __u32 generation; - int size; - char *logrecord; - char record[292]; - struct dentry *root; - int error; - - ENTRY; - - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - root = fset->fset_dentry; - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - CDEBUG(D_INODE, "Path: %s\n", path); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - ino = cpu_to_le64(dentry->d_inode->i_ino); - generation = cpu_to_le32(dentry->d_inode->i_generation); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) + - sizeof(ino) + sizeof(generation) + sizeof(pathlen) + - sizeof(remote_ino) + sizeof(remote_generation) + - sizeof(remote_version) + sizeof(rec->offset) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 0; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, new_file_ver); - logrecord = logit(logrecord, &ino, sizeof(ino)); - logrecord = logit(logrecord, &generation, sizeof(generation)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, &remote_ino, sizeof(remote_ino)); - logrecord = logit(logrecord, &remote_generation, - sizeof(remote_generation)); - logrecord = log_version(logrecord, remote_version); - logrecord = logit(logrecord, &rec->offset, sizeof(rec->offset)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - BUFF_FREE(buffer); - - EXIT; - return error; -} - -/* - * Check if the given record is at the end of the file. If it is, truncate - * the lml to the record's offset, removing it. Repeat on prior record, - * until we reach an active record or a reserved record (as defined by the - * reservations list). - */ -static int presto_truncate_lml_tail(struct presto_file_set *fset) -{ - loff_t lml_tail; - loff_t lml_last_rec; - loff_t lml_last_recsize; - loff_t local_offset; - int recno; - struct kml_prefix_hdr prefix; - struct inode *inode = fset->fset_lml.fd_file->f_dentry->d_inode; - void *handle; - int rc; - - ENTRY; - /* If someone else is already truncating the LML, return. */ - write_lock(&fset->fset_lml.fd_lock); - if (fset->fset_lml.fd_truncating == 1 ) { - write_unlock(&fset->fset_lml.fd_lock); - EXIT; - return 0; - } - /* someone is about to write to the end of the LML */ - if ( !list_empty(&fset->fset_lml.fd_reservations) ) { - write_unlock(&fset->fset_lml.fd_lock); - EXIT; - return 0; - } - lml_tail = fset->fset_lml.fd_file->f_dentry->d_inode->i_size; - /* Nothing to truncate?*/ - if (lml_tail == 0) { - write_unlock(&fset->fset_lml.fd_lock); - EXIT; - return 0; - } - fset->fset_lml.fd_truncating = 1; - write_unlock(&fset->fset_lml.fd_lock); - - presto_last_record(&fset->fset_lml, &lml_last_recsize, - &lml_last_rec, &recno, lml_tail); - /* Do we have a record to check? If not we have zeroes at the - beginning of the file. -SHP - */ - if (lml_last_recsize != 0) { - local_offset = lml_last_rec - lml_last_recsize; - rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix, - sizeof(prefix), &local_offset); - if (rc != sizeof(prefix)) { - EXIT; - goto tr_out; - } - - if ( prefix.opcode != KML_OPCODE_NOOP ) { - EXIT; - rc = 0; - /* We may have zeroes at the end of the file, should - we clear them out? -SHP - */ - goto tr_out; - } - } else - lml_last_rec=0; - - handle = presto_trans_start(fset, inode, KML_OPCODE_TRUNC); - if ( IS_ERR(handle) ) { - EXIT; - rc = -ENOMEM; - goto tr_out; - } - - rc = izo_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, - lml_last_rec - lml_last_recsize, lml_tail); - presto_trans_commit(fset, handle); - if ( rc == 0 ) { - rc = 1; - } - EXIT; - - tr_out: - CDEBUG(D_JOURNAL, "rc = %d\n", rc); - write_lock(&fset->fset_lml.fd_lock); - fset->fset_lml.fd_truncating = 0; - write_unlock(&fset->fset_lml.fd_lock); - return rc; -} - -int presto_truncate_lml(struct presto_file_set *fset) -{ - int rc; - ENTRY; - - while ( (rc = presto_truncate_lml_tail(fset)) > 0); - if ( rc < 0 && rc != -EALREADY) { - CERROR("truncate_lml error %d\n", rc); - } - EXIT; - return rc; -} - -int presto_clear_lml_close(struct presto_file_set *fset, loff_t lml_offset) -{ - int rc; - struct kml_prefix_hdr record; - loff_t offset = lml_offset; - - ENTRY; - - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", - (long)lml_offset, sizeof(record)); - rc = presto_fread(fset->fset_lml.fd_file, (char *)&record, - sizeof(record), &offset); - - if ( rc != sizeof(record) ) { - CERROR("presto: clear_lml io error %d\n", rc); - EXIT; - return -EIO; - } - - /* overwrite the prefix */ - CDEBUG(D_JOURNAL, "overwriting prefix: off %ld\n", (long)lml_offset); - record.opcode = KML_OPCODE_NOOP; - offset = lml_offset; - /* note: this does just a single transaction in the cache */ - rc = presto_fwrite(fset->fset_lml.fd_file, (char *)(&record), - sizeof(record), &offset); - if ( rc != sizeof(record) ) { - EXIT; - return -EIO; - } - - EXIT; - return 0; -} - - - -/* now a journal function for every operation */ - -int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, struct presto_version *old_ver, - struct izo_rollback_data *rb, struct iattr *iattr) -{ - int opcode = KML_OPCODE_SETATTR; - char *buffer, *path, *logrecord, record[316]; - struct dentry *root; - __u32 uid, gid, mode, valid, flags, pathlen; - __u64 fsize, mtime, ctime; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) - || ((dentry->d_parent != dentry) && d_unhashed(dentry))) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + sizeof(*old_ver) + - sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) + - sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) + - sizeof(pathlen) + sizeof(*rb) + sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - /* Only journal one kind of mtime, and not atime at all. Also don't - * journal bogus data in iattr, to make the journal more compressible. - */ - if (iattr->ia_valid & ATTR_MTIME_SET) - iattr->ia_valid = iattr->ia_valid | ATTR_MTIME; - valid = cpu_to_le32(iattr->ia_valid & ~(ATTR_ATIME | ATTR_MTIME_SET | - ATTR_ATIME_SET)); - mode = iattr->ia_valid & ATTR_MODE ? cpu_to_le32(iattr->ia_mode): 0; - uid = iattr->ia_valid & ATTR_UID ? cpu_to_le32(iattr->ia_uid): 0; - gid = iattr->ia_valid & ATTR_GID ? cpu_to_le32(iattr->ia_gid): 0; - fsize = iattr->ia_valid & ATTR_SIZE ? cpu_to_le64(iattr->ia_size): 0; - mtime = iattr->ia_valid & ATTR_MTIME ? cpu_to_le64(iattr->ia_mtime.tv_sec): 0; - ctime = iattr->ia_valid & ATTR_CTIME ? cpu_to_le64(iattr->ia_ctime.tv_sec): 0; - flags = iattr->ia_valid & ATTR_ATTR_FLAG ? - cpu_to_le32(iattr->ia_attr_flags): 0; - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, old_ver); - logrecord = logit(logrecord, &valid, sizeof(valid)); - logrecord = logit(logrecord, &mode, sizeof(mode)); - logrecord = logit(logrecord, &uid, sizeof(uid)); - logrecord = logit(logrecord, &gid, sizeof(gid)); - logrecord = logit(logrecord, &fsize, sizeof(fsize)); - logrecord = logit(logrecord, &mtime, sizeof(mtime)); - logrecord = logit(logrecord, &ctime, sizeof(ctime)); - logrecord = logit(logrecord, &flags, sizeof(flags)); - logrecord = log_rollback(logrecord, rb); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int presto_get_fileid(int minor, struct presto_file_set *fset, - struct dentry *dentry) -{ - int opcode = KML_OPCODE_GET_FILEID; - struct rec_info rec; - char *buffer, *path, *logrecord, record[4096]; /*include path*/ - struct dentry *root; - __u32 uid, gid, pathlen; - int error, size; - struct kml_suffix *suffix; - - ENTRY; - - root = fset->fset_dentry; - - uid = cpu_to_le32(dentry->d_inode->i_uid); - gid = cpu_to_le32(dentry->d_inode->i_gid); - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + sizeof(pathlen) + - size_round(le32_to_cpu(pathlen)) + - sizeof(struct kml_suffix); - - CDEBUG(D_FILE, "kml size: %d\n", size); - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - memset(&rec, 0, sizeof(rec)); - rec.is_kml = 1; - rec.size = size; - - logrecord = journal_log_prefix(record, opcode, &rec); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, path, size_round(le32_to_cpu(pathlen))); - suffix = (struct kml_suffix *)logrecord; - logrecord = journal_log_suffix(logrecord, record, fset, dentry, &rec); - /* journal_log_suffix expects journal_log to set this */ - suffix->recno = 0; - - CDEBUG(D_FILE, "actual kml size: %Zd\n", logrecord - record); - CDEBUG(D_FILE, "get fileid: uid %d, gid %d, path: %s\n", uid, gid,path); - - error = izo_upc_get_fileid(minor, size, record, - size_round(le32_to_cpu(pathlen)), path, - fset->fset_name); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *new_file_ver, int mode) -{ - int opcode = KML_OPCODE_CREATE; - char *buffer, *path, *logrecord, record[292]; - struct dentry *root; - __u32 uid, gid, lmode, pathlen; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - uid = cpu_to_le32(dentry->d_inode->i_uid); - gid = cpu_to_le32(dentry->d_inode->i_gid); - lmode = cpu_to_le32(mode); - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dentry->d_parent); - logrecord = log_version(logrecord, new_file_ver); - logrecord = logit(logrecord, &lmode, sizeof(lmode)); - logrecord = logit(logrecord, &uid, sizeof(uid)); - logrecord = logit(logrecord, &gid, sizeof(gid)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, const char *target, - struct presto_version *tgt_dir_ver, - struct presto_version *new_link_ver) -{ - int opcode = KML_OPCODE_SYMLINK; - char *buffer, *path, *logrecord, record[292]; - struct dentry *root; - __u32 uid, gid, pathlen; - __u32 targetlen = cpu_to_le32(strlen(target)); - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - uid = cpu_to_le32(dentry->d_inode->i_uid); - gid = cpu_to_le32(dentry->d_inode->i_gid); - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(uid) + sizeof(gid) + sizeof(pathlen) + - sizeof(targetlen) + sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)) + - size_round(le32_to_cpu(targetlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dentry->d_parent); - logrecord = log_version(logrecord, new_link_ver); - logrecord = logit(logrecord, &uid, sizeof(uid)); - logrecord = logit(logrecord, &gid, sizeof(gid)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, &targetlen, sizeof(targetlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - target, size_round(le32_to_cpu(targetlen)), - NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *tgt_dir_ver, - struct presto_version *new_dir_ver, int mode) -{ - int opcode = KML_OPCODE_MKDIR; - char *buffer, *path, *logrecord, record[292]; - struct dentry *root; - __u32 uid, gid, lmode, pathlen; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - uid = cpu_to_le32(dentry->d_inode->i_uid); - gid = cpu_to_le32(dentry->d_inode->i_gid); - lmode = cpu_to_le32(mode); - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - logrecord = journal_log_prefix(record, opcode, rec); - - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dentry->d_parent); - logrecord = log_version(logrecord, new_dir_ver); - logrecord = logit(logrecord, &lmode, sizeof(lmode)); - logrecord = logit(logrecord, &uid, sizeof(uid)); - logrecord = logit(logrecord, &gid, sizeof(gid)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - - -int -presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dir, struct presto_version *tgt_dir_ver, - struct presto_version *old_dir_ver, - struct izo_rollback_data *rb, int len, const char *name) -{ - int opcode = KML_OPCODE_RMDIR; - char *buffer, *path, *logrecord, record[316]; - __u32 pathlen, llen; - struct dentry *root; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - llen = cpu_to_le32(len); - BUFF_ALLOC(buffer, NULL); - path = presto_path(dir, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(pathlen) + sizeof(llen) + sizeof(*rb) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - CDEBUG(D_JOURNAL, "path: %s (%d), name: %s (%d), size %d\n", - path, pathlen, name, len, size); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)) + - size_round(len); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dir); - logrecord = log_version(logrecord, old_dir_ver); - logrecord = logit(logrecord, rb, sizeof(*rb)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, &llen, sizeof(llen)); - logrecord = journal_log_suffix(logrecord, record, fset, dir, rec); - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - name, size_round(len), - NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - - -int -presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dentry, struct presto_version *tgt_dir_ver, - struct presto_version *new_node_ver, int mode, - int dmajor, int dminor ) -{ - int opcode = KML_OPCODE_MKNOD; - char *buffer, *path, *logrecord, record[292]; - struct dentry *root; - __u32 uid, gid, lmode, lmajor, lminor, pathlen; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - uid = cpu_to_le32(dentry->d_inode->i_uid); - gid = cpu_to_le32(dentry->d_inode->i_gid); - lmode = cpu_to_le32(mode); - lmajor = cpu_to_le32(dmajor); - lminor = cpu_to_le32(dminor); - - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) + - sizeof(lminor) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dentry->d_parent); - logrecord = log_version(logrecord, new_node_ver); - logrecord = logit(logrecord, &lmode, sizeof(lmode)); - logrecord = logit(logrecord, &uid, sizeof(uid)); - logrecord = logit(logrecord, &gid, sizeof(gid)); - logrecord = logit(logrecord, &lmajor, sizeof(lmajor)); - logrecord = logit(logrecord, &lminor, sizeof(lminor)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int -presto_journal_link(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *src, struct dentry *tgt, - struct presto_version *tgt_dir_ver, - struct presto_version *new_link_ver) -{ - int opcode = KML_OPCODE_LINK; - char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292]; - __u32 pathlen, srcpathlen; - struct dentry *root; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - BUFF_ALLOC(srcbuffer, NULL); - srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE); - srcpathlen = cpu_to_le32(MYPATHLEN(srcbuffer, srcpath)); - - BUFF_ALLOC(buffer, srcbuffer); - path = presto_path(tgt, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(srcpathlen) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)) + - size_round(le32_to_cpu(srcpathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, tgt->d_parent); - logrecord = log_version(logrecord, new_link_ver); - logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec); - - error = presto_log(fset, rec, record, size, - srcpath, size_round(le32_to_cpu(srcpathlen)), - path, size_round(le32_to_cpu(pathlen)), - NULL, 0); - - BUFF_FREE(srcbuffer); - BUFF_FREE(buffer); - EXIT; - return error; -} - - -int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *src, struct dentry *tgt, - struct presto_version *src_dir_ver, - struct presto_version *tgt_dir_ver) -{ - int opcode = KML_OPCODE_RENAME; - char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292]; - __u32 pathlen, srcpathlen; - struct dentry *root; - int error, size; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - BUFF_ALLOC(srcbuffer, NULL); - srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE); - srcpathlen = cpu_to_le32(MYPATHLEN(srcbuffer, srcpath)); - - BUFF_ALLOC(buffer, srcbuffer); - path = presto_path(tgt, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 4 * sizeof(*src_dir_ver) + - sizeof(srcpathlen) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)) + - size_round(le32_to_cpu(srcpathlen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, src_dir_ver); - logrecord = log_dentry_version(logrecord, src->d_parent); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, tgt->d_parent); - logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec); - - error = presto_log(fset, rec, record, size, - srcpath, size_round(le32_to_cpu(srcpathlen)), - path, size_round(le32_to_cpu(pathlen)), - NULL, 0); - - BUFF_FREE(buffer); - BUFF_FREE(srcbuffer); - EXIT; - return error; -} - -int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, - struct dentry *dir, struct presto_version *tgt_dir_ver, - struct presto_version *old_file_ver, - struct izo_rollback_data *rb, struct dentry *dentry, - char *old_target, int old_targetlen) -{ - int opcode = KML_OPCODE_UNLINK; - char *buffer, *path, *logrecord, record[316]; - const char *name; - __u32 pathlen, llen; - struct dentry *root; - int error, size, len; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - name = dentry->d_name.name; - len = dentry->d_name.len; - - llen = cpu_to_le32(len); - BUFF_ALLOC(buffer, NULL); - path = presto_path(dir, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) + - sizeof(pathlen) + sizeof(llen) + sizeof(*rb) + - sizeof(old_targetlen) + sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len) + - size_round(old_targetlen); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, tgt_dir_ver); - logrecord = log_dentry_version(logrecord, dir); - logrecord = log_version(logrecord, old_file_ver); - logrecord = log_rollback(logrecord, rb); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, &llen, sizeof(llen)); - logrecord = logit(logrecord, &old_targetlen, sizeof(old_targetlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dir, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - name, size_round(len), - old_target, size_round(old_targetlen)); - - BUFF_FREE(buffer); - EXIT; - return error; -} - -int -presto_journal_close(struct rec_info *rec, struct presto_file_set *fset, - struct presto_file_data *fd, struct dentry *dentry, - struct presto_version *old_file_ver, - struct presto_version *new_file_ver) -{ - int opcode = KML_OPCODE_CLOSE; - char *buffer, *path, *logrecord, record[316]; - struct dentry *root; - int error, size, i; - __u32 pathlen, generation; - __u64 ino; - __u32 open_fsuid; - __u32 open_fsgid; - __u32 open_ngroups; - __u32 open_groups[NGROUPS_SMALL]; - __u32 open_mode; - __u32 open_uid; - __u32 open_gid; - - ENTRY; - - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) - || ((dentry->d_parent != dentry) && d_unhashed(dentry))) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - if (fd) { - open_ngroups = fd->fd_ngroups; - for (i = 0; i < fd->fd_ngroups; i++) - open_groups[i] = (__u32) fd->fd_groups[i]; - open_mode = fd->fd_mode; - open_uid = fd->fd_uid; - open_gid = fd->fd_gid; - open_fsuid = fd->fd_fsuid; - open_fsgid = fd->fd_fsgid; - } else { - open_ngroups = current->group_info->ngroups; - for (i=0; igroup_info->ngroups; i++) - open_groups[i] = (__u32) GROUP_AT(current->group_info,i); - open_mode = dentry->d_inode->i_mode; - open_uid = dentry->d_inode->i_uid; - open_gid = dentry->d_inode->i_gid; - open_fsuid = current->fsuid; - open_fsgid = current->fsgid; - } - BUFF_ALLOC(buffer, NULL); - path = presto_path(dentry, root, buffer, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(buffer, path)); - ino = cpu_to_le64(dentry->d_inode->i_ino); - generation = cpu_to_le32(dentry->d_inode->i_generation); - size = sizeof(__u32) * open_ngroups + - sizeof(open_mode) + sizeof(open_uid) + sizeof(open_gid) + - sizeof(struct kml_prefix_hdr) + sizeof(*old_file_ver) + - sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) + - sizeof(pathlen) + sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix_with_groups_and_ids( - record, opcode, rec, open_ngroups, open_groups, - open_fsuid, open_fsgid); - logrecord = logit(logrecord, &open_mode, sizeof(open_mode)); - logrecord = logit(logrecord, &open_uid, sizeof(open_uid)); - logrecord = logit(logrecord, &open_gid, sizeof(open_gid)); - logrecord = log_version(logrecord, old_file_ver); - logrecord = log_version(logrecord, new_file_ver); - logrecord = logit(logrecord, &ino, sizeof(ino)); - logrecord = logit(logrecord, &generation, sizeof(generation)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - BUFF_FREE(buffer); - - EXIT; - return error; -} - -int presto_rewrite_close(struct rec_info *rec, struct presto_file_set *fset, - char *path, __u32 pathlen, - int ngroups, __u32 *groups, - __u64 ino, __u32 generation, - struct presto_version *new_file_ver) -{ - int opcode = KML_OPCODE_CLOSE; - char *logrecord, record[292]; - struct dentry *root; - int error, size; - - ENTRY; - - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - size = sizeof(__u32) * ngroups + - sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) + - sizeof(ino) + sizeof(generation) + - sizeof(le32_to_cpu(pathlen)) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - rec->size = size + size_round(le32_to_cpu(pathlen)); - - logrecord = journal_log_prefix_with_groups(record, opcode, rec, - ngroups, groups); - logrecord = log_version(logrecord, new_file_ver); - logrecord = logit(logrecord, &ino, sizeof(ino)); - logrecord = logit(logrecord, &generation, sizeof(generation)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = journal_log_suffix(logrecord, record, fset, NULL, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - NULL, 0, NULL, 0); - - EXIT; - return error; -} - - -/* write closes for the local close records in the LML */ -int presto_complete_lml(struct presto_file_set *fset) -{ - __u32 groups[NGROUPS_SMALL]; - loff_t lml_offset; - loff_t read_offset; - char *buffer; - void *handle; - struct rec_info rec; - struct close_rec { - struct presto_version new_file_ver; - __u64 ino; - __u32 generation; - __u32 pathlen; - __u64 remote_ino; - __u32 remote_generation; - __u32 remote_version; - __u64 lml_offset; - } close_rec; - struct file *file = fset->fset_lml.fd_file; - struct kml_prefix_hdr prefix; - int rc = 0; - ENTRY; - - lml_offset = 0; - again: - if (lml_offset >= file->f_dentry->d_inode->i_size) { - EXIT; - return rc; - } - - read_offset = lml_offset; - rc = presto_fread(file, (char *)&prefix, - sizeof(prefix), &read_offset); - if ( rc != sizeof(prefix) ) { - EXIT; - CERROR("presto_complete_lml: ioerror - 1, tell Peter\n"); - return -EIO; - } - - if ( prefix.opcode == KML_OPCODE_NOOP ) { - lml_offset += prefix.len; - goto again; - } - - rc = presto_fread(file, (char *)groups, - prefix.ngroups * sizeof(__u32), &read_offset); - if ( rc != prefix.ngroups * sizeof(__u32) ) { - EXIT; - CERROR("presto_complete_lml: ioerror - 2, tell Peter\n"); - return -EIO; - } - - rc = presto_fread(file, (char *)&close_rec, - sizeof(close_rec), &read_offset); - if ( rc != sizeof(close_rec) ) { - EXIT; - CERROR("presto_complete_lml: ioerror - 3, tell Peter\n"); - return -EIO; - } - - /* is this a backfetch or a close record? */ - if ( le64_to_cpu(close_rec.remote_ino) != 0 ) { - lml_offset += prefix.len; - goto again; - } - - BUFF_ALLOC(buffer, NULL); - rc = presto_fread(file, (char *)buffer, - le32_to_cpu(close_rec.pathlen), &read_offset); - if ( rc != le32_to_cpu(close_rec.pathlen) ) { - EXIT; - CERROR("presto_complete_lml: ioerror - 4, tell Peter\n"); - return -EIO; - } - - handle = presto_trans_start(fset, file->f_dentry->d_inode, - KML_OPCODE_RELEASE); - if ( IS_ERR(handle) ) { - EXIT; - return -ENOMEM; - } - - rc = presto_clear_lml_close(fset, lml_offset); - if ( rc ) { - CERROR("error during clearing: %d\n", rc); - presto_trans_commit(fset, handle); - EXIT; - return rc; - } - - rc = presto_rewrite_close(&rec, fset, buffer, close_rec.pathlen, - prefix.ngroups, groups, - close_rec.ino, close_rec.generation, - &close_rec.new_file_ver); - if ( rc ) { - CERROR("error during rewrite close: %d\n", rc); - presto_trans_commit(fset, handle); - EXIT; - return rc; - } - - presto_trans_commit(fset, handle); - if ( rc ) { - CERROR("error during truncation: %d\n", rc); - EXIT; - return rc; - } - - lml_offset += prefix.len; - CDEBUG(D_JOURNAL, "next LML record at: %ld\n", (long)lml_offset); - goto again; - - EXIT; - return -EINVAL; -} - - -#ifdef CONFIG_FS_EXT_ATTR -/* Journal an ea operation. A NULL buffer implies the attribute is - * getting deleted. In this case we simply change the opcode, but nothing - * else is affected. - */ -int presto_journal_set_ext_attr (struct rec_info *rec, - struct presto_file_set *fset, - struct dentry *dentry, - struct presto_version *ver, const char *name, - const char *buffer, int buffer_len, - int flags) -{ - int opcode = (buffer == NULL) ? - KML_OPCODE_DELEXTATTR : - KML_OPCODE_SETEXTATTR ; - char *temp, *path, *logrecord, record[292]; - struct dentry *root; - int error, size; - __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX)); - __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0); - __u32 mode, pathlen; - - ENTRY; - if ( presto_no_journal(fset) ) { - EXIT; - return 0; - } - - if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) - || ((dentry->d_parent != dentry) && d_unhashed(dentry))) { - EXIT; - return 0; - } - - root = fset->fset_dentry; - - BUFF_ALLOC(temp, NULL); - path = presto_path(dentry, root, temp, PAGE_SIZE); - pathlen = cpu_to_le32(MYPATHLEN(temp, path)); - - flags=cpu_to_le32(flags); - /* Ugly, but needed. posix ACLs change the mode without using - * setattr, we need to record these changes. The EA code per se - * is not really affected. - */ - mode=cpu_to_le32(dentry->d_inode->i_mode); - - size = sizeof(__u32) * current->group_info->ngroups + - sizeof(struct kml_prefix_hdr) + - 2 * sizeof(struct presto_version) + - sizeof(flags) + sizeof(mode) + sizeof(namelen) + - sizeof(buflen) + sizeof(pathlen) + - sizeof(struct kml_suffix); - - if ( size > sizeof(record) ) - CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__); - - rec->is_kml = 1; - /* Make space for a path, a attr name and value*/ - /* We use the buflen instead of buffer_len to make sure that we - * journal the right length. This may be a little paranoid, but - * with 64 bits round the corner, I would rather be safe than sorry! - * Also this handles deletes with non-zero buffer_lengths correctly. - * SHP - */ - rec->size = size + size_round(le32_to_cpu(pathlen)) + - size_round(le32_to_cpu(namelen)) + - size_round(le32_to_cpu(buflen)); - - logrecord = journal_log_prefix(record, opcode, rec); - logrecord = log_version(logrecord, ver); - logrecord = log_dentry_version(logrecord, dentry); - logrecord = logit(logrecord, &flags, sizeof(flags)); - logrecord = logit(logrecord, &mode, sizeof(flags)); - logrecord = logit(logrecord, &pathlen, sizeof(pathlen)); - logrecord = logit(logrecord, &namelen, sizeof(namelen)); - logrecord = logit(logrecord, &buflen, sizeof(buflen)); - logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec); - - error = presto_log(fset, rec, record, size, - path, size_round(le32_to_cpu(pathlen)), - name, size_round(le32_to_cpu(namelen)), - buffer, size_round(le32_to_cpu(buflen))); - - BUFF_FREE(temp); - EXIT; - return error; -} -#endif diff --git a/fs/intermezzo/journal_ext2.c b/fs/intermezzo/journal_ext2.c deleted file mode 100644 index d1cb293c2..000000000 --- a/fs/intermezzo/journal_ext2.c +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#if defined(CONFIG_EXT2_FS) - -/* EXT2 has no journalling, so these functions do nothing */ -static loff_t presto_e2_freespace(struct presto_cache *cache, - struct super_block *sb) -{ - unsigned long freebl = le32_to_cpu(EXT2_SB(sb)->s_es->s_free_blocks_count); - unsigned long avail = freebl - le32_to_cpu(EXT2_SB(sb)->s_es->s_r_blocks_count); - return (avail << EXT2_BLOCK_SIZE_BITS(sb)); -} - -/* start the filesystem journal operations */ -static void *presto_e2_trans_start(struct presto_file_set *fset, struct inode *inode, int op) -{ - __u32 avail_kmlblocks; - - if ( presto_no_journal(fset) || - strcmp(fset->fset_cache->cache_type, "ext2")) - return NULL; - - avail_kmlblocks = EXT2_SB(inode->i_sb)->s_es->s_free_blocks_count; - - if ( avail_kmlblocks < 3 ) { - return ERR_PTR(-ENOSPC); - } - - if ( (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR) - && avail_kmlblocks < 6 ) { - return ERR_PTR(-ENOSPC); - } - return (void *) 1; -} - -static void presto_e2_trans_commit(struct presto_file_set *fset, void *handle) -{ - do {} while (0); -} - -static int presto_e2_has_all_data(struct inode *inode) -{ - BUG(); - return 0; -} - -struct journal_ops presto_ext2_journal_ops = { - .tr_all_data = presto_e2_has_all_data, - .tr_avail = presto_e2_freespace, - .tr_start = presto_e2_trans_start, - .tr_commit = presto_e2_trans_commit, - .tr_journal_data = NULL -}; - -#endif /* CONFIG_EXT2_FS */ diff --git a/fs/intermezzo/journal_ext3.c b/fs/intermezzo/journal_ext3.c deleted file mode 100644 index b847b6198..000000000 --- a/fs/intermezzo/journal_ext3.c +++ /dev/null @@ -1,283 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2001 Mountain View Data, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE) -#include -#include -#include -#endif - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE) - -#define MAX_PATH_BLOCKS(inode) (PATH_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb)) -#define MAX_NAME_BLOCKS(inode) (NAME_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb)) - -/* space requirements: - presto_do_truncate: - used to truncate the KML forward to next fset->chunksize boundary - - zero partial block - - update inode - presto_write_record: - write header (< one block) - write one path (< MAX_PATHLEN) - possibly write another path (< MAX_PATHLEN) - write suffix (< one block) - presto_update_last_rcvd - write one block -*/ - -static loff_t presto_e3_freespace(struct presto_cache *cache, - struct super_block *sb) -{ - loff_t freebl = le32_to_cpu(EXT3_SB(sb)->s_es->s_free_blocks_count); - loff_t avail = freebl - - le32_to_cpu(EXT3_SB(sb)->s_es->s_r_blocks_count); - return (avail << EXT3_BLOCK_SIZE_BITS(sb)); -} - -/* start the filesystem journal operations */ -static void *presto_e3_trans_start(struct presto_file_set *fset, - struct inode *inode, - int op) -{ - int jblocks; - int trunc_blks, one_path_blks, extra_path_blks, - extra_name_blks, lml_blks; - __u32 avail_kmlblocks; - handle_t *handle; - - if ( presto_no_journal(fset) || - strcmp(fset->fset_cache->cache_type, "ext3")) - { - CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n", - fset->fset_cache->cache_type); - return NULL; - } - - avail_kmlblocks = EXT3_SB(inode->i_sb)->s_es->s_free_blocks_count; - - if ( avail_kmlblocks < 3 ) { - return ERR_PTR(-ENOSPC); - } - - if ( (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR) - && avail_kmlblocks < 6 ) { - return ERR_PTR(-ENOSPC); - } - - /* Need journal space for: - at least three writes to KML (two one block writes, one a path) - possibly a second name (unlink, rmdir) - possibly a second path (symlink, rename) - a one block write to the last rcvd file - */ - - trunc_blks = EXT3_DATA_TRANS_BLOCKS + 1; - one_path_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 3; - lml_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 2; - extra_path_blks = EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode); - extra_name_blks = EXT3_DATA_TRANS_BLOCKS + MAX_NAME_BLOCKS(inode); - - /* additional blocks appear for "two pathname" operations - and operations involving the LML records - */ - switch (op) { - case KML_OPCODE_TRUNC: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS; - break; - case KML_OPCODE_KML_TRUNC: - /* Hopefully this is a little better, but I'm still mostly - * guessing here. */ - /* unlink 1 */ - jblocks = extra_name_blks + trunc_blks + - EXT3_DELETE_TRANS_BLOCKS + 2; - - /* unlink 2 */ - jblocks += extra_name_blks + trunc_blks + - EXT3_DELETE_TRANS_BLOCKS + 2; - - /* rename 1 */ - jblocks += 2 * extra_path_blks + trunc_blks + - 2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3; - - /* rename 2 */ - jblocks += 2 * extra_path_blks + trunc_blks + - 2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3; - break; - case KML_OPCODE_RELEASE: - /* - jblocks = one_path_blks + lml_blks + 2*trunc_blks; - */ - jblocks = one_path_blks; - break; - case KML_OPCODE_SETATTR: - jblocks = one_path_blks + trunc_blks + 1 ; - break; - case KML_OPCODE_CREATE: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 3 + 2; - break; - case KML_OPCODE_LINK: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 2; - break; - case KML_OPCODE_UNLINK: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS + 2; - break; - case KML_OPCODE_SYMLINK: - jblocks = one_path_blks + extra_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 5; - break; - case KML_OPCODE_MKDIR: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 4 + 2; - break; - case KML_OPCODE_RMDIR: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS + 1; - break; - case KML_OPCODE_MKNOD: - jblocks = one_path_blks + trunc_blks + - EXT3_DATA_TRANS_BLOCKS + 3 + 2; - break; - case KML_OPCODE_RENAME: - jblocks = one_path_blks + extra_path_blks + trunc_blks + - 2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3; - break; - case KML_OPCODE_WRITE: - jblocks = one_path_blks; - /* add this when we can wrap our transaction with - that of ext3_file_write (ordered writes) - + EXT3_DATA_TRANS_BLOCKS; - */ - break; - default: - CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op); - return NULL; - } - - CDEBUG(D_JOURNAL, "creating journal handle (%d blocks) for op %d\n", - jblocks, op); - /* journal_start/stop does not do its own locking while updating - * the handle/transaction information. Hence we create our own - * critical section to protect these calls. -SHP - */ - lock_kernel(); - handle = journal_start(EXT3_JOURNAL(inode), jblocks); - unlock_kernel(); - return handle; -} - -static void presto_e3_trans_commit(struct presto_file_set *fset, void *handle) -{ - if ( presto_no_journal(fset) || !handle) - return; - - /* See comments before journal_start above. -SHP */ - lock_kernel(); - journal_stop(handle); - unlock_kernel(); -} - -static void presto_e3_journal_file_data(struct inode *inode) -{ -#ifdef EXT3_JOURNAL_DATA_FL - EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL; -#else -#warning You must have a facility to enable journaled writes for recovery! -#endif -} - -/* The logic here is a slightly modified version of ext3/inode.c:block_to_path - */ -static int presto_e3_has_all_data(struct inode *inode) -{ - int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT3_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)); - long block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; - - ENTRY; - - if (inode->i_size == 0) { - EXIT; - return 1; - } - - if (block < direct_blocks) { - /* No indirect blocks, no problem. */ - } else if (block < indirect_blocks + direct_blocks) { - block++; - } else if (block < double_blocks + indirect_blocks + direct_blocks) { - block += 2; - } else if (((block - double_blocks - indirect_blocks - direct_blocks) - >> (ptrs_bits * 2)) < ptrs) { - block += 3; - } - - block *= (inode->i_sb->s_blocksize / 512); - - CDEBUG(D_CACHE, "Need %ld blocks, have %ld.\n", block, inode->i_blocks); - - if (block > inode->i_blocks) { - EXIT; - return 0; - } - - EXIT; - return 1; -} - -struct journal_ops presto_ext3_journal_ops = { - .tr_all_data = presto_e3_has_all_data, - .tr_avail = presto_e3_freespace, - .tr_start = presto_e3_trans_start, - .tr_commit = presto_e3_trans_commit, - .tr_journal_data = presto_e3_journal_file_data, - .tr_ilookup = presto_iget_ilookup -}; - -#endif /* CONFIG_EXT3_FS */ diff --git a/fs/intermezzo/journal_obdfs.c b/fs/intermezzo/journal_obdfs.c deleted file mode 100644 index 702ee8b64..000000000 --- a/fs/intermezzo/journal_obdfs.c +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2001 Mountain View Data, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_OBDFS_FS -#include /usr/src/obd/include/linux/obdfs.h -#endif - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#ifdef CONFIG_OBDFS_FS - - -static unsigned long presto_obdfs_freespace(struct presto_file_set *fset, - struct super_block *sb) -{ - return 0x0fffff; -} - -/* start the filesystem journal operations */ -static void *presto_obdfs_trans_start(struct presto_file_set *fset, - struct inode *inode, - int op) -{ - - return (void *) 1; -} - -#if 0 - int jblocks; - int trunc_blks, one_path_blks, extra_path_blks, - extra_name_blks, lml_blks; - __u32 avail_kmlblocks; - - if ( presto_no_journal(fset) || - strcmp(fset->fset_cache->cache_type, "ext3")) - { - CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n", - fset->fset_cache->cache_type); - return NULL; - } - - avail_kmlblocks = inode->i_sb->u.ext3_sb.s_es->s_free_blocks_count; - - if ( avail_kmlblocks < 3 ) { - return ERR_PTR(-ENOSPC); - } - - if ( (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR) - && avail_kmlblocks < 6 ) { - return ERR_PTR(-ENOSPC); - } - - /* Need journal space for: - at least three writes to KML (two one block writes, one a path) - possibly a second name (unlink, rmdir) - possibly a second path (symlink, rename) - a one block write to the last rcvd file - */ - - trunc_blks = EXT3_DATA_TRANS_BLOCKS + 1; - one_path_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 3; - lml_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 2; - extra_path_blks = EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode); - extra_name_blks = EXT3_DATA_TRANS_BLOCKS + MAX_NAME_BLOCKS(inode); - - /* additional blocks appear for "two pathname" operations - and operations involving the LML records - */ - switch (op) { - case PRESTO_OP_TRUNC: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS; - break; - case PRESTO_OP_RELEASE: - /* - jblocks = one_path_blks + lml_blks + 2*trunc_blks; - */ - jblocks = one_path_blks; - break; - case PRESTO_OP_SETATTR: - jblocks = one_path_blks + trunc_blks + 1 ; - break; - case PRESTO_OP_CREATE: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 3; - break; - case PRESTO_OP_LINK: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS; - break; - case PRESTO_OP_UNLINK: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS; - break; - case PRESTO_OP_SYMLINK: - jblocks = one_path_blks + extra_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 5; - break; - case PRESTO_OP_MKDIR: - jblocks = one_path_blks + trunc_blks - + EXT3_DATA_TRANS_BLOCKS + 4; - break; - case PRESTO_OP_RMDIR: - jblocks = one_path_blks + extra_name_blks + trunc_blks - + EXT3_DELETE_TRANS_BLOCKS; - break; - case PRESTO_OP_MKNOD: - jblocks = one_path_blks + trunc_blks + - EXT3_DATA_TRANS_BLOCKS + 3; - break; - case PRESTO_OP_RENAME: - jblocks = one_path_blks + extra_path_blks + trunc_blks + - 2 * EXT3_DATA_TRANS_BLOCKS + 2; - break; - case PRESTO_OP_WRITE: - jblocks = one_path_blks; - /* add this when we can wrap our transaction with - that of ext3_file_write (ordered writes) - + EXT3_DATA_TRANS_BLOCKS; - */ - break; - default: - CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op); - return NULL; - } - - CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks); - return journal_start(EXT3_JOURNAL(inode), jblocks); -} -#endif - -void presto_obdfs_trans_commit(struct presto_file_set *fset, void *handle) -{ -#if 0 - if ( presto_no_journal(fset) || !handle) - return; - - journal_stop(handle); -#endif -} - -void presto_obdfs_journal_file_data(struct inode *inode) -{ -#ifdef EXT3_JOURNAL_DATA_FL - inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL; -#else -#warning You must have a facility to enable journaled writes for recovery! -#endif -} - -struct journal_ops presto_obdfs_journal_ops = { - .tr_avail = presto_obdfs_freespace, - .tr_start = presto_obdfs_trans_start, - .tr_commit = presto_obdfs_trans_commit, - .tr_journal_data = presto_obdfs_journal_file_data -}; - -#endif diff --git a/fs/intermezzo/journal_reiserfs.c b/fs/intermezzo/journal_reiserfs.c deleted file mode 100644 index 93fc14845..000000000 --- a/fs/intermezzo/journal_reiserfs.c +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2001 Mountain View Data, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if 0 -#if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) -#include -#include -#include -#endif - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) - - -static loff_t presto_reiserfs_freespace(struct presto_cache *cache, - struct super_block *sb) -{ - struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (sb); - loff_t avail; - - avail = le32_to_cpu(rs->s_free_blocks) * - le16_to_cpu(rs->s_blocksize); - return avail; -} - -/* start the filesystem journal operations */ -static void *presto_reiserfs_trans_start(struct presto_file_set *fset, - struct inode *inode, - int op) -{ - int jblocks; - __u32 avail_kmlblocks; - struct reiserfs_transaction_handle *th ; - - PRESTO_ALLOC(th, sizeof(*th)); - if (!th) { - CERROR("presto: No memory for trans handle\n"); - return NULL; - } - - avail_kmlblocks = presto_reiserfs_freespace(fset->fset_cache, - inode->i_sb); - if ( presto_no_journal(fset) || - strcmp(fset->fset_cache->cache_type, "reiserfs")) - { - CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n", - fset->fset_cache->cache_type); - return NULL; - } - - if ( avail_kmlblocks < 3 ) { - return ERR_PTR(-ENOSPC); - } - - if ( (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR) - && avail_kmlblocks < 6 ) { - return ERR_PTR(-ENOSPC); - } - - jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4; - CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks); - - lock_kernel(); - journal_begin(th, inode->i_sb, jblocks); - unlock_kernel(); - return th; -} - -static void presto_reiserfs_trans_commit(struct presto_file_set *fset, - void *handle) -{ - int jblocks; - jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4; - - lock_kernel(); - journal_end(handle, fset->fset_cache->cache_sb, jblocks); - unlock_kernel(); - PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle)); -} - -static void presto_reiserfs_journal_file_data(struct inode *inode) -{ -#ifdef EXT3_JOURNAL_DATA_FL - inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL; -#else -#warning You must have a facility to enable journaled writes for recovery! -#endif -} - -static int presto_reiserfs_has_all_data(struct inode *inode) -{ - BUG(); - return 0; -} - -struct journal_ops presto_reiserfs_journal_ops = { - .tr_all_data = presto_reiserfs_has_all_data, - .tr_avail = presto_reiserfs_freespace, - .tr_start = presto_reiserfs_trans_start, - .tr_commit = presto_reiserfs_trans_commit, - .tr_journal_data = presto_reiserfs_journal_file_data -}; - -#endif -#endif diff --git a/fs/intermezzo/journal_tmpfs.c b/fs/intermezzo/journal_tmpfs.c deleted file mode 100644 index 4f3c463f0..000000000 --- a/fs/intermezzo/journal_tmpfs.c +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Los Alamos National Laboratory - * Copyright (C) 2000 TurboLinux, Inc. - * Copyright (C) 2001 Mountain View Data, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_TMPFS) -#include -#if defined(CONFIG_EXT3) -#include -#include -#endif -#endif - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#if defined(CONFIG_TMPFS) - -/* space requirements: - presto_do_truncate: - used to truncate the KML forward to next fset->chunksize boundary - - zero partial block - - update inode - presto_write_record: - write header (< one block) - write one path (< MAX_PATHLEN) - possibly write another path (< MAX_PATHLEN) - write suffix (< one block) - presto_update_last_rcvd - write one block -*/ - -static loff_t presto_tmpfs_freespace(struct presto_cache *cache, - struct super_block *sb) -{ - return (1<<30); -} - -/* start the filesystem journal operations */ -static void *presto_tmpfs_trans_start(struct presto_file_set *fset, - struct inode *inode, - int op) -{ - return (void *)1; -} - -static void presto_tmpfs_trans_commit(struct presto_file_set *fset, void *handle) -{ - return; -} - -static void presto_tmpfs_journal_file_data(struct inode *inode) -{ - return; -} - -/* The logic here is a slightly modified version of ext3/inode.c:block_to_path - */ -static int presto_tmpfs_has_all_data(struct inode *inode) -{ - return 0; -} - -struct journal_ops presto_tmpfs_journal_ops = { - .tr_all_data = presto_tmpfs_has_all_data, - .tr_avail = presto_tmpfs_freespace, - .tr_start = presto_tmpfs_trans_start, - .tr_commit = presto_tmpfs_trans_commit, - .tr_journal_data = presto_tmpfs_journal_file_data, - .tr_ilookup = presto_tmpfs_ilookup, - .tr_add_ilookup = presto_add_ilookup_dentry -}; - -#endif /* CONFIG_EXT3_FS */ diff --git a/fs/intermezzo/journal_xfs.c b/fs/intermezzo/journal_xfs.c deleted file mode 100644 index 59b22a500..000000000 --- a/fs/intermezzo/journal_xfs.c +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if 0 -/* XFS Support not there yet */ -#ifdef CONFIG_FS_XFS -#include -#endif -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" -#include "intermezzo_journal.h" - -#if 0 - -/* XFS has journalling, but these functions do nothing yet... */ - -static unsigned long presto_xfs_freespace(struct presto_file_set *fset, - struct super_block *sb) -{ - -#if 0 - vfs_t *vfsp = LINVFS_GET_VFS(sb); - struct statvfs_t stat; - bhv_desc_t *bdp; - unsigned long avail; - int rc; - - VFS_STATVFS(vfsp, &stat, NULL, rc); - avail = statp.f_bfree; - - return sbp->sb_fdblocks; -#endif - return 0x0fffffff; -} - - -/* start the filesystem journal operations */ -static void * -presto_xfs_trans_start(struct presto_file_set *fset, - struct inode *inode, int op) -{ - int xfs_op; - /* do a free blocks check as in journal_ext3? does anything protect - * the space in that case or can it disappear out from under us - * anyway? */ - -/* copied from xfs_trans.h, skipping header maze for now */ -#define XFS_TRANS_SETATTR_NOT_SIZE 1 -#define XFS_TRANS_SETATTR_SIZE 2 -#define XFS_TRANS_INACTIVE 3 -#define XFS_TRANS_CREATE 4 -#define XFS_TRANS_CREATE_TRUNC 5 -#define XFS_TRANS_TRUNCATE_FILE 6 -#define XFS_TRANS_REMOVE 7 -#define XFS_TRANS_LINK 8 -#define XFS_TRANS_RENAME 9 -#define XFS_TRANS_MKDIR 10 -#define XFS_TRANS_RMDIR 11 -#define XFS_TRANS_SYMLINK 12 - - /* map the op onto the values for XFS so it can do reservation. if - * we don't have enough info to differentiate between e.g. setattr - * with or without size, what do we do? will it adjust? */ - switch (op) { - case PRESTO_OP_SETATTR: - /* or XFS_TRANS_SETATTR_NOT_SIZE? */ - xfs_op = XFS_TRANS_SETATTR_SIZE; - break; - case PRESTO_OP_CREATE: - /* or CREATE_TRUNC? */ - xfs_op = XFS_TRANS_CREATE; - break; - case PRESTO_OP_LINK: - xfs_op = XFS_TRANS_LINK; - break; - case PRESTO_OP_UNLINK: - xfs_op = XFS_TRANS_REMOVE; - break; - case PRESTO_OP_SYMLINK: - xfs_op = XFS_TRANS_SYMLINK; - break; - case PRESTO_OP_MKDIR: - xfs_op = XFS_TRANS_MKDIR; - break; - case PRESTO_OP_RMDIR: - xfs_op = XFS_TRANS_RMDIR; - break; - case PRESTO_OP_MKNOD: - /* XXX can't find an analog for mknod? */ - xfs_op = XFS_TRANS_CREATE; - break; - case PRESTO_OP_RENAME: - xfs_op = XFS_TRANS_RENAME; - break; - default: - CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op); - return NULL; - } - - return xfs_trans_start(inode, xfs_op); -} - -static void presto_xfs_trans_commit(struct presto_file_set *fset, void *handle) -{ - /* assert (handle == current->j_handle) */ - xfs_trans_stop(handle); -} - -static void presto_xfs_journal_file_data(struct inode *inode) -{ - return; -} - -static int presto_xfs_has_all_data(struct inode *inode) -{ - BUG(); - return 0; -} - -struct journal_ops presto_xfs_journal_ops = { - .tr_all_data = presto_xfs_has_all_data, - .tr_avail = presto_xfs_freespace, - .tr_start = presto_xfs_trans_start, - .tr_commit = presto_xfs_trans_commit, - .tr_journal_data = presto_xfs_journal_file_data -}; - -#endif - - -#endif /* CONFIG_XFS_FS */ - diff --git a/fs/intermezzo/kml.c b/fs/intermezzo/kml.c deleted file mode 100644 index e992c18f8..000000000 --- a/fs/intermezzo/kml.c +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_upcall.h" -#include "intermezzo_psdev.h" -#include "intermezzo_kml.h" - -static struct presto_file_set * kml_getfset (char *path) -{ - return presto_path2fileset(path); -} - -/* Send the KML buffer and related volume info into kernel */ -int begin_kml_reint (struct file *file, unsigned long arg) -{ - struct { - char *volname; - int namelen; - char *recbuf; - int reclen; /* int newpos; */ - } input; - struct kml_fsdata *kml_fsdata = NULL; - struct presto_file_set *fset = NULL; - char *path; - int error; - - ENTRY; - /* allocate buffer & copy it to kernel space */ - if (copy_from_user(&input, (char *)arg, sizeof(input))) { - EXIT; - return -EFAULT; - } - - if (input.reclen > kml_fsdata->kml_maxsize) - return -ENOMEM; /* we'll find solution to this in the future */ - - PRESTO_ALLOC(path, char *, input.namelen + 1); - if ( !path ) { - EXIT; - return -ENOMEM; - } - if (copy_from_user(path, input.volname, input.namelen)) { - PRESTO_FREE(path, input.namelen + 1); - EXIT; - return -EFAULT; - } - path[input.namelen] = '\0'; - fset = kml_getfset (path); - PRESTO_FREE(path, input.namelen + 1); - - kml_fsdata = FSET_GET_KMLDATA(fset); - /* read the buf from user memory here */ - if (copy_from_user(kml_fsdata->kml_buf, input.recbuf, input.reclen)) { - EXIT; - return -EFAULT; - } - kml_fsdata->kml_len = input.reclen; - - decode_kmlrec (&kml_fsdata->kml_reint_cache, - kml_fsdata->kml_buf, kml_fsdata->kml_len); - - kml_fsdata->kml_reint_current = kml_fsdata->kml_reint_cache.next; - kml_fsdata->kml_reintpos = 0; - kml_fsdata->kml_count = 0; - return 0; -} - -/* DO_KML_REINT */ -int do_kml_reint (struct file *file, unsigned long arg) -{ - struct { - char *volname; - int namelen; - char *path; - int pathlen; - int recno; - int offset; - int len; - int generation; - __u64 ino; - } input; - int error; - char *path; - struct kml_rec *close_rec; - struct kml_fsdata *kml_fsdata; - struct presto_file_set *fset; - - ENTRY; - if (copy_from_user(&input, (char *)arg, sizeof(input))) { - EXIT; - return -EFAULT; - } - PRESTO_ALLOC(path, char *, input.namelen + 1); - if ( !path ) { - EXIT; - return -ENOMEM; - } - if (copy_from_user(path, input.volname, input.namelen)) { - PRESTO_FREE(path, input.namelen + 1); - EXIT; - return -EFAULT; - } - path[input.namelen] = '\0'; - fset = kml_getfset (path); - PRESTO_FREE(path, input.namelen + 1); - - kml_fsdata = FSET_GET_KMLDATA(fset); - - error = kml_reintbuf(kml_fsdata, - fset->fset_mtpt->d_name.name, - &close_rec); - - if (error == KML_CLOSE_BACKFETCH && close_rec != NULL) { - struct kml_close *close = &close_rec->rec_kml.close; - input.ino = close->ino; - input.generation = close->generation; - if (strlen (close->path) + 1 < input.pathlen) { - strcpy (input.path, close->path); - input.pathlen = strlen (close->path) + 1; - input.recno = close_rec->rec_tail.recno; - input.offset = close_rec->rec_kml_offset; - input.len = close_rec->rec_size; - input.generation = close->generation; - input.ino = close->ino; - } - else { - CDEBUG(D_KML, "KML_DO_REINT::no space to save:%d < %d", - strlen (close->path) + 1, input.pathlen); - error = -ENOMEM; - } - if (copy_to_user((char *)arg, &input, sizeof (input))) - return -EFAULT; - } - return error; -} - -/* END_KML_REINT */ -int end_kml_reint (struct file *file, unsigned long arg) -{ - /* Free KML buffer and related volume info */ - struct { - char *volname; - int namelen; -#if 0 - int count; - int newpos; -#endif - } input; - struct presto_file_set *fset = NULL; - struct kml_fsdata *kml_fsdata = NULL; - int error; - char *path; - - ENTRY; - if (copy_from_user(&input, (char *)arg, sizeof(input))) { - EXIT; - return -EFAULT; - } - - PRESTO_ALLOC(path, char *, input.namelen + 1); - if ( !path ) { - EXIT; - return -ENOMEM; - } - if (copy_from_user(path, input.volname, input.namelen)) { - if ( error ) { - PRESTO_FREE(path, input.namelen + 1); - EXIT; - return -EFAULT; - } - path[input.namelen] = '\0'; - fset = kml_getfset (path); - PRESTO_FREE(path, input.namelen + 1); - - kml_fsdata = FSET_GET_KMLDATA(fset); - delete_kmlrec (&kml_fsdata->kml_reint_cache); - - /* kml reint support */ - kml_fsdata->kml_reint_current = NULL; - kml_fsdata->kml_len = 0; - kml_fsdata->kml_reintpos = 0; - kml_fsdata->kml_count = 0; -#if 0 - input.newpos = kml_upc->newpos; - input.count = kml_upc->count; - if (copy_to_user((char *)arg, &input, sizeof (input))) - return -EFAULT; -#endif - return error; -} diff --git a/fs/intermezzo/kml_decode.c b/fs/intermezzo/kml_decode.c deleted file mode 100644 index f04e7d5fd..000000000 --- a/fs/intermezzo/kml_decode.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * KML Decoding - * - * Copryright (C) 1996 Arthur Ma - * - * Copyright (C) 2001 Mountainview Data, Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include "intermezzo_fs.h" -#include "intermezzo_kml.h" - -static int size_round (int val); -static int unpack_create (struct kml_create *rec, char *buf, - int pos, int *rec_offs); -static int unpack_open (struct kml_open *rec, char *buf, - int pos, int *rec_offs); -static int unpack_symlink (struct kml_symlink *rec, char *buf, - int pos, int *rec_offs); -static int unpack_mknod (struct kml_mknod *rec, char *buf, - int pos, int *rec_offs); -static int unpack_link (struct kml_link *rec, char *buf, - int pos, int *rec_offs); -static int unpack_rename (struct kml_rename *rec, char *buf, - int pos, int *rec_offs); -static int unpack_unlink (struct kml_unlink *rec, char *buf, - int pos, int *rec_offs); -static int unpack_rmdir (struct kml_rmdir *rec, char *buf, - int pos, int *rec_offs); -static int unpack_setattr (struct kml_setattr *rec, char *buf, - int pos, int *rec_offs); -static int unpack_close (struct kml_close *rec, char *buf, - int pos, int *rec_offs); -static int unpack_mkdir (struct kml_mkdir *rec, char *buf, - int pos, int *rec_offs); - -#if 0 -static int unpack_endmark (struct kml_endmark *rec, char *buf, - int pos, int *rec_offs); -static void print_kml_endmark (struct kml_endmark *rec); -#endif - -static int kml_unpack (char *kml_buf, int rec_size, int kml_offset, - struct kml_rec **newrec); -static char *kml_version (struct presto_version *ver); -static void print_kml_prefix (struct big_journal_prefix *head); -static void print_kml_create (struct kml_create *rec); -static void print_kml_mkdir (struct kml_mkdir *rec); -static void print_kml_unlink (struct kml_unlink *rec); -static void print_kml_rmdir (struct kml_rmdir *rec); -static void print_kml_close (struct kml_close *rec); -static void print_kml_symlink (struct kml_symlink *rec); -static void print_kml_rename (struct kml_rename *rec); -static void print_kml_setattr (struct kml_setattr *rec); -static void print_kml_link (struct kml_link *rec); -static void print_kml_mknod (struct kml_mknod *rec); -static void print_kml_open (struct kml_open *rec); -static void print_kml_suffix (struct journal_suffix *tail); -static char *readrec (char *recbuf, int reclen, int pos, int *size); - -#define KML_PREFIX_WORDS 8 -static int kml_unpack (char *kml_buf, int rec_size, int kml_offset, - struct kml_rec **newrec) -{ - struct kml_rec *rec; - char *p; - int pos, rec_offs; - int error; - - ENTRY; - if (rec_size < sizeof (struct journal_prefix) + - sizeof (struct journal_suffix)) - return -EBADF; - - PRESTO_ALLOC(rec, struct kml_rec *, sizeof (struct kml_rec)); - if (rec == NULL) { - EXIT; - return -ENOMEM; - } - rec->rec_kml_offset = kml_offset; - rec->rec_size = rec_size; - p = kml_buf; - p = dlogit (&rec->rec_head, p, KML_PREFIX_WORDS * sizeof (int)); - p = dlogit (&rec->rec_head.groups, p, - sizeof (int) * rec->rec_head.ngroups); - - pos = sizeof (struct journal_prefix) + - sizeof (int) * rec->rec_head.ngroups; - switch (rec->rec_head.opcode) - { - case KML_CREATE: - error = unpack_create (&rec->rec_kml.create, - kml_buf, pos, &rec_offs); - break; - case KML_MKDIR: - error = unpack_mkdir (&rec->rec_kml.mkdir, - kml_buf, pos, &rec_offs); - break; - case KML_UNLINK: - error = unpack_unlink (&rec->rec_kml.unlink, - kml_buf, pos, &rec_offs); - break; - case KML_RMDIR: - error = unpack_rmdir (&rec->rec_kml.rmdir, - kml_buf, pos, &rec_offs); - break; - case KML_CLOSE: - error = unpack_close (&rec->rec_kml.close, - kml_buf, pos, &rec_offs); - break; - case KML_SYMLINK: - error = unpack_symlink (&rec->rec_kml.symlink, - kml_buf, pos, &rec_offs); - break; - case KML_RENAME: - error = unpack_rename (&rec->rec_kml.rename, - kml_buf, pos, &rec_offs); - break; - case KML_SETATTR: - error = unpack_setattr (&rec->rec_kml.setattr, - kml_buf, pos, &rec_offs); - break; - case KML_LINK: - error = unpack_link (&rec->rec_kml.link, - kml_buf, pos, &rec_offs); - break; - case KML_OPEN: - error = unpack_open (&rec->rec_kml.open, - kml_buf, pos, &rec_offs); - break; - case KML_MKNOD: - error = unpack_mknod (&rec->rec_kml.mknod, - kml_buf, pos, &rec_offs); - break; -#if 0 - case KML_ENDMARK: - error = unpack_endmark (&rec->rec_kml.endmark, - kml_buf, pos, &rec_offs); - break; -#endif - default: - CDEBUG (D_KML, "wrong opcode::%u\n", - rec->rec_head.opcode); - EXIT; - return -EINVAL; - } - if (error) { - PRESTO_FREE (rec, sizeof (struct kml_rec)); - return -EINVAL; - } - p = kml_buf + rec_offs; - p = dlogit (&rec->rec_tail, p, sizeof (struct journal_suffix)); - memset (&rec->kml_optimize, 0, sizeof (struct kml_optimize)); - *newrec = rec; - EXIT; - return 0; -} - -static int size_round (int val) -{ - return (val + 3) & (~0x3); -} - -static int unpack_create (struct kml_create *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 88; - int pathlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->mode, p, sizeof (int)); - p = dlogit (&rec->uid, p, sizeof (int)); - p = dlogit (&rec->gid, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - - *rec_offs = pos + unpack_size + size_round(pathlen); - EXIT; - return 0; -} - -static int unpack_open (struct kml_open *rec, char *buf, - int pos, int *rec_offs) -{ - *rec_offs = pos; - return 0; -} - -static int unpack_symlink (struct kml_symlink *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 88; - int pathlen, targetlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->uid, p, sizeof (int)); - p = dlogit (&rec->gid, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - p = dlogit (&targetlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->sourcepath = q; - - PRESTO_ALLOC(q, char *, targetlen + 1); - if (q == NULL) { - PRESTO_FREE (rec->sourcepath, pathlen + 1); - EXIT; - return -ENOMEM; - } - - memcpy (q, p, targetlen); - q[targetlen] = '\0'; - rec->targetpath = q; - - *rec_offs = pos + unpack_size + size_round(pathlen) + - size_round(targetlen); - EXIT; - return 0; -} - -static int unpack_mknod (struct kml_mknod *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 96; - int pathlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->mode, p, sizeof (int)); - p = dlogit (&rec->uid, p, sizeof (int)); - p = dlogit (&rec->gid, p, sizeof (int)); - p = dlogit (&rec->major, p, sizeof (int)); - p = dlogit (&rec->minor, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - - *rec_offs = pos + unpack_size + size_round(pathlen); - EXIT; - return 0; -} - -static int unpack_link (struct kml_link *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 80; - int pathlen, targetlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&pathlen, p, sizeof (int)); - p = dlogit (&targetlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->sourcepath = q; - p += size_round (pathlen); - - PRESTO_ALLOC(q, char *, targetlen + 1); - if (q == NULL) { - PRESTO_FREE (rec->sourcepath, pathlen + 1); - EXIT; - return -ENOMEM; - } - memcpy (q, p, targetlen); - q[targetlen] = '\0'; - rec->targetpath = q; - - *rec_offs = pos + unpack_size + size_round(pathlen) + - size_round(targetlen); - EXIT; - return 0; -} - -static int unpack_rename (struct kml_rename *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 104; - int pathlen, targetlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_tgtv, p, sizeof (struct presto_version)); - p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version)); - p = dlogit (&pathlen, p, sizeof (int)); - p = dlogit (&targetlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->sourcepath = q; - p += size_round (pathlen); - - PRESTO_ALLOC(q, char *, targetlen + 1); - if (q == NULL) { - PRESTO_FREE (rec->sourcepath, pathlen + 1); - EXIT; - return -ENOMEM; - } - - memcpy (q, p, targetlen); - q[targetlen] = '\0'; - rec->targetpath = q; - - *rec_offs = pos + unpack_size + size_round(pathlen) + - size_round(targetlen); - EXIT; - return 0; -} - -static int unpack_unlink (struct kml_unlink *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 80; - int pathlen, targetlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version)); - p = dlogit (&pathlen, p, sizeof (int)); - p = dlogit (&targetlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - p += size_round (pathlen); - - PRESTO_ALLOC(q, char *, targetlen + 1); - if (q == NULL) { - PRESTO_FREE (rec->path, pathlen + 1); - EXIT; - return -ENOMEM; - } - - memcpy (q, p, targetlen); - q[targetlen] = '\0'; - rec->name = q; - - /* fix the presto_journal_unlink problem */ - *rec_offs = pos + unpack_size + size_round(pathlen) + - size_round(targetlen); - EXIT; - return 0; -} - -static int unpack_rmdir (struct kml_rmdir *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 80; - int pathlen, targetlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version)); - p = dlogit (&pathlen, p, sizeof (int)); - p = dlogit (&targetlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - p += size_round (pathlen); - - PRESTO_ALLOC(q, char *, targetlen + 1); - if (q == NULL) { - PRESTO_FREE (rec->path, pathlen + 1); - EXIT; - return -ENOMEM; - } - memcpy (q, p, targetlen); - q[targetlen] = '\0'; - rec->name = q; - - *rec_offs = pos + unpack_size + size_round(pathlen) + - size_round(targetlen); - EXIT; - return 0; -} - -static int unpack_setattr (struct kml_setattr *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 72; - struct kml_attr { - __u64 size, mtime, ctime; - } objattr; - int valid, mode, uid, gid, flags; - int pathlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version)); - p = dlogit (&valid, p, sizeof (int)); - p = dlogit (&mode, p, sizeof (int)); - p = dlogit (&uid, p, sizeof (int)); - p = dlogit (&gid, p, sizeof (int)); - p = dlogit (&objattr, p, sizeof (struct kml_attr)); - p = dlogit (&flags, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - - rec->iattr.ia_valid = valid; - rec->iattr.ia_mode = mode; - rec->iattr.ia_uid = uid; - rec->iattr.ia_gid = gid; - rec->iattr.ia_size = objattr.size; - rec->iattr.ia_mtime = objattr.mtime; - rec->iattr.ia_ctime = objattr.ctime; - rec->iattr.ia_atime = 0; - rec->iattr.ia_attr_flags = flags; - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - p += pathlen; - - *rec_offs = pos + unpack_size + size_round(pathlen); - EXIT; - return 0; -} - -static int unpack_close (struct kml_close *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 52; - int pathlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->open_mode, p, sizeof (int)); - p = dlogit (&rec->open_uid, p, sizeof (int)); - p = dlogit (&rec->open_gid, p, sizeof (int)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->ino, p, sizeof (__u64)); - p = dlogit (&rec->generation, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - p += pathlen; - - *rec_offs = pos + unpack_size + size_round(pathlen); - EXIT; - return 0; -} - -static int unpack_mkdir (struct kml_mkdir *rec, char *buf, - int pos, int *rec_offs) -{ - char *p, *q; - int unpack_size = 88; - int pathlen; - - ENTRY; - p = buf + pos; - p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version)); - p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version)); - p = dlogit (&rec->mode, p, sizeof (int)); - p = dlogit (&rec->uid, p, sizeof (int)); - p = dlogit (&rec->gid, p, sizeof (int)); - p = dlogit (&pathlen, p, sizeof (int)); - - PRESTO_ALLOC(q, char *, pathlen + 1); - if (q == NULL) { - EXIT; - return -ENOMEM; - } - - memcpy (q, p, pathlen); - q[pathlen] = '\0'; - rec->path = q; - p += pathlen; - - *rec_offs = pos + unpack_size + size_round(pathlen); - EXIT; - return 0; -} - -#if 0 -static int unpack_endmark (struct kml_endmark *rec, char *buf, - int pos, int *rec_offs) -{ - char *p; - p = buf + pos; - p = dlogit (&rec->total, p, sizeof (int)); - - PRESTO_ALLOC (rec->kop, struct kml_kop_node *, - sizeof (struct kml_kop_node) * rec->total); - if (rec->kop == NULL) { - EXIT; - return -ENOMEM; - } - - p = dlogit (rec->kop, p, sizeof (struct kml_kop_node) * rec->total); - - *rec_offs = pos + sizeof (int) + sizeof (struct kml_kop_node) * rec->total; - return 0; -} -#endif - -static char *kml_version (struct presto_version *ver) -{ - static char buf[256]; - sprintf (buf, "mt::%lld, ct::%lld, size::%lld", - ver->pv_mtime, ver->pv_ctime, ver->pv_size); - return buf; -} - -static void print_kml_prefix (struct big_journal_prefix *head) -{ - int i; - - CDEBUG (D_KML, " === KML PREFIX\n"); - CDEBUG (D_KML, " len = %u\n", head->len); - CDEBUG (D_KML, " version = %u\n", head->version); - CDEBUG (D_KML, " pid = %u\n", head->pid); - CDEBUG (D_KML, " uid = %u\n", head->uid); - CDEBUG (D_KML, " fsuid = %u\n", head->fsuid); - CDEBUG (D_KML, " fsgid = %u\n", head->fsgid); - CDEBUG (D_KML, " opcode = %u\n", head->opcode); - CDEBUG (D_KML, " ngroup = %u", head->ngroups); - for (i = 0; i < head->ngroups; i++) - CDEBUG (D_KML, "%u ", head->groups[i]); - CDEBUG (D_KML, "\n"); -} - -static void print_kml_create (struct kml_create *rec) -{ - CDEBUG (D_KML, " === CREATE\n"); - CDEBUG (D_KML, " path::%s\n", rec->path); - CDEBUG (D_KML, " new_objv::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); - CDEBUG (D_KML, " mode::%o\n", rec->mode); - CDEBUG (D_KML, " uid::%d\n", rec->uid); - CDEBUG (D_KML, " gid::%d\n", rec->gid); -} - -static void print_kml_mkdir (struct kml_mkdir *rec) -{ - CDEBUG (D_KML, " === MKDIR\n"); - CDEBUG (D_KML, " path::%s\n", rec->path); - CDEBUG (D_KML, " new_objv::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); - CDEBUG (D_KML, " mode::%o\n", rec->mode); - CDEBUG (D_KML, " uid::%d\n", rec->uid); - CDEBUG (D_KML, " gid::%d\n", rec->gid); -} - -static void print_kml_unlink (struct kml_unlink *rec) -{ - CDEBUG (D_KML, " === UNLINK\n"); - CDEBUG (D_KML, " path::%s/%s\n", rec->path, rec->name); - CDEBUG (D_KML, " old_tgtv::%s\n", kml_version (&rec->old_tgtv)); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); -} - -static void print_kml_rmdir (struct kml_rmdir *rec) -{ - CDEBUG (D_KML, " === RMDIR\n"); - CDEBUG (D_KML, " path::%s/%s\n", rec->path, rec->name); - CDEBUG (D_KML, " old_tgtv::%s\n", kml_version (&rec->old_tgtv)); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); -} - -static void print_kml_close (struct kml_close *rec) -{ - CDEBUG (D_KML, " === CLOSE\n"); - CDEBUG (D_KML, " mode::%o\n", rec->open_mode); - CDEBUG (D_KML, " uid::%d\n", rec->open_uid); - CDEBUG (D_KML, " gid::%d\n", rec->open_gid); - CDEBUG (D_KML, " path::%s\n", rec->path); - CDEBUG (D_KML, " new_objv::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " ino::%lld\n", rec->ino); - CDEBUG (D_KML, " gen::%u\n", rec->generation); -} - -static void print_kml_symlink (struct kml_symlink *rec) -{ - CDEBUG (D_KML, " === SYMLINK\n"); - CDEBUG (D_KML, " s-path::%s\n", rec->sourcepath); - CDEBUG (D_KML, " t-path::%s\n", rec->targetpath); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); - CDEBUG (D_KML, " new_objv::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " uid::%d\n", rec->uid); - CDEBUG (D_KML, " gid::%d\n", rec->gid); -} - -static void print_kml_rename (struct kml_rename *rec) -{ - CDEBUG (D_KML, " === RENAME\n"); - CDEBUG (D_KML, " s-path::%s\n", rec->sourcepath); - CDEBUG (D_KML, " t-path::%s\n", rec->targetpath); - CDEBUG (D_KML, " old_tgtv::%s\n", kml_version (&rec->old_tgtv)); - CDEBUG (D_KML, " new_tgtv::%s\n", kml_version (&rec->new_tgtv)); - CDEBUG (D_KML, " new_objv::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " old_objv::%s\n", kml_version (&rec->old_objectv)); -} - -static void print_kml_setattr (struct kml_setattr *rec) -{ - CDEBUG (D_KML, " === SETATTR\n"); - CDEBUG (D_KML, " path::%s\n", rec->path); - CDEBUG (D_KML, " old_objv::%s\n", kml_version (&rec->old_objectv)); - CDEBUG (D_KML, " valid::0x%x\n", rec->iattr.ia_valid); - CDEBUG (D_KML, " mode::%o\n", rec->iattr.ia_mode); - CDEBUG (D_KML, " uid::%d\n", rec->iattr.ia_uid); - CDEBUG (D_KML, " gid::%d\n", rec->iattr.ia_gid); - CDEBUG (D_KML, " size::%u\n", (u32) rec->iattr.ia_size); - CDEBUG (D_KML, " mtime::%u\n", (u32) rec->iattr.ia_mtime); - CDEBUG (D_KML, " ctime::%u\n", (u32) rec->iattr.ia_ctime); - CDEBUG (D_KML, " flags::%u\n", (u32) rec->iattr.ia_attr_flags); -} - -static void print_kml_link (struct kml_link *rec) -{ - CDEBUG (D_KML, " === LINK\n"); - CDEBUG (D_KML, " path::%s ==> %s\n", rec->sourcepath, rec->targetpath); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_obj::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); -} - -static void print_kml_mknod (struct kml_mknod *rec) -{ - CDEBUG (D_KML, " === MKNOD\n"); - CDEBUG (D_KML, " path::%s\n", rec->path); - CDEBUG (D_KML, " new_obj::%s\n", kml_version (&rec->new_objectv)); - CDEBUG (D_KML, " old_parv::%s\n", kml_version (&rec->old_parentv)); - CDEBUG (D_KML, " new_parv::%s\n", kml_version (&rec->new_parentv)); - CDEBUG (D_KML, " mode::%o\n", rec->mode); - CDEBUG (D_KML, " uid::%d\n", rec->uid); - CDEBUG (D_KML, " gid::%d\n", rec->gid); - CDEBUG (D_KML, " major::%d\n", rec->major); - CDEBUG (D_KML, " minor::%d\n", rec->minor); -} - -static void print_kml_open (struct kml_open *rec) -{ - CDEBUG (D_KML, " === OPEN\n"); -} - -#if 0 -static void print_kml_endmark (struct kml_endmark *rec) -{ - int i; - CDEBUG (D_KML, " === ENDMARK\n"); - CDEBUG (D_KML, " total::%u\n", rec->total); - for (i = 0; i < rec->total; i++) - { - CDEBUG (D_KML, " recno=%ld::flag=%ld,op=%ld, i_ino=%ld, \ - i_nlink=%ld\n", (long) rec->kop[i].kml_recno, - (long) rec->kop[i].kml_flag, (long) rec->kop[i].kml_op, - (long) rec->kop[i].i_ino, (long) rec->kop[i].i_nlink); - } -} -#endif - -static void print_kml_optimize (struct kml_optimize *rec) -{ - CDEBUG (D_KML, " === OPTIMIZE\n"); - if (rec->kml_flag == KML_REC_DELETE) - CDEBUG (D_KML, " kml_flag::deleted\n"); - else - CDEBUG (D_KML, " kml_flag::exist\n"); - CDEBUG (D_KML, " kml_op::%u\n", rec->kml_op); - CDEBUG (D_KML, " i_nlink::%d\n", rec->i_nlink); - CDEBUG (D_KML, " i_ino::%u\n", rec->i_ino); -} - -static void print_kml_suffix (struct journal_suffix *tail) -{ - CDEBUG (D_KML, " === KML SUFFIX\n"); - CDEBUG (D_KML, " prevrec::%ld\n", tail->prevrec); - CDEBUG (D_KML, " recno::%ld\n", (long) tail->recno); - CDEBUG (D_KML, " time::%d\n", tail->time); - CDEBUG (D_KML, " len::%d\n", tail->len); -} - -void kml_printrec (struct kml_rec *rec, int kml_printop) -{ - if (kml_printop & PRINT_KML_PREFIX) - print_kml_prefix (&rec->rec_head); - if (kml_printop & PRINT_KML_REC) - { - switch (rec->rec_head.opcode) - { - case KML_CREATE: - print_kml_create (&rec->rec_kml.create); - break; - case KML_MKDIR: - print_kml_mkdir (&rec->rec_kml.mkdir); - break; - case KML_UNLINK: - print_kml_unlink (&rec->rec_kml.unlink); - break; - case KML_RMDIR: - print_kml_rmdir (&rec->rec_kml.rmdir); - break; - case KML_CLOSE: - print_kml_close (&rec->rec_kml.close); - break; - case KML_SYMLINK: - print_kml_symlink (&rec->rec_kml.symlink); - break; - case KML_RENAME: - print_kml_rename (&rec->rec_kml.rename); - break; - case KML_SETATTR: - print_kml_setattr (&rec->rec_kml.setattr); - break; - case KML_LINK: - print_kml_link (&rec->rec_kml.link); - break; - case KML_OPEN: - print_kml_open (&rec->rec_kml.open); - break; - case KML_MKNOD: - print_kml_mknod (&rec->rec_kml.mknod); - break; -#if 0 - case KML_ENDMARK: - print_kml_endmark (&rec->rec_kml.endmark); -#endif - break; - default: - CDEBUG (D_KML, " === BAD RECORD, opcode=%u\n", - rec->rec_head.opcode); - break; - } - } - if (kml_printop & PRINT_KML_SUFFIX) - print_kml_suffix (&rec->rec_tail); - if (kml_printop & PRINT_KML_OPTIMIZE) - print_kml_optimize (&rec->kml_optimize); -} - -void kml_freerec (struct kml_rec *rec) -{ - char *sourcepath = NULL, - *targetpath = NULL; - switch (rec->rec_head.opcode) - { - case KML_CREATE: - sourcepath = rec->rec_kml.create.path; - break; - case KML_MKDIR: - sourcepath = rec->rec_kml.create.path; - break; - case KML_UNLINK: - sourcepath = rec->rec_kml.unlink.path; - targetpath = rec->rec_kml.unlink.name; - break; - case KML_RMDIR: - sourcepath = rec->rec_kml.rmdir.path; - targetpath = rec->rec_kml.rmdir.name; - break; - case KML_CLOSE: - sourcepath = rec->rec_kml.close.path; - break; - case KML_SYMLINK: - sourcepath = rec->rec_kml.symlink.sourcepath; - targetpath = rec->rec_kml.symlink.targetpath; - break; - case KML_RENAME: - sourcepath = rec->rec_kml.rename.sourcepath; - targetpath = rec->rec_kml.rename.targetpath; - break; - case KML_SETATTR: - sourcepath = rec->rec_kml.setattr.path; - break; - case KML_LINK: - sourcepath = rec->rec_kml.link.sourcepath; - targetpath = rec->rec_kml.link.targetpath; - break; - case KML_OPEN: - break; - case KML_MKNOD: - sourcepath = rec->rec_kml.mknod.path; - break; -#if 0 - case KML_ENDMARK: - PRESTO_FREE (rec->rec_kml.endmark.kop, sizeof (int) + - sizeof (struct kml_kop_node) * - rec->rec_kml.endmark.total); -#endif - break; - default: - break; - } - if (sourcepath != NULL) - PRESTO_FREE (sourcepath, strlen (sourcepath) + 1); - if (targetpath != NULL) - PRESTO_FREE (targetpath, strlen (targetpath) + 1); -} - -char *readrec (char *recbuf, int reclen, int pos, int *size) -{ - char *p = recbuf + pos; - *size = *((int *) p); - if (*size > (reclen - pos)) - return NULL; - return p; -} - -int kml_decoderec (char *buf, int pos, int buflen, int *size, - struct kml_rec **newrec) -{ - char *tmp; - int error; - tmp = readrec (buf, buflen, pos, size); - if (tmp == NULL) - return -EBADF; - error = kml_unpack (tmp, *size, pos, newrec); - return error; -} - -#if 0 -static void fill_kmlrec_optimize (struct list_head *head, - struct kml_rec *optrec) -{ - struct kml_rec *kmlrec; - struct list_head *tmp; - struct kml_endmark *km; - struct kml_optimize *ko; - int n; - - if (optrec->rec_kml.endmark.total == 0) - return; - n = optrec->rec_kml.endmark.total - 1; - tmp = head->prev; - km = &optrec->rec_kml.endmark; - while ( n >= 0 && tmp != head ) - { - kmlrec = list_entry(tmp, struct kml_rec, - kml_optimize.kml_chains); - tmp = tmp->prev; - if (kmlrec->rec_tail.recno == km->kop[n].kml_recno) - { - ko = &kmlrec->kml_optimize; - ko->kml_flag = km->kop[n].kml_flag; - ko->kml_op = km->kop[n].kml_op; - ko->i_nlink = km->kop[n].i_nlink; - ko->i_ino = km->kop[n].i_ino; - n --; - } - } - if (n != -1) - CDEBUG (D_KML, "Yeah!!!, KML optimize error, recno=%d, n=%d\n", - optrec->rec_tail.recno, n); -} -#endif - -int decode_kmlrec (struct list_head *head, char *kml_buf, int buflen) -{ - struct kml_rec *rec; - int pos = 0, size; - int err; - while (pos < buflen) { - err = kml_decoderec (kml_buf, pos, buflen, &size, &rec); - if (err != 0) - break; -#if 0 - if (rec->rec_head.opcode == KML_ENDMARK) { - fill_kmlrec_optimize (head, rec); - mark_rec_deleted (rec); - } -#endif - list_add_tail (&rec->kml_optimize.kml_chains, head); - pos += size; - } - return err; -} - -int delete_kmlrec (struct list_head *head) -{ - struct kml_rec *rec; - struct list_head *tmp; - - if (list_empty(head)) - return 0; - tmp = head->next; - while ( tmp != head ) { - rec = list_entry(tmp, struct kml_rec, - kml_optimize.kml_chains); - tmp = tmp->next; - kml_freerec (rec); - } - INIT_LIST_HEAD(head); - return 0; -} - -int print_allkmlrec (struct list_head *head, int printop) -{ - struct kml_rec *rec; - struct list_head *tmp; - - if (list_empty(head)) - return 0; - tmp = head->next; - while ( tmp != head ) { - rec = list_entry(tmp, struct kml_rec, - kml_optimize.kml_chains); - tmp = tmp->next; -#if 0 - if (printop & PRINT_KML_EXIST) { - if (is_deleted_node (rec)) - continue; - } - else if (printop & PRINT_KML_DELETE) { - if (! is_deleted_node (rec)) - continue; - } -#endif - kml_printrec (rec, printop); - } - INIT_LIST_HEAD(head); - return 0; -} - diff --git a/fs/intermezzo/kml_reint.c b/fs/intermezzo/kml_reint.c deleted file mode 100644 index e447b766e..000000000 --- a/fs/intermezzo/kml_reint.c +++ /dev/null @@ -1,647 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Reintegration of KML records - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir, - struct run_ctxt *saved) -{ - struct run_ctxt ctxt; - struct presto_dentry_data *dd = presto_d2d(dir->f_dentry); - int i; - - ctxt.fsuid = rec->prefix.hdr->fsuid; - ctxt.fsgid = rec->prefix.hdr->fsgid; - ctxt.fs = KERNEL_DS; - ctxt.pwd = dd->dd_fset->fset_dentry; - ctxt.pwdmnt = dd->dd_fset->fset_mnt; - - ctxt.root = ctxt.pwd; - ctxt.rootmnt = ctxt.pwdmnt; - if (rec->prefix.hdr->ngroups > 0) { - ctxt.group_info = groups_alloc(rec->prefix.hdr->ngroups); - for (i = 0; i< ctxt.group_info->ngroups; i++) - GROUP_AT(ctxt.group_info,i)= rec->prefix.groups[i]; - } else - ctxt.group_info = groups_alloc(0); - - push_ctxt(saved, &ctxt); -} - - -/* Append two strings in a less-retarded fashion. */ -static char * path_join(char *p1, int p1len, char *p2, int p2len) -{ - int size = p1len + p2len + 2; /* possibly one extra /, one NULL */ - char *path; - - path = kmalloc(size, GFP_KERNEL); - if (path == NULL) - return NULL; - - memcpy(path, p1, p1len); - if (path[p1len - 1] != '/') { - path[p1len] = '/'; - p1len++; - } - memcpy(path + p1len, p2, p2len); - path[p1len + p2len] = '\0'; - - return path; -} - -static inline int kml_recno_equal(struct kml_rec *rec, - struct presto_file_set *fset) -{ - return (rec->suffix->recno == fset->fset_lento_recno + 1); -} - -static inline int version_equal(struct presto_version *a, struct inode *inode) -{ - if (a == NULL) - return 1; - - if (inode == NULL) { - CERROR("InterMezzo: NULL inode in version_equal()\n"); - return 0; - } - - if (inode->i_mtime.tv_sec == a->pv_mtime_sec && - inode->i_mtime.tv_nsec == a->pv_mtime_nsec && - (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size)) - return 1; - - return 0; -} - -static int reint_close(struct kml_rec *rec, struct file *file, - struct lento_vfs_context *given_info) -{ - struct run_ctxt saved_ctxt; - int error; - struct presto_file_set *fset; - struct lento_vfs_context info; - ENTRY; - - memcpy(&info, given_info, sizeof(*given_info)); - - - CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path); - - fset = presto_fset(file->f_dentry); - if (fset->fset_flags & FSET_DATA_ON_DEMAND) { - struct iattr iattr; - - iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE; - iattr.ia_mtime.tv_sec = (time_t)rec->new_objectv->pv_mtime_sec; - iattr.ia_mtime.tv_nsec = (time_t)rec->new_objectv->pv_mtime_nsec; - iattr.ia_ctime.tv_sec = (time_t)rec->new_objectv->pv_ctime_sec; - iattr.ia_ctime.tv_nsec = (time_t)rec->new_objectv->pv_ctime_nsec; - iattr.ia_size = (time_t)rec->new_objectv->pv_size; - - /* no kml record, but update last rcvd */ - /* save fileid in dentry for later backfetch */ - info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID; - info.remote_ino = rec->ino; - info.remote_generation = rec->generation; - info.flags &= ~LENTO_FL_KML; - kmlreint_pre_secure(rec, file, &saved_ctxt); - error = lento_setattr(rec->path, &iattr, &info); - pop_ctxt(&saved_ctxt); - - presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA; - } else { - int minor = presto_f2m(fset); - - info.updated_time.tv_sec = rec->new_objectv->pv_mtime_sec; - info.updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec; - memcpy(&info.remote_version, rec->old_objectv, - sizeof(*rec->old_objectv)); - info.remote_ino = rec->ino; - info.remote_generation = rec->generation; - error = izo_upc_backfetch(minor, rec->path, fset->fset_name, - &info); - if (error) { - CERROR("backfetch error %d\n", error); - /* if file doesn't exist anymore, then ignore the CLOSE - * and just update the last_rcvd. - */ - if (error == ENOENT) { - CDEBUG(D_KML, "manually updating remote offset uuid %s" - "recno %d offset %Lu\n", info.uuid, info.recno, - (unsigned long long) info.kml_offset); - error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset); - if(error) - CERROR("izo_rcvd_upd_remote error %d\n", error); - - } - } - - /* propagate error to avoid further reint */ - } - - EXIT; - return error; -} - -static int reint_create(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; ENTRY; - - CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path); - info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_create(rec->path, rec->mode, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_link(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - - ENTRY; - - CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target); - info->updated_time.tv_sec = rec->new_objectv->pv_mtime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_link(rec->path, rec->target, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_mkdir(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - - ENTRY; - - CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path); - info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_mkdir(rec->path, rec->mode, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_mknod(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - dev_t dev; - - ENTRY; - - CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path); - info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - - dev = rec->rdev ? old_decode_dev(rec->rdev) : MKDEV(rec->major, rec->minor); - - error = lento_mknod(rec->path, rec->mode, dev, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - - -static int reint_noop(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - return 0; -} - -static int reint_rename(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - - ENTRY; - - CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target); - info->updated_time.tv_sec = rec->new_objectv->pv_mtime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_rename(rec->path, rec->target, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_rmdir(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - char *path; - - ENTRY; - - path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen); - if (path == NULL) { - EXIT; - return -ENOMEM; - } - - CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path); - info->updated_time.tv_sec = rec->new_parentv->pv_mtime_sec; - info->updated_time.tv_nsec = rec->new_parentv->pv_mtime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_rmdir(path, info); - pop_ctxt(&saved_ctxt); - - kfree(path); - EXIT; - return error; -} - -static int reint_setattr(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - struct iattr iattr; - int error; - - ENTRY; - - iattr.ia_valid = rec->valid; - iattr.ia_mode = (umode_t)rec->mode; - iattr.ia_uid = (uid_t)rec->uid; - iattr.ia_gid = (gid_t)rec->gid; - iattr.ia_size = (off_t)rec->size; - iattr.ia_ctime.tv_sec = rec->ctime_sec; - iattr.ia_ctime.tv_nsec = rec->ctime_nsec; - iattr.ia_mtime.tv_sec = rec->mtime_sec; - iattr.ia_mtime.tv_nsec = rec->mtime_nsec; - iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */ - iattr.ia_attr_flags = rec->flags; - - CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid); - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_setattr(rec->path, &iattr, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_symlink(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - - ENTRY; - - CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target); - info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec; - info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_symlink(rec->target, rec->path, info); - pop_ctxt(&saved_ctxt); - - EXIT; - return error; -} - -static int reint_unlink(struct kml_rec *rec, struct file *dir, - struct lento_vfs_context *info) -{ - struct run_ctxt saved_ctxt; - int error; - char *path; - - ENTRY; - - path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen); - if (path == NULL) { - EXIT; - return -ENOMEM; - } - - CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path); - info->updated_time.tv_sec = rec->new_parentv->pv_mtime_sec; - info->updated_time.tv_nsec = rec->new_parentv->pv_mtime_nsec; - kmlreint_pre_secure(rec, dir, &saved_ctxt); - error = lento_unlink(path, info); - pop_ctxt(&saved_ctxt); - - kfree(path); - EXIT; - return error; -} - -static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec, - struct file *dir, struct lento_vfs_context *info, - char * kml_data, __u64 kml_size) -{ - int error; - - ENTRY; - - error = reint_rename(rec, dir, info); - if (error == -ENOENT) { - /* normal reint failed because path was not found */ - struct rec_info rec; - - CDEBUG(D_KML, "saving branch rename kml\n"); - rec.is_kml = 1; - rec.size = kml_size; - error = presto_log(fset, &rec, kml_data, kml_size, - NULL, 0, NULL, 0, NULL, 0); - if (error == 0) - error = presto_write_last_rcvd(&rec, fset, info); - } - - EXIT; - return error; -} - -int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec, - struct file *dir, struct lento_vfs_context *info, - char * kml_data, __u64 kml_size) -{ - int error = 0; - int op = rec->prefix.hdr->opcode; - - if (op == KML_OPCODE_CLOSE) { - /* regular close and backfetch */ - error = reint_close(rec, dir, info); - } else if (op == KML_OPCODE_RENAME) { - /* rename only if name already exists */ - error = branch_reint_rename(fset, rec, dir, info, - kml_data, kml_size); - } else { - /* just rewrite kml into branch/kml and update last_rcvd */ - struct rec_info rec; - - CDEBUG(D_KML, "Saving branch kml\n"); - rec.is_kml = 1; - rec.size = kml_size; - error = presto_log(fset, &rec, kml_data, kml_size, - NULL, 0, NULL, 0, NULL, 0); - if (error == 0) - error = presto_write_last_rcvd(&rec, fset, info); - } - - return error; -} - -typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir, - struct lento_vfs_context *info); - -static reinter_t presto_reinters[KML_OPCODE_NUM] = -{ - [KML_OPCODE_CLOSE] = reint_close, - [KML_OPCODE_CREATE] = reint_create, - [KML_OPCODE_LINK] = reint_link, - [KML_OPCODE_MKDIR] = reint_mkdir, - [KML_OPCODE_MKNOD] = reint_mknod, - [KML_OPCODE_NOOP] = reint_noop, - [KML_OPCODE_RENAME] = reint_rename, - [KML_OPCODE_RMDIR] = reint_rmdir, - [KML_OPCODE_SETATTR] = reint_setattr, - [KML_OPCODE_SYMLINK] = reint_symlink, - [KML_OPCODE_UNLINK] = reint_unlink, -}; - -static inline reinter_t get_reinter(int op) -{ - if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t)) - return NULL; - else - return presto_reinters[op]; -} - -int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data) -{ - char *ptr; - char *end; - struct kml_rec rec; - int error = 0; - struct lento_vfs_context info; - struct presto_cache *cache; - struct presto_file_set *fset; - struct presto_dentry_data *dd = presto_d2d(dir->f_dentry); - int op; - reinter_t reinter; - - struct izo_rcvd_rec lr_rec; - int off; - - ENTRY; - - error = presto_prep(dir->f_dentry, &cache, &fset); - if ( error ) { - CERROR("intermezzo: Reintegration on invalid file\n"); - return error; - } - - if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { - CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n", - dir->f_dentry->d_inode->i_ino); - - return -EINVAL; - } - - if (data->ioc_plen1 > 64 * 1024) { - EXIT; - return -ENOSPC; - } - - ptr = fset->fset_reint_buf; - end = ptr + data->ioc_plen1; - - if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) { - EXIT; - error = -EFAULT; - goto out; - } - - error = kml_unpack(&rec, &ptr, end); - if (error) { - EXIT; - error = -EFAULT; - goto out; - } - - off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid); - if (off < 0) { - CERROR("No last_rcvd record, setting to 0\n"); - memset(&lr_rec, 0, sizeof(lr_rec)); - } - - data->ioc_kmlsize = ptr - fset->fset_reint_buf; - - if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) { - CERROR("KML record number %Lu expected, not %d\n", - (unsigned long long) (lr_rec.lr_remote_recno + 1), - rec.suffix->recno); - -#if 0 - if (!version_check(&rec, dd->dd_fset, &info)) { - /* FIXME: do an upcall to resolve conflicts */ - CERROR("intermezzo: would be a conflict!\n"); - error = -EINVAL; - EXIT; - goto out; - } -#endif - } - - op = rec.prefix.hdr->opcode; - - reinter = get_reinter(op); - if (!reinter) { - CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op); - error = -EINVAL; - EXIT; - goto out; - } - - info.kml_offset = data->ioc_offset + data->ioc_kmlsize; - info.recno = rec.suffix->recno; - info.flags = LENTO_FL_EXPECT; - if (data->ioc_flags) - info.flags |= LENTO_FL_KML; - - memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid)); - - if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags) - error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf, - data->ioc_kmlsize); - else - error = reinter(&rec, dir, &info); - out: - EXIT; - return error; -} - -int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data) -{ - char *buf = NULL; - char *ptr; - char *end; - struct kml_rec rec; - struct file *file; - struct presto_cache *cache; - struct presto_file_set *fset; - struct presto_dentry_data *dd = presto_d2d(dir->f_dentry); - struct run_ctxt saved_ctxt; - int error; - - ENTRY; - - error = presto_prep(dir->f_dentry, &cache, &fset); - if ( error ) { - CERROR("intermezzo: Reintegration on invalid file\n"); - return error; - } - - if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { - CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n", - dir->f_dentry->d_inode->i_ino); - - return -EINVAL; - } - - - PRESTO_ALLOC(buf, data->ioc_plen1); - if (!buf) { - EXIT; - return -ENOMEM; - } - ptr = buf; - end = buf + data->ioc_plen1; - - if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { - EXIT; - PRESTO_FREE(buf, data->ioc_plen1); - return -EFAULT; - } - - error = kml_unpack(&rec, &ptr, end); - if (error) { - EXIT; - PRESTO_FREE(buf, data->ioc_plen1); - return -EFAULT; - } - - kmlreint_pre_secure(&rec, dir, &saved_ctxt); - - file = filp_open(rec.path, O_RDONLY, 0); - if (!file || IS_ERR(file)) { - error = PTR_ERR(file); - goto out; - } - data->ioc_ino = file->f_dentry->d_inode->i_ino; - data->ioc_generation = file->f_dentry->d_inode->i_generation; - filp_close(file, 0); - - CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path, - (unsigned long long) data->ioc_ino, - (unsigned long long) data->ioc_generation); - - out: - if (buf) - PRESTO_FREE(buf, data->ioc_plen1); - pop_ctxt(&saved_ctxt); - EXIT; - return error; -} - - diff --git a/fs/intermezzo/kml_setup.c b/fs/intermezzo/kml_setup.c deleted file mode 100644 index 8a017180f..000000000 --- a/fs/intermezzo/kml_setup.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_upcall.h" -#include "intermezzo_psdev.h" -#include "intermezzo_kml.h" - -int kml_init (struct presto_file_set *fset) -{ - struct kml_fsdata *data; - - ENTRY; - PRESTO_ALLOC (data, struct kml_fsdata *, sizeof (struct kml_fsdata)); - if (data == NULL) { - EXIT; - return -ENOMEM; - } - INIT_LIST_HEAD (&data->kml_reint_cache); - INIT_LIST_HEAD (&data->kml_kop_cache); - - PRESTO_ALLOC (data->kml_buf, char *, KML_REINT_MAXBUF); - if (data->kml_buf == NULL) { - PRESTO_FREE (data, sizeof (struct kml_fsdata)); - EXIT; - return -ENOMEM; - } - - data->kml_maxsize = KML_REINT_MAXBUF; - data->kml_len = 0; - data->kml_reintpos = 0; - data->kml_count = 0; - fset->fset_kmldata = data; - EXIT; - return 0; -} - -int kml_cleanup (struct presto_file_set *fset) -{ - struct kml_fsdata *data = fset->fset_kmldata; - - if (data == NULL) - return 0; - - fset->fset_kmldata = NULL; -#if 0 - kml_sop_cleanup (&data->kml_reint_cache); - kml_kop_cleanup (&data->kml_kop_cache); -#endif - PRESTO_FREE (data->kml_buf, KML_REINT_MAXBUF); - PRESTO_FREE (data, sizeof (struct kml_fsdata)); - return 0; -} - - diff --git a/fs/intermezzo/kml_unpack.c b/fs/intermezzo/kml_unpack.c deleted file mode 100644 index d12a346b3..000000000 --- a/fs/intermezzo/kml_unpack.c +++ /dev/null @@ -1,712 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Unpacking of KML records - * - */ - -#ifdef __KERNEL__ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#else -# include -# include -# include -# include -# include -# include -# include -#endif - -#include "intermezzo_lib.h" -#include "intermezzo_idl.h" -#include "intermezzo_fs.h" - -int kml_unpack_version(struct presto_version **ver, char **buf, char *end) -{ - char *ptr = *buf; - struct presto_version *pv; - - UNLOGP(*ver, struct presto_version, ptr, end); - pv = *ver; - pv->pv_mtime_sec = NTOH__u32(pv->pv_mtime_sec); - pv->pv_mtime_nsec = NTOH__u32(pv->pv_mtime_nsec); - pv->pv_ctime_sec = NTOH__u32(pv->pv_ctime_sec); - pv->pv_ctime_nsec = NTOH__u32(pv->pv_ctime_nsec); - pv->pv_size = NTOH__u64(pv->pv_size); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end) -{ - return 0; -} - - -static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - return 0; -} - -static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->uid, __u32, ptr, end); - LUNLOGV(rec->gid, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->uid, __u32, ptr, end); - LUNLOGV(rec->gid, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->old_objectv, &ptr, end); - LUNLOGV(rec->old_mode, __u32, ptr, end); - LUNLOGV(rec->old_rdev, __u32, ptr, end); - LUNLOGV(rec->old_uid, __u64, ptr, end); - LUNLOGV(rec->old_gid, __u64, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - LUNLOGV(rec->old_targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->old_objectv, &ptr, end); - LUNLOGV(rec->old_mode, __u32, ptr, end); - LUNLOGV(rec->old_rdev, __u32, ptr, end); - LUNLOGV(rec->old_uid, __u64, ptr, end); - LUNLOGV(rec->old_gid, __u64, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - LUNLOGV(rec->mode, __u32, ptr, end); // used for open_mode - LUNLOGV(rec->uid, __u32, ptr, end); // used for open_uid - LUNLOGV(rec->gid, __u32, ptr, end); // used for open_gid - kml_unpack_version(&rec->old_objectv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->ino, __u64, ptr, end); - LUNLOGV(rec->generation, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->uid, __u32, ptr, end); - LUNLOGV(rec->gid, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_objectv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_objectv, &ptr, end); - LUNLOGV(rec->valid, __u32, ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->uid, __u32, ptr, end); - LUNLOGV(rec->gid, __u32, ptr, end); - LUNLOGV(rec->size, __u64, ptr, end); - LUNLOGV(rec->mtime_sec, __u32, ptr, end); - LUNLOGV(rec->mtime_nsec, __u32, ptr, end); - LUNLOGV(rec->ctime_sec, __u32, ptr, end); - LUNLOGV(rec->ctime_nsec, __u32, ptr, end); - LUNLOGV(rec->flags, __u32, ptr, end); - LUNLOGV(rec->old_mode, __u32, ptr, end); - LUNLOGV(rec->old_rdev, __u32, ptr, end); - LUNLOGV(rec->old_uid, __u64, ptr, end); - LUNLOGV(rec->old_gid, __u64, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - -static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_parentv, &ptr, end); - kml_unpack_version(&rec->new_parentv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->uid, __u32, ptr, end); - LUNLOGV(rec->gid, __u32, ptr, end); - LUNLOGV(rec->major, __u32, ptr, end); - LUNLOGV(rec->minor, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end) -{ - printf("NOT IMPLEMENTED"); - return 0; -} - - -static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end) -{ - printf("NOT IMPLEMENTED"); - return 0; -} - - -static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end) -{ - printf("NOT IMPLEMENTED"); - return 0; -} - - -static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_objectv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->flags, __u32, ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->namelen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->name, char, rec->namelen, ptr, end); - UNLOGL(rec->target, char, rec->targetlen, ptr, end); - - *buf = ptr; - - return 0; -} - - -static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - kml_unpack_version(&rec->old_objectv, &ptr, end); - kml_unpack_version(&rec->new_objectv, &ptr, end); - LUNLOGV(rec->flags, __u32, ptr, end); - LUNLOGV(rec->mode, __u32, ptr, end); - LUNLOGV(rec->pathlen, __u32, ptr, end); - LUNLOGV(rec->namelen, __u32, ptr, end); - LUNLOGV(rec->targetlen, __u32, ptr, end); - UNLOGL(rec->path, char, rec->pathlen, ptr, end); - UNLOGL(rec->name, char, rec->namelen, ptr, end); - - *buf = ptr; - - return 0; -} - -static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end) -{ - printf("NOT IMPLEMENTED"); - return 0; -} - -static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end) -{ - - printf("NOT IMPLEMENTED"); - return 0; -} - - -typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end); - -static unpacker unpackers[KML_OPCODE_NUM] = -{ - [KML_OPCODE_NOOP] = kml_unpack_noop, - [KML_OPCODE_CREATE] = kml_unpack_create, - [KML_OPCODE_MKDIR] = kml_unpack_mkdir, - [KML_OPCODE_UNLINK] = kml_unpack_unlink, - [KML_OPCODE_RMDIR] = kml_unpack_rmdir, - [KML_OPCODE_CLOSE] = kml_unpack_close, - [KML_OPCODE_SYMLINK] = kml_unpack_symlink, - [KML_OPCODE_RENAME] = kml_unpack_rename, - [KML_OPCODE_SETATTR] = kml_unpack_setattr, - [KML_OPCODE_LINK] = kml_unpack_link, - [KML_OPCODE_OPEN] = kml_unpack_open, - [KML_OPCODE_MKNOD] = kml_unpack_mknod, - [KML_OPCODE_WRITE] = kml_unpack_write, - [KML_OPCODE_RELEASE] = kml_unpack_release, - [KML_OPCODE_TRUNC] = kml_unpack_trunc, - [KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr, - [KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr, - [KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc, - [KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid -}; - -int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - int n; - - UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end); - rec->prefix.hdr->len = NTOH__u32(rec->prefix.hdr->len); - rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version); - rec->prefix.hdr->pid = NTOH__u32(rec->prefix.hdr->pid); - rec->prefix.hdr->auid = NTOH__u32(rec->prefix.hdr->auid); - rec->prefix.hdr->fsuid = NTOH__u32(rec->prefix.hdr->fsuid); - rec->prefix.hdr->fsgid = NTOH__u32(rec->prefix.hdr->fsgid); - rec->prefix.hdr->opcode = NTOH__u32(rec->prefix.hdr->opcode); - rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups); - - UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end); - for (n = 0; n < rec->prefix.hdr->ngroups; n++) { - rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]); - } - - *buf = ptr; - - return 0; -} - -int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - - UNLOGP(rec->suffix, struct kml_suffix, ptr, end); - rec->suffix->prevrec = NTOH__u32(rec->suffix->prevrec); - rec->suffix->recno = NTOH__u32(rec->suffix->recno); - rec->suffix->time = NTOH__u32(rec->suffix->time); - rec->suffix->len = NTOH__u32(rec->suffix->len); - - *buf = ptr; - - return 0; -} - -int kml_unpack(struct kml_rec *rec, char **buf, char *end) -{ - char *ptr = *buf; - int err; - - if (((unsigned long)ptr % 4) != 0) { - printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__); - return -EINVAL; - } - - while (ptr < end) { - __u32 *i = (__u32 *)ptr; - if (*i) - break; - ptr += sizeof(*i); - } - *buf = ptr; - - memset(rec, 0, sizeof(*rec)); - - err = kml_unpack_prefix(rec, &ptr, end); - if (err) { - printf("InterMezzo: %s: unpack_prefix failed: %d\n", - __FUNCTION__, err); - return err; - } - - if (rec->prefix.hdr->opcode < 0 || - rec->prefix.hdr->opcode >= KML_OPCODE_NUM) { - printf("InterMezzo: %s: invalid opcode (%d)\n", - __FUNCTION__, rec->prefix.hdr->opcode); - return -EINVAL; - } - err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end); - if (err) { - printf("InterMezzo: %s: unpacker failed: %d\n", - __FUNCTION__, err); - return err; - } - - err = kml_unpack_suffix(rec, &ptr, end); - if (err) { - printf("InterMezzo: %s: unpack_suffix failed: %d\n", - __FUNCTION__, err); - return err; - } - - - if (rec->prefix.hdr->len != rec->suffix->len) { - printf("InterMezzo: %s: lengths don't match\n", - __FUNCTION__); - return -EINVAL; - } - if ((rec->prefix.hdr->len % 4) != 0) { - printf("InterMezzo: %s: record length not a " - "multiple of 4.\n", __FUNCTION__); - return -EINVAL; - } - if (ptr - *buf != rec->prefix.hdr->len) { - printf("InterMezzo: %s: unpacking error\n", - __FUNCTION__); - return -EINVAL; - } - while (ptr < end) { - __u32 *i = (__u32 *)ptr; - if (*i) - break; - ptr += sizeof(*i); - } - *buf = ptr; - return 0; -} - - -#ifndef __KERNEL__ -#define STR(ptr) ((ptr))? (ptr) : "" - -#define OPNAME(n) [KML_OPCODE_##n] = #n -static char *opnames[KML_OPCODE_NUM] = { - OPNAME(NOOP), - OPNAME(CREATE), - OPNAME(MKDIR), - OPNAME(UNLINK), - OPNAME(RMDIR), - OPNAME(CLOSE), - OPNAME(SYMLINK), - OPNAME(RENAME), - OPNAME(SETATTR), - OPNAME(LINK), - OPNAME(OPEN), - OPNAME(MKNOD), - OPNAME(WRITE), - OPNAME(RELEASE), - OPNAME(TRUNC), - OPNAME(SETEXTATTR), - OPNAME(DELEXTATTR), - OPNAME(KML_TRUNC), - OPNAME(GET_FILEID) -}; -#undef OPNAME - -static char *print_opname(int op) -{ - if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames)) - return NULL; - return opnames[op]; -} - - -static char *print_time(__u64 i) -{ - char buf[128]; - - memset(buf, 0, 128); - -#ifndef __KERNEL__ - strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i)); -#else - sprintf(buf, "%Ld\n", i); -#endif - - return strdup(buf); -} - -static char *print_version(struct presto_version *ver) -{ - char ver_buf[128]; - char *mtime; - char *ctime; - - if (!ver || ver->pv_ctime == 0) { - return strdup(""); - } - mtime = print_time(ver->pv_mtime); - ctime = print_time(ver->pv_ctime); - sprintf(ver_buf, "mtime %s, ctime %s, len %lld", - mtime, ctime, ver->pv_size); - free(mtime); - free(ctime); - return strdup(ver_buf); -} - - -char *kml_print_rec(struct kml_rec *rec, int brief) -{ - char *str; - char *nov, *oov, *ntv, *otv, *npv, *opv; - char *rectime, *mtime, *ctime; - - if (brief) { - str = g_strdup_printf(" %08d %7s %*s %*s", - rec->suffix->recno, - print_opname (rec->prefix.hdr->opcode), - rec->pathlen, STR(rec->path), - rec->targetlen, STR(rec->target)); - - return str; - } - - rectime = print_time(rec->suffix->time); - mtime = print_time(rec->mtime); - ctime = print_time(rec->ctime); - - nov = print_version(rec->new_objectv); - oov = print_version(rec->old_objectv); - ntv = print_version(rec->new_targetv); - otv = print_version(rec->old_targetv); - npv = print_version(rec->new_parentv); - opv = print_version(rec->old_parentv); - - str = g_strdup_printf("\n -- Record:\n" - " Recno %d\n" - " KML off %lld\n" - " Version %d\n" - " Len %d\n" - " Suf len %d\n" - " Time %s\n" - " Opcode %d\n" - " Op %s\n" - " Pid %d\n" - " AUid %d\n" - " Fsuid %d\n" - " Fsgid %d\n" - " Prevrec %d\n" - " Ngroups %d\n" - //" Groups @{$self->{groups}}\n" - " -- Path:\n" - " Inode %d\n" - " Gen num %u\n" - " Old mode %o\n" - " Old rdev %x\n" - " Old uid %llu\n" - " Old gid %llu\n" - " Path %*s\n" - //" Open_mode %o\n", - " Pathlen %d\n" - " Tgt %*s\n" - " Tgtlen %d\n" - " Old Tgt %*s\n" - " Old Tgtln %d\n" - " -- Attr:\n" - " Valid %x\n" - " mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n" - " -- Versions:\n" - " New object %s\n" - " Old object %s\n" - " New target %s\n" - " Old target %s\n" - " New parent %s\n" - " Old parent %s\n", - - rec->suffix->recno, - rec->offset, - rec->prefix.hdr->version, - rec->prefix.hdr->len, - rec->suffix->len, - rectime, - rec->prefix.hdr->opcode, - print_opname (rec->prefix.hdr->opcode), - rec->prefix.hdr->pid, - rec->prefix.hdr->auid, - rec->prefix.hdr->fsuid, - rec->prefix.hdr->fsgid, - rec->suffix->prevrec, - rec->prefix.hdr->ngroups, - rec->ino, - rec->generation, - rec->old_mode, - rec->old_rdev, - rec->old_uid, - rec->old_gid, - rec->pathlen, - STR(rec->path), - rec->pathlen, - rec->targetlen, - STR(rec->target), - rec->targetlen, - rec->old_targetlen, - STR(rec->old_target), - rec->old_targetlen, - - rec->valid, - rec->mode, - rec->uid, - rec->gid, - rec->size, - mtime, - ctime, - rec->rdev, rec->major, rec->minor, - nov, oov, ntv, otv, npv, opv); - - free(nov); - free(oov); - free(ntv); - free(otv); - free(npv); - free(opv); - - free(rectime); - free(ctime); - free(mtime); - - return str; -} -#endif diff --git a/fs/intermezzo/kml_utils.c b/fs/intermezzo/kml_utils.c deleted file mode 100644 index 5062e2d71..000000000 --- a/fs/intermezzo/kml_utils.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_kml.h" - - -// dlogit -- oppsite to logit () -// return the sbuf + size; -char *dlogit (void *tbuf, const void *sbuf, int size) -{ - char *ptr = (char *)sbuf; - memcpy(tbuf, ptr, size); - ptr += size; - return ptr; -} - -static spinlock_t kml_lock = SPIN_LOCK_UNLOCKED; -static char buf[1024]; -char * bdup_printf (char *format, ...) -{ - va_list args; - int i; - char *path; - unsigned long flags; - - spin_lock_irqsave(&kml_lock, flags); - va_start(args, format); - i = vsprintf(buf, format, args); /* hopefully i < sizeof(buf) */ - va_end(args); - - PRESTO_ALLOC (path, char *, i + 1); - if (path == NULL) - return NULL; - strcpy (path, buf); - - spin_unlock_irqrestore(&kml_lock, flags); - return path; -} - - diff --git a/fs/intermezzo/methods.c b/fs/intermezzo/methods.c deleted file mode 100644 index 8950efc8c..000000000 --- a/fs/intermezzo/methods.c +++ /dev/null @@ -1,493 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * Copyright (C) 2000 Mountain View Data, Inc. - * - * Extended Attribute Support - * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "intermezzo_fs.h" - - -int filter_print_entry = 0; -int filter_debug = 0xfffffff; -/* - * The function in this file are responsible for setting up the - * correct methods layered file systems like InterMezzo and snapfs - */ - - -static struct filter_fs filter_oppar[FILTER_FS_TYPES]; - -/* get to the upper methods (intermezzo, snapfs) */ -inline struct super_operations *filter_c2usops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_sops; -} - -inline struct inode_operations *filter_c2udiops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_dir_iops; -} - - -inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_file_iops; -} - -inline struct inode_operations *filter_c2usiops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_sym_iops; -} - - -inline struct file_operations *filter_c2udfops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_dir_fops; -} - -inline struct file_operations *filter_c2uffops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_file_fops; -} - -inline struct file_operations *filter_c2usfops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_sym_fops; -} - -inline struct dentry_operations *filter_c2udops(struct filter_fs *cache) -{ - return &cache->o_fops.filter_dentry_ops; -} - -/* get to the cache (lower) methods */ -inline struct super_operations *filter_c2csops(struct filter_fs *cache) -{ - return cache->o_caops.cache_sops; -} - -inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache) -{ - return cache->o_caops.cache_dir_iops; -} - -inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache) -{ - return cache->o_caops.cache_file_iops; -} - -inline struct inode_operations *filter_c2csiops(struct filter_fs *cache) -{ - return cache->o_caops.cache_sym_iops; -} - -inline struct file_operations *filter_c2cdfops(struct filter_fs *cache) -{ - return cache->o_caops.cache_dir_fops; -} - -inline struct file_operations *filter_c2cffops(struct filter_fs *cache) -{ - return cache->o_caops.cache_file_fops; -} - -inline struct file_operations *filter_c2csfops(struct filter_fs *cache) -{ - return cache->o_caops.cache_sym_fops; -} - -inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache) -{ - return cache->o_caops.cache_dentry_ops; -} - - -void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type) -{ - if ( strlen(cache_type) == strlen("ext2") && - memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) { -#ifdef CONFIG_EXT2_FS - ops->o_trops = &presto_ext2_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("ext3") && - memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) { -#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE) - ops->o_trops = &presto_ext3_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("tmpfs") && - memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) { -#if defined(CONFIG_TMPFS) - ops->o_trops = &presto_tmpfs_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("reiserfs") && - memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) { -#if 0 - /* #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) */ - ops->o_trops = &presto_reiserfs_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("xfs") && - memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) { -#if 0 -/*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */ - ops->o_trops = &presto_xfs_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("obdfs") && - memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) { -#if defined(CONFIG_OBDFS_FS) || defined (CONFIG_OBDFS_FS_MODULE) - ops->o_trops = presto_obdfs_journal_ops; -#else - ops->o_trops = NULL; -#endif - FDEBUG(D_SUPER, "ops at %p\n", ops); - } -} - - -/* find the cache for this FS */ -struct filter_fs *filter_get_filter_fs(const char *cache_type) -{ - struct filter_fs *ops = NULL; - FENTRY; - - if ( strlen(cache_type) == strlen("ext2") && - memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) { - ops = &filter_oppar[FILTER_FS_EXT2]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("xfs") && - memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) { - ops = &filter_oppar[FILTER_FS_XFS]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("ext3") && - memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) { - ops = &filter_oppar[FILTER_FS_EXT3]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("tmpfs") && - memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) { - ops = &filter_oppar[FILTER_FS_TMPFS]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if ( strlen(cache_type) == strlen("reiserfs") && - memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) { - ops = &filter_oppar[FILTER_FS_REISERFS]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - if ( strlen(cache_type) == strlen("obdfs") && - memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) { - ops = &filter_oppar[FILTER_FS_OBDFS]; - FDEBUG(D_SUPER, "ops at %p\n", ops); - } - - if (ops == NULL) { - CERROR("prepare to die: unrecognized cache type for Filter\n"); - } - FEXIT; - return ops; -} - - -/* - * Frobnicate the InterMezzo operations - * this establishes the link between the InterMezzo file system - * and the underlying file system used for the cache. - */ - -void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops) -{ - /* Get ptr to the shared struct snapfs_ops structure. */ - struct filter_ops *props = &cache->o_fops; - /* Get ptr to the shared struct cache_ops structure. */ - struct cache_ops *caops = &cache->o_caops; - - FENTRY; - - if ( cache->o_flags & FILTER_DID_SUPER_OPS ) { - FEXIT; - return; - } - cache->o_flags |= FILTER_DID_SUPER_OPS; - - /* Set the cache superblock operations to point to the - superblock operations of the underlying file system. */ - caops->cache_sops = cache_sops; - - /* - * Copy the cache (real fs) superblock ops to the "filter" - * superblock ops as defaults. Some will be changed below - */ - memcpy(&props->filter_sops, cache_sops, sizeof(*cache_sops)); - - /* 'put_super' unconditionally is that of filter */ - if (filter_sops->put_super) { - props->filter_sops.put_super = filter_sops->put_super; - } - - if (cache_sops->read_inode) { - props->filter_sops.read_inode = filter_sops->read_inode; - FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n", - cache, cache, props->filter_sops.read_inode); - } - - if (cache_sops->remount_fs) - props->filter_sops.remount_fs = filter_sops->remount_fs; - FEXIT; -} - - -void filter_setup_dir_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) -{ - struct inode_operations *cache_filter_iops; - struct inode_operations *cache_iops = inode->i_op; - struct file_operations *cache_fops = inode->i_fop; - FENTRY; - - if ( cache->o_flags & FILTER_DID_DIR_OPS ) { - FEXIT; - return; - } - cache->o_flags |= FILTER_DID_DIR_OPS; - - /* former ops become cache_ops */ - cache->o_caops.cache_dir_iops = cache_iops; - cache->o_caops.cache_dir_fops = cache_fops; - FDEBUG(D_SUPER, "filter at %p, cache iops %p, iops %p\n", - cache, cache_iops, filter_c2udiops(cache)); - - /* setup our dir iops: copy and modify */ - memcpy(filter_c2udiops(cache), cache_iops, sizeof(*cache_iops)); - - /* abbreviate */ - cache_filter_iops = filter_c2udiops(cache); - - /* methods that filter if cache filesystem has these ops */ - if (cache_iops->lookup && filter_iops->lookup) - cache_filter_iops->lookup = filter_iops->lookup; - if (cache_iops->create && filter_iops->create) - cache_filter_iops->create = filter_iops->create; - if (cache_iops->link && filter_iops->link) - cache_filter_iops->link = filter_iops->link; - if (cache_iops->unlink && filter_iops->unlink) - cache_filter_iops->unlink = filter_iops->unlink; - if (cache_iops->mkdir && filter_iops->mkdir) - cache_filter_iops->mkdir = filter_iops->mkdir; - if (cache_iops->rmdir && filter_iops->rmdir) - cache_filter_iops->rmdir = filter_iops->rmdir; - if (cache_iops->symlink && filter_iops->symlink) - cache_filter_iops->symlink = filter_iops->symlink; - if (cache_iops->rename && filter_iops->rename) - cache_filter_iops->rename = filter_iops->rename; - if (cache_iops->mknod && filter_iops->mknod) - cache_filter_iops->mknod = filter_iops->mknod; - if (cache_iops->permission && filter_iops->permission) - cache_filter_iops->permission = filter_iops->permission; - if (cache_iops->getattr) - cache_filter_iops->getattr = filter_iops->getattr; - /* Some filesystems do not use a setattr method of their own - instead relying on inode_setattr/write_inode. We still need to - journal these so we make setattr an unconditional operation. - XXX: we should probably check for write_inode. SHP - */ - /*if (cache_iops->setattr)*/ - cache_filter_iops->setattr = filter_iops->setattr; -#ifdef CONFIG_FS_EXT_ATTR - /* For now we assume that posix acls are handled through extended - * attributes. If this is not the case, we must explicitly trap - * posix_set_acl. SHP - */ - if (cache_iops->set_ext_attr && filter_iops->set_ext_attr) - cache_filter_iops->set_ext_attr = filter_iops->set_ext_attr; -#endif - - - /* copy dir fops */ - memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops)); - - /* unconditional filtering operations */ - filter_c2udfops(cache)->ioctl = filter_fops->ioctl; - - FEXIT; -} - - -void filter_setup_file_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) -{ - struct inode_operations *pr_iops; - struct inode_operations *cache_iops = inode->i_op; - struct file_operations *cache_fops = inode->i_fop; - FENTRY; - - if ( cache->o_flags & FILTER_DID_FILE_OPS ) { - FEXIT; - return; - } - cache->o_flags |= FILTER_DID_FILE_OPS; - - /* steal the old ops */ - /* former ops become cache_ops */ - cache->o_caops.cache_file_iops = cache_iops; - cache->o_caops.cache_file_fops = cache_fops; - - /* abbreviate */ - pr_iops = filter_c2ufiops(cache); - - /* setup our dir iops: copy and modify */ - memcpy(pr_iops, cache_iops, sizeof(*cache_iops)); - - /* copy dir fops */ - CERROR("*** cache file ops at %p\n", cache_fops); - memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops)); - - /* assign */ - /* See comments above in filter_setup_dir_ops. SHP */ - /*if (cache_iops->setattr)*/ - pr_iops->setattr = filter_iops->setattr; - if (cache_iops->getattr) - pr_iops->getattr = filter_iops->getattr; - /* XXX Should this be conditional rmr ? */ - pr_iops->permission = filter_iops->permission; -#ifdef CONFIG_FS_EXT_ATTR - /* For now we assume that posix acls are handled through extended - * attributes. If this is not the case, we must explicitly trap and - * posix_set_acl - */ - if (cache_iops->set_ext_attr && filter_iops->set_ext_attr) - pr_iops->set_ext_attr = filter_iops->set_ext_attr; -#endif - - - /* unconditional filtering operations */ - filter_c2uffops(cache)->open = filter_fops->open; - filter_c2uffops(cache)->release = filter_fops->release; - filter_c2uffops(cache)->write = filter_fops->write; - filter_c2uffops(cache)->ioctl = filter_fops->ioctl; - - FEXIT; -} - -/* XXX in 2.3 there are "fast" and "slow" symlink ops for ext2 XXX */ -void filter_setup_symlink_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) -{ - struct inode_operations *pr_iops; - struct inode_operations *cache_iops = inode->i_op; - struct file_operations *cache_fops = inode->i_fop; - FENTRY; - - if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) { - FEXIT; - return; - } - cache->o_flags |= FILTER_DID_SYMLINK_OPS; - - /* steal the old ops */ - cache->o_caops.cache_sym_iops = cache_iops; - cache->o_caops.cache_sym_fops = cache_fops; - - /* abbreviate */ - pr_iops = filter_c2usiops(cache); - - /* setup our dir iops: copy and modify */ - memcpy(pr_iops, cache_iops, sizeof(*cache_iops)); - - /* See comments above in filter_setup_dir_ops. SHP */ - /* if (cache_iops->setattr) */ - pr_iops->setattr = filter_iops->setattr; - if (cache_iops->getattr) - pr_iops->getattr = filter_iops->getattr; - - /* assign */ - /* copy fops - careful for symlinks they might be NULL */ - if ( cache_fops ) { - memcpy(filter_c2usfops(cache), cache_fops, sizeof(*cache_fops)); - } - - FEXIT; -} - -void filter_setup_dentry_ops(struct filter_fs *cache, - struct dentry_operations *cache_dop, - struct dentry_operations *filter_dop) -{ - if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) { - FEXIT; - return; - } - cache->o_flags |= FILTER_DID_DENTRY_OPS; - - cache->o_caops.cache_dentry_ops = cache_dop; - memcpy(&cache->o_fops.filter_dentry_ops, - filter_dop, sizeof(*filter_dop)); - - if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){ - CERROR("WARNING: filter overriding revalidation!\n"); - } - return; -} diff --git a/fs/intermezzo/presto.c b/fs/intermezzo/presto.c deleted file mode 100644 index bf1603186..000000000 --- a/fs/intermezzo/presto.c +++ /dev/null @@ -1,736 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Author: Peter J. Braam - * Copyright (C) 1998 Stelias Computing Inc - * Copyright (C) 1999 Red Hat Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This file implements basic routines supporting the semantics - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -int presto_walk(const char *name, struct nameidata *nd) -{ - int err; - /* we do not follow symlinks to support symlink operations - correctly. The vfs should always hand us resolved dentries - so we should not be required to use LOOKUP_FOLLOW. At the - reintegrating end, lento again should be working with the - resolved pathname and not the symlink. SHP - XXX: This code implies that direct symlinks do not work. SHP - */ - unsigned int flags = 0; //LOOKUP_POSITIVE; - - ENTRY; - err = path_lookup(name, flags, nd); - return err; -} - - -/* find the presto minor device for this inode */ -int presto_i2m(struct inode *inode) -{ - struct presto_cache *cache; - ENTRY; - cache = presto_get_cache(inode); - CDEBUG(D_PSDEV, "\n"); - if ( !cache ) { - CERROR("PRESTO: BAD: cannot find cache for dev %s, ino %ld\n", - inode->i_sb->s_id, inode->i_ino); - EXIT; - return -1; - } - EXIT; - return cache->cache_psdev->uc_minor; -} - -inline int presto_f2m(struct presto_file_set *fset) -{ - return fset->fset_cache->cache_psdev->uc_minor; - -} - -inline int presto_c2m(struct presto_cache *cache) -{ - return cache->cache_psdev->uc_minor; - -} - -/* XXX check this out */ -struct presto_file_set *presto_path2fileset(const char *name) -{ - struct nameidata nd; - struct presto_file_set *fileset; - int error; - ENTRY; - - error = presto_walk(name, &nd); - if (!error) { -#if 0 - error = do_revalidate(nd.dentry); -#endif - if (!error) - fileset = presto_fset(nd.dentry); - path_release(&nd); - EXIT; - } else - fileset = ERR_PTR(error); - - EXIT; - return fileset; -} - -/* check a flag on this dentry or fset root. Semantics: - - most flags: test if it is set - - PRESTO_ATTR, PRESTO_DATA return 1 if PRESTO_FSETINSYNC is set -*/ -int presto_chk(struct dentry *dentry, int flag) -{ - int minor; - struct presto_file_set *fset = presto_fset(dentry); - - ENTRY; - minor = presto_i2m(dentry->d_inode); - if ( izo_channels[minor].uc_no_filter ) { - EXIT; - return ~0; - } - - /* if the fileset is in sync DATA and ATTR are OK */ - if ( fset && - (flag == PRESTO_ATTR || flag == PRESTO_DATA) && - (fset->fset_flags & FSET_INSYNC) ) { - CDEBUG(D_INODE, "fset in sync (ino %ld)!\n", - fset->fset_dentry->d_inode->i_ino); - EXIT; - return 1; - } - - EXIT; - return (presto_d2d(dentry)->dd_flags & flag); -} - -/* set a bit in the dentry flags */ -void presto_set(struct dentry *dentry, int flag) -{ - ENTRY; - if ( dentry->d_inode ) { - CDEBUG(D_INODE, "SET ino %ld, flag %x\n", - dentry->d_inode->i_ino, flag); - } - if ( presto_d2d(dentry) == NULL) { - CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry, - dentry->d_name.len, dentry->d_name.name); - BUG(); - } - presto_d2d(dentry)->dd_flags |= flag; - EXIT; -} - -/* given a path: complete the closes on the fset */ -int lento_complete_closes(char *path) -{ - struct nameidata nd; - struct dentry *dentry; - int error; - struct presto_file_set *fset; - ENTRY; - - error = presto_walk(path, &nd); - if (error) { - EXIT; - return error; - } - - dentry = nd.dentry; - - error = -ENXIO; - if ( !presto_ispresto(dentry->d_inode) ) { - EXIT; - goto out_complete; - } - - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto out_complete; - } - - /* transactions and locking are internal to this function */ - error = presto_complete_lml(fset); - - EXIT; - out_complete: - path_release(&nd); - return error; -} - -#if 0 -/* given a path: write a close record and cancel an LML record, finally - call truncate LML. Lento is doing this so it goes in with uid/gid's - root. -*/ -int lento_cancel_lml(char *path, - __u64 lml_offset, - __u64 remote_ino, - __u32 remote_generation, - __u32 remote_version, - struct lento_vfs_context *info) -{ - struct nameidata nd; - struct rec_info rec; - struct dentry *dentry; - int error; - struct presto_file_set *fset; - void *handle; - struct presto_version new_ver; - ENTRY; - - - error = presto_walk(path, &nd); - if (error) { - EXIT; - return error; - } - dentry = nd.dentry; - - error = -ENXIO; - if ( !presto_ispresto(dentry->d_inode) ) { - EXIT; - goto out_cancel_lml; - } - - fset = presto_fset(dentry); - - error=-EINVAL; - if (fset==NULL) { - CERROR("No fileset!\n"); - EXIT; - goto out_cancel_lml; - } - - /* this only requires a transaction below which is automatic */ - handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE); - if ( IS_ERR(handle) ) { - error = -ENOMEM; - EXIT; - goto out_cancel_lml; - } - - if (info->flags & LENTO_FL_CANCEL_LML) { - error = presto_clear_lml_close(fset, lml_offset); - if ( error ) { - presto_trans_commit(fset, handle); - EXIT; - goto out_cancel_lml; - } - } - - - if (info->flags & LENTO_FL_WRITE_KML) { - presto_getversion(&new_ver, dentry->d_inode); - error = presto_journal_close(&rec, fset, NULL, dentry, - &new_ver); - if ( error ) { - EXIT; - presto_trans_commit(fset, handle); - goto out_cancel_lml; - } - } - - if (info->flags & LENTO_FL_WRITE_EXPECT) { - error = presto_write_last_rcvd(&rec, fset, info); - if ( error < 0 ) { - EXIT; - presto_trans_commit(fset, handle); - goto out_cancel_lml; - } - } - - presto_trans_commit(fset, handle); - - if (info->flags & LENTO_FL_CANCEL_LML) { - presto_truncate_lml(fset); - } - - - out_cancel_lml: - EXIT; - path_release(&nd); - return error; -} -#endif - -/* given a dentry, operate on the flags in its dentry. Used by downcalls */ -int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag, - int *res) -{ - int error = 0; - - if (presto_d2d(dentry) == NULL) { - CERROR("InterMezzo: no ddata for inode %ld in %s\n", - dentry->d_inode->i_ino, __FUNCTION__); - return -EINVAL; - } - - CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n", - dentry->d_inode->i_ino, and_flag, or_flag, - presto_d2d(dentry)->dd_flags); - - presto_d2d(dentry)->dd_flags &= and_flag; - presto_d2d(dentry)->dd_flags |= or_flag; - if (res) - *res = presto_d2d(dentry)->dd_flags; - - return error; -} - -/* given a path, operate on the flags in its cache. Used by mark_ioctl */ -int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag, - int *res) -{ - struct presto_cache *cache; - - if (presto_d2d(dentry) == NULL) { - CERROR("InterMezzo: no ddata for inode %ld in %s\n", - dentry->d_inode->i_ino, __FUNCTION__); - return -EINVAL; - } - - CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n", - dentry->d_inode->i_ino, and_flag, or_flag, - presto_d2d(dentry)->dd_flags); - - cache = presto_get_cache(dentry->d_inode); - if ( !cache ) { - CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n"); - return -EBADF; - } - - cache->cache_flags &= and_flag; - cache->cache_flags |= or_flag; - if (res) - *res = (int)cache->cache_flags; - - return 0; -} - -int presto_set_max_kml_size(const char *path, unsigned long max_size) -{ - struct presto_file_set *fset; - - ENTRY; - - fset = presto_path2fileset(path); - if (IS_ERR(fset)) { - EXIT; - return PTR_ERR(fset); - } - - fset->kml_truncate_size = max_size; - CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.\n", - max_size, path); - - EXIT; - return 0; -} - -int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag, - int * res) -{ - struct presto_file_set *fset; - - fset = presto_fset(dentry); - if ( !fset ) { - CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n"); - make_bad_inode(dentry->d_inode); - return -EBADF; - } - fset->fset_flags &= and_flag; - fset->fset_flags |= or_flag; - if (res) - *res = (int)fset->fset_flags; - - return 0; -} - -/* talk to Lento about the permit */ -static int presto_permit_upcall(struct dentry *dentry) -{ - int rc; - char *path, *buffer; - int pathlen; - int minor; - int fsetnamelen; - struct presto_file_set *fset = NULL; - - ENTRY; - - if ( (minor = presto_i2m(dentry->d_inode)) < 0) { - EXIT; - return -EINVAL; - } - - fset = presto_fset(dentry); - if (!fset) { - EXIT; - return -ENOTCONN; - } - - if ( !presto_lento_up(minor) ) { - if ( fset->fset_flags & FSET_STEAL_PERMIT ) { - EXIT; - return 0; - } else { - EXIT; - return -ENOTCONN; - } - } - - PRESTO_ALLOC(buffer, PAGE_SIZE); - if ( !buffer ) { - CERROR("PRESTO: out of memory!\n"); - EXIT; - return -ENOMEM; - } - path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE); - pathlen = MYPATHLEN(buffer, path); - fsetnamelen = strlen(fset->fset_name); - rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name); - PRESTO_FREE(buffer, PAGE_SIZE); - EXIT; - return rc; -} - -/* get a write permit for the fileset of this inode - * - if this returns a negative value there was an error - * - if 0 is returned the permit was already in the kernel -- or -- - * Lento gave us the permit without reintegration - * - lento returns the number of records it reintegrated - * - * Note that if this fileset has branches, a permit will -never- to a normal - * process for writing in the data area (ie, outside of .intermezzo) - */ -int presto_get_permit(struct inode * inode) -{ - struct dentry *de; - struct presto_file_set *fset; - int minor = presto_i2m(inode); - int rc = 0; - - ENTRY; - if (minor < 0) { - EXIT; - return -1; - } - - if ( ISLENTO(minor) ) { - EXIT; - return 0; - } - - if (list_empty(&inode->i_dentry)) { - CERROR("No alias for inode %d\n", (int) inode->i_ino); - EXIT; - return -EINVAL; - } - - de = list_entry(inode->i_dentry.next, struct dentry, d_alias); - - if (presto_chk(de, PRESTO_DONT_JOURNAL)) { - EXIT; - return 0; - } - - fset = presto_fset(de); - if ( !fset ) { - CERROR("Presto: no fileset in presto_get_permit!\n"); - EXIT; - return -EINVAL; - } - - if (fset->fset_flags & FSET_HAS_BRANCHES) { - EXIT; - return -EROFS; - } - - spin_lock(&fset->fset_permit_lock); - if (fset->fset_flags & FSET_HASPERMIT) { - fset->fset_permit_count++; - CDEBUG(D_INODE, "permit count now %d, inode %lx\n", - fset->fset_permit_count, inode->i_ino); - spin_unlock(&fset->fset_permit_lock); - EXIT; - return 0; - } - - /* Allow reintegration to proceed without locks -SHP */ - fset->fset_permit_upcall_count++; - if (fset->fset_permit_upcall_count == 1) { - spin_unlock(&fset->fset_permit_lock); - rc = presto_permit_upcall(fset->fset_dentry); - spin_lock(&fset->fset_permit_lock); - fset->fset_permit_upcall_count--; - if (rc == 0) { - izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT, - NULL); - fset->fset_permit_count++; - } else if (rc == ENOTCONN) { - CERROR("InterMezzo: disconnected operation. stealing permit.\n"); - izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT, - NULL); - fset->fset_permit_count++; - /* set a disconnected flag here to stop upcalls */ - rc = 0; - } else { - CERROR("InterMezzo: presto_permit_upcall failed: %d\n", rc); - rc = -EROFS; - /* go to sleep here and try again? */ - } - wake_up_interruptible(&fset->fset_permit_queue); - } else { - /* Someone is already doing an upcall; go to sleep. */ - DECLARE_WAITQUEUE(wait, current); - - spin_unlock(&fset->fset_permit_lock); - add_wait_queue(&fset->fset_permit_queue, &wait); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock(&fset->fset_permit_lock); - if (fset->fset_permit_upcall_count == 0) - break; - spin_unlock(&fset->fset_permit_lock); - - if (signal_pending(current)) { - remove_wait_queue(&fset->fset_permit_queue, - &wait); - return -ERESTARTSYS; - } - schedule(); - } - remove_wait_queue(&fset->fset_permit_queue, &wait); - /* We've been woken up: do we have the permit? */ - if (fset->fset_flags & FSET_HASPERMIT) - /* FIXME: Is this the right thing? */ - rc = -EAGAIN; - } - - CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), " - "rc %d\n", fset->fset_permit_count, inode->i_ino, rc); - spin_unlock(&fset->fset_permit_lock); - EXIT; - return rc; -} - -int presto_put_permit(struct inode * inode) -{ - struct dentry *de; - struct presto_file_set *fset; - int minor = presto_i2m(inode); - - ENTRY; - if (minor < 0) { - EXIT; - return -1; - } - - if ( ISLENTO(minor) ) { - EXIT; - return 0; - } - - if (list_empty(&inode->i_dentry)) { - CERROR("No alias for inode %d\n", (int) inode->i_ino); - EXIT; - return -1; - } - - de = list_entry(inode->i_dentry.next, struct dentry, d_alias); - - fset = presto_fset(de); - if ( !fset ) { - CERROR("InterMezzo: no fileset in %s!\n", __FUNCTION__); - EXIT; - return -1; - } - - if (presto_chk(de, PRESTO_DONT_JOURNAL)) { - EXIT; - return 0; - } - - spin_lock(&fset->fset_permit_lock); - if (fset->fset_flags & FSET_HASPERMIT) { - if (fset->fset_permit_count > 0) - fset->fset_permit_count--; - else - CERROR("Put permit while permit count is 0, " - "inode %ld!\n", inode->i_ino); - } else { - fset->fset_permit_count = 0; - CERROR("InterMezzo: put permit while no permit, inode %ld, " - "flags %x!\n", inode->i_ino, fset->fset_flags); - } - - CDEBUG(D_INODE, "permit count now %d, inode %ld\n", - fset->fset_permit_count, inode->i_ino); - - if (fset->fset_flags & FSET_PERMIT_WAITING && - fset->fset_permit_count == 0) { - CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepers\n", - inode->i_ino); - wake_up_interruptible(&fset->fset_permit_queue); - } - spin_unlock(&fset->fset_permit_lock); - - EXIT; - return 0; -} - -void presto_getversion(struct presto_version * presto_version, - struct inode * inode) -{ - presto_version->pv_mtime_sec = inode->i_mtime.tv_sec; - presto_version->pv_mtime_nsec = inode->i_mtime.tv_nsec; - presto_version->pv_ctime_sec = inode->i_ctime.tv_sec; - presto_version->pv_ctime_nsec = inode->i_ctime.tv_nsec; - presto_version->pv_size = (__u64)inode->i_size; -} - - -/* If uuid is non-null, it is the uuid of the peer that's making the revocation - * request. If it is null, this request was made locally, without external - * pressure to give up the permit. This most often occurs when a client - * starts up. - * - * FIXME: this function needs to be refactored slightly once we start handling - * multiple clients. - */ -int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16]) -{ - struct presto_file_set *fset; - DECLARE_WAITQUEUE(wait, current); - int minor, rc; - - ENTRY; - - minor = presto_i2m(dentry->d_inode); - if (minor < 0) { - EXIT; - return -ENODEV; - } - - fset = presto_fset(dentry); - if (fset == NULL) { - EXIT; - return -ENODEV; - } - - spin_lock(&fset->fset_permit_lock); - if (fset->fset_flags & FSET_PERMIT_WAITING) { - CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported! Aborting this particular permit request...\n"); - EXIT; - spin_unlock(&fset->fset_permit_lock); - return -EINVAL; - } - - if (fset->fset_permit_count == 0) - goto got_permit; - - /* Something is still using this permit. Mark that we're waiting for it - * and go to sleep. */ - rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL); - spin_unlock(&fset->fset_permit_lock); - if (rc < 0) { - EXIT; - return rc; - } - - add_wait_queue(&fset->fset_permit_queue, &wait); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock(&fset->fset_permit_lock); - if (fset->fset_permit_count == 0) - break; - spin_unlock(&fset->fset_permit_lock); - - if (signal_pending(current)) { - /* FIXME: there must be a better thing to return... */ - remove_wait_queue(&fset->fset_permit_queue, &wait); - EXIT; - return -ERESTARTSYS; - } - - /* FIXME: maybe there should be a timeout here. */ - - schedule(); - } - - remove_wait_queue(&fset->fset_permit_queue, &wait); - got_permit: - /* By this point fset->fset_permit_count is zero and we're holding the - * lock. */ - CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ld\n", - dentry->d_inode->i_ino); - - if (uuid != NULL) { - rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid); - if (rc < 0) { - spin_unlock(&fset->fset_permit_lock); - EXIT; - return rc; - } - } - - izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL); - izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL); - spin_unlock(&fset->fset_permit_lock); - EXIT; - return 0; -} - -inline int presto_is_read_only(struct presto_file_set * fset) -{ - int minor, mask; - struct presto_cache *cache = fset->fset_cache; - - minor= cache->cache_psdev->uc_minor; - mask= (ISLENTO(minor)? FSET_LENTO_RO : FSET_CLIENT_RO); - if ( fset->fset_flags & mask ) - return 1; - mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO); - return ((cache->cache_flags & mask)? 1 : 0); -} diff --git a/fs/intermezzo/psdev.c b/fs/intermezzo/psdev.c deleted file mode 100644 index 40a85cc7e..000000000 --- a/fs/intermezzo/psdev.c +++ /dev/null @@ -1,647 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * An implementation of a loadable kernel mode driver providing - * multiple kernel/user space bidirectional communications links. - * - * Author: Alan Cox - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * Adapted to become the Linux 2.0 Coda pseudo device - * Peter Braam - * Michael Callahan - * - * Changes for Linux 2.1 - * Copyright (c) 1997 Carnegie-Mellon University - * - * Redone again for InterMezzo - * Copyright (c) 1998 Peter J. Braam - * Copyright (c) 2000 Mountain View Data, Inc. - * Copyright (c) 2000 Tacitus Systems, Inc. - * Copyright (c) 2001 Cluster File Systems, Inc. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - - -#ifdef PRESTO_DEVEL -int presto_print_entry = 1; -int presto_debug = 4095; -#else -int presto_print_entry = 0; -int presto_debug = 0; -#endif - -/* Like inode.c (presto_sym_iops), the initializer is just to prevent - izo_channels from appearing as a COMMON symbol (and therefore - interfering with other modules that use the same variable name). */ -struct upc_channel izo_channels[MAX_CHANNEL] = {{0}}; - -int izo_psdev_get_free_channel(void) -{ - int i, result = -1; - - for (i = 0 ; i < MAX_CHANNEL ; i++ ) { - if (list_empty(&(izo_channels[i].uc_cache_list))) { - result = i; - break; - } - } - return result; -} - - -int izo_psdev_setpid(int minor) -{ - struct upc_channel *channel; - if (minor < 0 || minor >= MAX_CHANNEL) { - return -EINVAL; - } - - channel = &(izo_channels[minor]); - /* - * This ioctl is performed by each Lento that starts up - * and wants to do further communication with presto. - */ - CDEBUG(D_PSDEV, "Setting current pid to %d channel %d\n", - current->pid, minor); - channel->uc_pid = current->pid; - spin_lock(&channel->uc_lock); - if ( !list_empty(&channel->uc_processing) ) { - struct list_head *lh; - struct upc_req *req; - CERROR("WARNING: setpid & processing not empty!\n"); - list_for_each(lh, &channel->uc_processing) { - req = list_entry(lh, struct upc_req, rq_chain); - /* freeing of req and data is done by the sleeper */ - wake_up(&req->rq_sleep); - } - } - if ( !list_empty(&channel->uc_processing) ) { - CERROR("BAD: FAILDED TO CLEAN PROCESSING LIST!\n"); - } - spin_unlock(&channel->uc_lock); - EXIT; - return 0; -} - -int izo_psdev_setchannel(struct file *file, int fd) -{ - - struct file *psdev_file = fget(fd); - struct presto_cache *cache = presto_get_cache(file->f_dentry->d_inode); - - if (!psdev_file) { - CERROR("%s: no psdev_file!\n", __FUNCTION__); - return -EINVAL; - } - - if (!cache) { - CERROR("%s: no cache!\n", __FUNCTION__); - fput(psdev_file); - return -EINVAL; - } - - if (psdev_file->private_data) { - CERROR("%s: channel already set!\n", __FUNCTION__); - fput(psdev_file); - return -EINVAL; - } - - psdev_file->private_data = cache->cache_psdev; - fput(psdev_file); - EXIT; - return 0; -} - -inline int presto_lento_up(int minor) -{ - return izo_channels[minor].uc_pid; -} - -static unsigned int presto_psdev_poll(struct file *file, poll_table * wait) - { - struct upc_channel *channel = (struct upc_channel *)file->private_data; - unsigned int mask = POLLOUT | POLLWRNORM; - - /* ENTRY; this will flood you */ - if ( ! channel ) { - CERROR("%s: bad psdev file\n", __FUNCTION__); - return -EBADF; - } - - poll_wait(file, &(channel->uc_waitq), wait); - - spin_lock(&channel->uc_lock); - if (!list_empty(&channel->uc_pending)) { - CDEBUG(D_PSDEV, "Non-empty pending list.\n"); - mask |= POLLIN | POLLRDNORM; - } - spin_unlock(&channel->uc_lock); - - /* EXIT; will flood you */ - return mask; -} - -/* - * Receive a message written by Lento to the psdev - */ -static ssize_t presto_psdev_write(struct file *file, const char *buf, - size_t count, loff_t *off) -{ - struct upc_channel *channel = (struct upc_channel *)file->private_data; - struct upc_req *req = NULL; - struct upc_req *tmp; - struct list_head *lh; - struct izo_upcall_resp hdr; - int error; - - if ( ! channel ) { - CERROR("%s: bad psdev file\n", __FUNCTION__); - return -EBADF; - } - - /* Peek at the opcode, uniquefier */ - if ( count < sizeof(hdr) ) { - CERROR("presto_psdev_write: Lento didn't write full hdr.\n"); - return -EINVAL; - } - - error = copy_from_user(&hdr, buf, sizeof(hdr)); - if ( error ) - return -EFAULT; - - CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n", - current->pid, hdr.opcode, hdr.unique); - - spin_lock(&channel->uc_lock); - /* Look for the message on the processing queue. */ - list_for_each(lh, &channel->uc_processing) { - tmp = list_entry(lh, struct upc_req , rq_chain); - if (tmp->rq_unique == hdr.unique) { - req = tmp; - /* unlink here: keeps search length minimal */ - list_del_init(&req->rq_chain); - CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n", - hdr.opcode, hdr.unique); - break; - } - } - spin_unlock(&channel->uc_lock); - if (!req) { - CERROR("psdev_write: msg (%d, %d) not found\n", - hdr.opcode, hdr.unique); - return(-ESRCH); - } - - /* move data into response buffer. */ - if (req->rq_bufsize < count) { - CERROR("psdev_write: too much cnt: %d, cnt: %Zd, " - "opc: %d, uniq: %d.\n", - req->rq_bufsize, count, hdr.opcode, hdr.unique); - count = req->rq_bufsize; /* don't have more space! */ - } - error = copy_from_user(req->rq_data, buf, count); - if ( error ) - return -EFAULT; - - /* adjust outsize: good upcalls can be aware of this */ - req->rq_rep_size = count; - req->rq_flags |= REQ_WRITE; - - wake_up(&req->rq_sleep); - return(count); -} - -/* - * Read a message from the kernel to Lento - */ -static ssize_t presto_psdev_read(struct file * file, char * buf, - size_t count, loff_t *off) -{ - struct upc_channel *channel = (struct upc_channel *)file->private_data; - struct upc_req *req; - int result = count; - - if ( ! channel ) { - CERROR("%s: bad psdev file\n", __FUNCTION__); - return -EBADF; - } - - spin_lock(&channel->uc_lock); - if (list_empty(&(channel->uc_pending))) { - CDEBUG(D_UPCALL, "Empty pending list in read, not good\n"); - spin_unlock(&channel->uc_lock); - return -EINVAL; - } - req = list_entry((channel->uc_pending.next), struct upc_req, rq_chain); - list_del(&(req->rq_chain)); - if (! (req->rq_flags & REQ_ASYNC) ) { - list_add(&(req->rq_chain), channel->uc_processing.prev); - } - spin_unlock(&channel->uc_lock); - - req->rq_flags |= REQ_READ; - - /* Move the input args into userspace */ - CDEBUG(D_PSDEV, "\n"); - if (req->rq_bufsize <= count) { - result = req->rq_bufsize; - } - - if (count < req->rq_bufsize) { - CERROR ("psdev_read: buffer too small, read %Zd of %d bytes\n", - count, req->rq_bufsize); - } - - if ( copy_to_user(buf, req->rq_data, result) ) { - BUG(); - return -EFAULT; - } - - /* If request was asynchronous don't enqueue, but free */ - if (req->rq_flags & REQ_ASYNC) { - CDEBUG(D_PSDEV, "psdev_read: async msg (%d, %d), result %d\n", - req->rq_opcode, req->rq_unique, result); - PRESTO_FREE(req->rq_data, req->rq_bufsize); - PRESTO_FREE(req, sizeof(*req)); - return result; - } - - return result; -} - - -static int presto_psdev_open(struct inode * inode, struct file * file) -{ - ENTRY; - - file->private_data = NULL; - - CDEBUG(D_PSDEV, "Psdev_open: caller: %d, flags: %d\n", current->pid, file->f_flags); - - EXIT; - return 0; -} - - - -static int presto_psdev_release(struct inode * inode, struct file * file) -{ - struct upc_channel *channel = (struct upc_channel *)file->private_data; - struct upc_req *req; - struct list_head *lh; - ENTRY; - - if ( ! channel ) { - CERROR("%s: bad psdev file\n", __FUNCTION__); - return -EBADF; - } - - CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid); - channel->uc_pid = 0; - - /* Wake up clients so they can return. */ - CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n"); - spin_lock(&channel->uc_lock); - list_for_each(lh, &channel->uc_pending) { - req = list_entry(lh, struct upc_req, rq_chain); - - /* Async requests stay around for a new lento */ - if (req->rq_flags & REQ_ASYNC) { - continue; - } - /* the sleeper will free the req and data */ - req->rq_flags |= REQ_DEAD; - wake_up(&req->rq_sleep); - } - - CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n"); - list_for_each(lh, &channel->uc_processing) { - req = list_entry(lh, struct upc_req, rq_chain); - /* freeing of req and data is done by the sleeper */ - req->rq_flags |= REQ_DEAD; - wake_up(&req->rq_sleep); - } - spin_unlock(&channel->uc_lock); - CDEBUG(D_PSDEV, "Done.\n"); - - EXIT; - return 0; -} - -static struct file_operations presto_psdev_fops = { - .owner = THIS_MODULE, - .read = presto_psdev_read, - .write = presto_psdev_write, - .poll = presto_psdev_poll, - .open = presto_psdev_open, - .release = presto_psdev_release -}; - -/* modules setup */ -static struct miscdevice intermezzo_psdev = { - INTERMEZZO_MINOR, - "intermezzo", - &presto_psdev_fops -}; - -int presto_psdev_init(void) -{ - int i; - int err; - - if ( (err = misc_register(&intermezzo_psdev)) ) { - CERROR("%s: cannot register %d err %d\n", - __FUNCTION__, INTERMEZZO_MINOR, err); - return -EIO; - } - - memset(&izo_channels, 0, sizeof(izo_channels)); - for ( i = 0 ; i < MAX_CHANNEL ; i++ ) { - struct upc_channel *channel = &(izo_channels[i]); - INIT_LIST_HEAD(&channel->uc_pending); - INIT_LIST_HEAD(&channel->uc_processing); - INIT_LIST_HEAD(&channel->uc_cache_list); - init_waitqueue_head(&channel->uc_waitq); - channel->uc_lock = SPIN_LOCK_UNLOCKED; - channel->uc_hard = 0; - channel->uc_no_filter = 0; - channel->uc_no_journal = 0; - channel->uc_no_upcall = 0; - channel->uc_timeout = 30; - channel->uc_errorval = 0; - channel->uc_minor = i; - } - return 0; -} - -void presto_psdev_cleanup(void) -{ - int i; - - misc_deregister(&intermezzo_psdev); - - for ( i = 0 ; i < MAX_CHANNEL ; i++ ) { - struct upc_channel *channel = &(izo_channels[i]); - struct list_head *lh, *next; - - spin_lock(&channel->uc_lock); - if ( ! list_empty(&channel->uc_pending)) { - CERROR("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i); - } - if ( ! list_empty(&channel->uc_processing)) { - CERROR("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i); - } - if ( ! list_empty(&channel->uc_cache_list)) { - CERROR("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i); - } - list_for_each_safe(lh, next, &channel->uc_pending) { - struct upc_req *req; - - req = list_entry(lh, struct upc_req, rq_chain); - if ( req->rq_flags & REQ_ASYNC ) { - list_del(&(req->rq_chain)); - CDEBUG(D_UPCALL, "free pending upcall type %d\n", - req->rq_opcode); - PRESTO_FREE(req->rq_data, req->rq_bufsize); - PRESTO_FREE(req, sizeof(struct upc_req)); - } else { - req->rq_flags |= REQ_DEAD; - wake_up(&req->rq_sleep); - } - } - list_for_each(lh, &channel->uc_processing) { - struct upc_req *req; - req = list_entry(lh, struct upc_req, rq_chain); - list_del(&(req->rq_chain)); - req->rq_flags |= REQ_DEAD; - wake_up(&req->rq_sleep); - } - spin_unlock(&channel->uc_lock); - } -} - -/* - * lento_upcall and lento_downcall routines - */ -static inline unsigned long lento_waitfor_upcall - (struct upc_channel *channel, struct upc_req *req, int minor) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long posttime; - - req->rq_posttime = posttime = jiffies; - - add_wait_queue(&req->rq_sleep, &wait); - for (;;) { - if ( izo_channels[minor].uc_hard == 0 ) - set_current_state(TASK_INTERRUPTIBLE); - else - set_current_state(TASK_UNINTERRUPTIBLE); - - /* got a reply */ - if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) ) - break; - - /* these cases only apply when TASK_INTERRUPTIBLE */ - if ( !izo_channels[minor].uc_hard && signal_pending(current) ) { - /* if this process really wants to die, let it go */ - if (sigismember(&(current->pending.signal), SIGKILL)|| - sigismember(&(current->pending.signal), SIGINT) ) - break; - /* signal is present: after timeout always return - really smart idea, probably useless ... */ - if ( time_after(jiffies, req->rq_posttime + - izo_channels[minor].uc_timeout * HZ) ) - break; - } - schedule(); - } - - spin_lock(&channel->uc_lock); - list_del_init(&req->rq_chain); - spin_unlock(&channel->uc_lock); - remove_wait_queue(&req->rq_sleep, &wait); - set_current_state(TASK_RUNNING); - - CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", - posttime, jiffies-posttime); - return (jiffies - posttime); -} - -/* - * lento_upcall will return an error in the case of - * failed communication with Lento _or_ will peek at Lento - * reply and return Lento's error. - * - * As lento has 2 types of errors, normal errors (positive) and internal - * errors (negative), normal errors are negated, while internal errors - * are all mapped to -EINTR, while showing a nice warning message. (jh) - * - * lento_upcall will always free buffer, either directly, when an upcall - * is read (in presto_psdev_read), when the filesystem is unmounted, or - * when the module is unloaded. - */ -int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *buffer, - int async) -{ - unsigned long runtime; - struct upc_channel *channel; - struct izo_upcall_resp *out; - struct upc_req *req; - int error = 0; - - ENTRY; - channel = &(izo_channels[minor]); - - if (channel->uc_no_upcall) { - EXIT; - goto exit_buf; - } - if (!channel->uc_pid && !async) { - EXIT; - error = -ENXIO; - goto exit_buf; - } - - /* Format the request message. */ - PRESTO_ALLOC(req, sizeof(struct upc_req)); - if ( !req ) { - EXIT; - error = -ENOMEM; - goto exit_buf; - } - req->rq_data = (void *)buffer; - req->rq_flags = 0; - req->rq_bufsize = *size; - req->rq_rep_size = 0; - req->rq_opcode = buffer->u_opc; - req->rq_unique = ++channel->uc_seq; - init_waitqueue_head(&req->rq_sleep); - - /* Fill in the common input args. */ - buffer->u_uniq = req->rq_unique; - buffer->u_async = async; - - /* Remove potential datarace possibility*/ - if ( async ) - req->rq_flags = REQ_ASYNC; - - spin_lock(&channel->uc_lock); - /* Append msg to pending queue and poke Lento. */ - list_add(&req->rq_chain, channel->uc_pending.prev); - spin_unlock(&channel->uc_lock); - CDEBUG(D_UPCALL, - "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n", - current->pid, channel->uc_pid, req->rq_opcode, - req->rq_unique, req); - wake_up_interruptible(&channel->uc_waitq); - - if ( async ) { - /* req, rq_data are freed in presto_psdev_read for async */ - /* req->rq_flags = REQ_ASYNC;*/ - EXIT; - return 0; - } - - /* We can be interrupted while we wait for Lento to process - * our request. If the interrupt occurs before Lento has read - * the request, we dequeue and return. If it occurs after the - * read but before the reply, we dequeue, send a signal - * message, and return. If it occurs after the reply we ignore - * it. In no case do we want to restart the syscall. If it - * was interrupted by a lento shutdown (psdev_close), return - * ENODEV. */ - - /* Go to sleep. Wake up on signals only after the timeout. */ - runtime = lento_waitfor_upcall(channel, req, minor); - - CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", - req->rq_opcode, jiffies - req->rq_posttime, - req->rq_unique, req->rq_rep_size); - CDEBUG(D_UPCALL, - "..process %d woken up by Lento for req at 0x%p, data at %p\n", - current->pid, req, req->rq_data); - - if (channel->uc_pid) { /* i.e. Lento is still alive */ - /* Op went through, interrupt or not we go on */ - if (req->rq_flags & REQ_WRITE) { - out = (struct izo_upcall_resp *)req->rq_data; - /* here we map positive Lento errors to kernel errors */ - if ( out->result < 0 ) { - CERROR("Tell Peter: Lento returns negative error %d, for oc %d!\n", - out->result, out->opcode); - out->result = EINVAL; - } - error = -out->result; - CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n", - out->unique, out->opcode, out->result, out); - *size = req->rq_rep_size; - EXIT; - goto exit_req; - } - /* Interrupted before lento read it. */ - if ( !(req->rq_flags & REQ_READ) && signal_pending(current)) { - CDEBUG(D_UPCALL, - "Interrupt before read: (op,un)=(%d,%d), flags %x\n", - req->rq_opcode, req->rq_unique, req->rq_flags); - /* perhaps the best way to convince the app to give up? */ - error = -EINTR; - EXIT; - goto exit_req; - } - - /* interrupted after Lento did its read, send signal */ - if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) { - CDEBUG(D_UPCALL,"Interrupt after read: op = %d.%d, flags = %x\n", - req->rq_opcode, req->rq_unique, req->rq_flags); - - error = -EINTR; - } else { - CERROR("Lento: Strange interruption - tell Peter.\n"); - error = -EINTR; - } - } else { /* If lento died i.e. !UC_OPEN(channel) */ - CERROR("lento_upcall: Lento dead on (op,un) (%d.%d) flags %d\n", - req->rq_opcode, req->rq_unique, req->rq_flags); - error = -ENODEV; - } - -exit_req: - PRESTO_FREE(req, sizeof(struct upc_req)); -exit_buf: - PRESTO_FREE(buffer,*size); - return error; -} diff --git a/fs/intermezzo/replicator.c b/fs/intermezzo/replicator.c deleted file mode 100644 index e7a0c5c17..000000000 --- a/fs/intermezzo/replicator.c +++ /dev/null @@ -1,290 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001 Cluster File Systems, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Manage RCVD records for clients in the kernel - * - */ - -#include -#include - -#include -#include -#include - -#include "intermezzo_fs.h" - -/* - * this file contains a hash table of replicators/clients for a - * fileset. It allows fast lookup and update of reintegration status - */ - -struct izo_offset_rec { - struct list_head or_list; - char or_uuid[16]; - loff_t or_offset; -}; - -#define RCACHE_BITS 8 -#define RCACHE_SIZE (1 << RCACHE_BITS) -#define RCACHE_MASK (RCACHE_SIZE - 1) - -static struct list_head * -izo_rep_cache(void) -{ - int i; - struct list_head *cache; - PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE); - if (cache == NULL) { - CERROR("intermezzo-fatal: no memory for replicator cache\n"); - return NULL; - } - memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE); - for (i = 0; i < RCACHE_SIZE; i++) - INIT_LIST_HEAD(&cache[i]); - - return cache; -} - -static struct list_head * -izo_rep_hash(struct list_head *cache, char *uuid) -{ - return &cache[(RCACHE_MASK & uuid[1])]; -} - -static void -izo_rep_cache_clean(struct presto_file_set *fset) -{ - int i; - struct list_head *bucket; - struct list_head *tmp; - - if (fset->fset_clients == NULL) - return; - for (i = 0; i < RCACHE_SIZE; i++) { - tmp = bucket = &fset->fset_clients[i]; - - tmp = tmp->next; - while (tmp != bucket) { - struct izo_offset_rec *offrec; - tmp = tmp->next; - list_del(tmp); - offrec = list_entry(tmp, struct izo_offset_rec, - or_list); - PRESTO_FREE(offrec, sizeof(struct izo_offset_rec)); - } - } -} - -struct izo_offset_rec * -izo_rep_cache_find(struct presto_file_set *fset, char *uuid) -{ - struct list_head *tmp, *buck = izo_rep_hash(fset->fset_clients, uuid); - struct izo_offset_rec *rec = NULL; - - list_for_each(tmp, buck) { - rec = list_entry(tmp, struct izo_offset_rec, or_list); - if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 ) - return rec; - } - - return NULL; -} - -static int -izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec, - loff_t offset) -{ - struct izo_offset_rec *offrec; - - if (izo_rep_cache_find(fset, rec->lr_uuid)) { - CERROR("izo: duplicate client entry %s off %Ld\n", - fset->fset_name, offset); - return -EINVAL; - } - - PRESTO_ALLOC(offrec, sizeof(*offrec)); - if (offrec == NULL) { - CERROR("izo: cannot allocate offrec\n"); - return -ENOMEM; - } - - memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid)); - offrec->or_offset = offset; - - list_add(&offrec->or_list, - izo_rep_hash(fset->fset_clients, rec->lr_uuid)); - return 0; -} - -int -izo_rep_cache_init(struct presto_file_set *fset) -{ - struct izo_rcvd_rec rec; - loff_t offset = 0, last_offset = 0; - - fset->fset_clients = izo_rep_cache(); - if (fset->fset_clients == NULL) { - CERROR("Error initializing client cache\n"); - return -ENOMEM; - } - - while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec, - sizeof(rec), &offset) == sizeof(rec) ) { - int rc; - - if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) { - izo_rep_cache_clean(fset); - return rc; - } - - last_offset = offset; - } - - return 0; -} - -/* - * Return local last_rcvd record for the client. Update or create - * if necessary. - * - * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error. - */ -int -izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, - struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server) -{ - int rc; - rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid); - if (rc < 0 && rc != -EINVAL) { - return rc; - } - - /* client is new or has been reset. */ - if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) { - memset(lr_server, 0, sizeof(*lr_server)); - memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid)); - rc = izo_rcvd_write(fset, lr_server); - if (rc < 0) - return rc; - } - - /* update intersync */ - rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server); - return rc; -} - -loff_t -izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid) -{ - struct izo_offset_rec *offrec; - struct izo_rcvd_rec tmprec; - loff_t offset; - - offrec = izo_rep_cache_find(fset, uuid); - if (offrec == NULL) { - CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n"); - return -EINVAL; - } - offset = offrec->or_offset; - - if (rec == NULL) - return offset; - - if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec, - sizeof(tmprec), &offset) != sizeof(tmprec)) { - CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset " - "%Lu\n", offset); - return -EIO; - } - - memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid)); - rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno); - rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset); - rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno); - rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset); - rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime); - - return offrec->or_offset; -} - -/* Try to lookup the UUID in the hash. Insert it if it isn't found. Write the - * data to the file. - * - * Returns the offset of the beginning of the record in the last_rcvd file. */ -loff_t -izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec) -{ - struct izo_offset_rec *offrec; - loff_t offset, rc; - - ENTRY; - - offrec = izo_rep_cache_find(fset, rec->lr_uuid); - if (offrec == NULL) { - /* I don't think it should be possible for an entry to be not in - * the hash table without also having an invalid offset, but we - * handle it gracefully regardless. */ - write_lock(&fset->fset_rcvd.fd_lock); - offset = fset->fset_rcvd.fd_offset; - fset->fset_rcvd.fd_offset += sizeof(*rec); - write_unlock(&fset->fset_rcvd.fd_lock); - - rc = izo_rep_cache_add(fset, rec, offset); - if (rc < 0) { - EXIT; - return rc; - } - } else - offset = offrec->or_offset; - - - rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec), - &offset); - if (rc == sizeof(*rec)) - /* presto_fwrite() advances 'offset' */ - rc = offset - sizeof(*rec); - - EXIT; - return rc; -} - -loff_t -izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid, __u64 remote_recno, - __u64 remote_offset) -{ - struct izo_rcvd_rec rec; - - loff_t rc; - - ENTRY; - rc = izo_rcvd_get(&rec, fset, uuid); - if (rc < 0) - return rc; - rec.lr_remote_recno = remote_recno; - rec.lr_remote_offset = remote_offset; - - rc = izo_rcvd_write(fset, &rec); - EXIT; - if (rc < 0) - return rc; - return 0; -} diff --git a/fs/intermezzo/super.c b/fs/intermezzo/super.c deleted file mode 100644 index 9993ef2bf..000000000 --- a/fs/intermezzo/super.c +++ /dev/null @@ -1,407 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1998 Peter J. Braam - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * presto's super.c - */ - -static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.4 2002/10/12 02:16:19 rread Exp $"; -#define INTERMEZZO_VERSION "$Revision: 1.4 $" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#ifdef PRESTO_DEBUG -long presto_vmemory = 0; -long presto_kmemory = 0; -#endif - -/* returns an allocated string, copied out from data if opt is found */ -static char *opt_read(const char *opt, char *data) -{ - char *value; - char *retval; - - CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data); - if ( strncmp(opt, data, strlen(opt)) ) - return NULL; - - if ( (value = strchr(data, '=')) == NULL ) - return NULL; - - value++; - PRESTO_ALLOC(retval, strlen(value) + 1); - if ( !retval ) { - CERROR("InterMezzo: Out of memory!\n"); - return NULL; - } - - strcpy(retval, value); - CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval); - return retval; -} - -static void opt_store(char **dst, char *opt) -{ - if (!dst) - CERROR("intermezzo: store_opt, error dst == NULL\n"); - - if (*dst) - PRESTO_FREE(*dst, strlen(*dst) + 1); - *dst = opt; -} - -static void opt_set_default(char **dst, char *defval) -{ - if (!dst) - CERROR("intermezzo: store_opt, error dst == NULL\n"); - - if (*dst) - PRESTO_FREE(*dst, strlen(*dst) + 1); - if (defval) { - char *def_alloced; - PRESTO_ALLOC(def_alloced, strlen(defval)+1); - if (!def_alloced) { - CERROR("InterMezzo: Out of memory!\n"); - return ; - } - strcpy(def_alloced, defval); - *dst = def_alloced; - } -} - - -/* Find the options for InterMezzo in "options", saving them into the - * passed pointers. If the pointer is null, the option is discarded. - * Copy out all non-InterMezzo options into cache_data (to be passed - * to the read_super operation of the cache). The return value will - * be a pointer to the end of the cache_data. - */ -static char *presto_options(struct file_system_type *fstype, - char *options, char *cache_data, - char **cache_type, char **fileset, - char **channel) -{ - char *this_char; - char *opt_ptr = options; - char *cache_data_end = cache_data; - - /* set the defaults */ - if (strcmp(fstype->name, "intermezzo") == 0) - opt_set_default(cache_type, "ext3"); - else - opt_set_default(cache_type, "tmpfs"); - - if (!options || !cache_data) - return cache_data_end; - - - CDEBUG(D_SUPER, "parsing options\n"); - while ((this_char = strsep (&opt_ptr, ",")) != NULL) { - char *opt; - if (!*this_char) - continue; - CDEBUG(D_SUPER, "this_char %s\n", this_char); - - if ( (opt = opt_read("fileset", this_char)) ) { - opt_store(fileset, opt); - continue; - } - if ( (opt = opt_read("cache_type", this_char)) ) { - opt_store(cache_type, opt); - continue; - } - if ( (opt = opt_read("channel", this_char)) ) { - opt_store(channel, opt); - continue; - } - - cache_data_end += - sprintf(cache_data_end, "%s%s", - cache_data_end != cache_data ? ",":"", - this_char); - } - - return cache_data_end; -} - -static int presto_set_channel(struct presto_cache *cache, char *channel) -{ - int minor; - - ENTRY; - if (!channel) { - minor = izo_psdev_get_free_channel(); - } else { - minor = simple_strtoul(channel, NULL, 0); - } - if (minor < 0 || minor >= MAX_CHANNEL) { - CERROR("all channels in use or channel too large %d\n", - minor); - return -EINVAL; - } - - cache->cache_psdev = &(izo_channels[minor]); - list_add(&cache->cache_channel_list, - &cache->cache_psdev->uc_cache_list); - - EXIT; - return minor; -} - -/* We always need to remove the presto options before passing - mount options to cache FS */ -struct super_block * -presto_get_sb(struct file_system_type *izo_type, int flags, - const char *devname, void *data) -{ - struct file_system_type *fstype; - struct presto_cache *cache = NULL; - char *cache_data = NULL; - char *cache_data_end; - char *cache_type = NULL; - char *fileset = NULL; - char *channel = NULL; - struct super_block *sb; - int err; - unsigned int minor; - - ENTRY; - - /* reserve space for the cache's data */ - PRESTO_ALLOC(cache_data, PAGE_SIZE); - if ( !cache_data ) { - CERROR("presto_read_super: Cannot allocate data page.\n"); - EXIT; - goto out_err; - } - - /* read and validate options */ - cache_data_end = presto_options(izo_type, data, cache_data, &cache_type, - &fileset, &channel); - - /* was there anything for the cache filesystem in the data? */ - if (cache_data_end == cache_data) { - PRESTO_FREE(cache_data, PAGE_SIZE); - cache_data_end = cache_data = NULL; - } else { - CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data, - cache_data); - } - - /* set up the cache */ - cache = presto_cache_init(); - if ( !cache ) { - CERROR("presto_read_super: failure allocating cache.\n"); - EXIT; - goto out_err; - } - cache->cache_type = cache_type; - - /* link cache to channel */ - minor = presto_set_channel(cache, channel); - if (minor < 0) { - EXIT; - goto out_err; - } - - CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n", - cache_type, fileset?fileset:"NULL", minor, cache->cache_flags); - - /* get the filter for the cache */ - fstype = get_fs_type(cache_type); - cache->cache_filter = filter_get_filter_fs((const char *)cache_type); - if ( !fstype || !cache->cache_filter) { - CERROR("Presto: unrecognized fs type or cache type\n"); - EXIT; - goto out_err; - } - - sb = fstype->get_sb(fstype, flags, devname, cache_data); - - if ( !sb || IS_ERR(sb)) { - CERROR("InterMezzo: cache mount failure.\n"); - EXIT; - goto out_err; - } - - /* can we in fact mount the cache */ - if (sb->s_bdev && (strcmp(fstype->name, "vintermezzo") == 0)) { - CERROR("vintermezzo must not be used with a block device\n"); - EXIT; - goto out_err; - } - - /* this might have been freed above */ - if (cache_data) { - PRESTO_FREE(cache_data, PAGE_SIZE); - cache_data = NULL; - } - - cache->cache_sb = sb; - cache->cache_root = dget(sb->s_root); - - /* we now know the dev of the cache: hash the cache */ - presto_cache_add(cache); - err = izo_prepare_fileset(sb->s_root, fileset); - - filter_setup_journal_ops(cache->cache_filter, cache->cache_type); - - /* make sure we have our own super operations: sb - still contains the cache operations */ - filter_setup_super_ops(cache->cache_filter, sb->s_op, - &presto_super_ops); - sb->s_op = filter_c2usops(cache->cache_filter); - - /* get izo directory operations: sb->s_root->d_inode exists now */ - filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode, - &presto_dir_iops, &presto_dir_fops); - filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, - &presto_dentry_ops); - sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter); - sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter); - sb->s_root->d_op = filter_c2udops(cache->cache_filter); - - EXIT; - return sb; - - out_err: - CDEBUG(D_SUPER, "out_err called\n"); - if (cache) - PRESTO_FREE(cache, sizeof(struct presto_cache)); - if (cache_data) - PRESTO_FREE(cache_data, PAGE_SIZE); - if (fileset) - PRESTO_FREE(fileset, strlen(fileset) + 1); - if (channel) - PRESTO_FREE(channel, strlen(channel) + 1); - if (cache_type) - PRESTO_FREE(cache_type, strlen(cache_type) + 1); - - CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n", - presto_kmemory, presto_vmemory); - return ERR_PTR(-EINVAL); -} - - - - -#ifdef PRESTO_DEVEL -static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV); -static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER); -#else -static struct file_system_type vpresto_fs_type = { - .owner = THIS_MODULE, - .name = "vintermezzo", - .get_sb = presto_get_sb, - .kill_sb = kill_litter_super, -}; -static struct file_system_type presto_fs_type = { - .owner = THIS_MODULE, - .name = "intermezzo", - .get_sb = presto_get_sb, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -#endif - - - -int __init init_intermezzo_fs(void) -{ - int status; - - printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION - " info@clusterfs.com\n"); - - status = presto_psdev_init(); - if ( status ) { - CERROR("Problem (%d) in init_intermezzo_psdev\n", status); - return status; - } - - status = init_intermezzo_sysctl(); - if (status) { - CERROR("presto: failed in init_intermezzo_sysctl!\n"); - } - - presto_cache_init_hash(); - - if (!presto_init_ddata_cache()) { - CERROR("presto out of memory!\n"); - return -ENOMEM; - } - - status = register_filesystem(&presto_fs_type); - if (status) { - CERROR("presto: failed in register_filesystem!\n"); - } - status = register_filesystem(&vpresto_fs_type); - if (status) { - CERROR("vpresto: failed in register_filesystem!\n"); - } - return status; -} - -void __exit exit_intermezzo_fs(void) -{ - int err; - - ENTRY; - - if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) { - CERROR("presto: failed to unregister filesystem\n"); - } - if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) { - CERROR("vpresto: failed to unregister filesystem\n"); - } - - presto_psdev_cleanup(); - cleanup_intermezzo_sysctl(); - presto_cleanup_ddata_cache(); - CERROR("after cleanup: kmem %ld, vmem %ld\n", - presto_kmemory, presto_vmemory); -} - - -MODULE_AUTHOR("Cluster Filesystems Inc. "); -MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION); -MODULE_LICENSE("GPL"); - -module_init(init_intermezzo_fs) -module_exit(exit_intermezzo_fs) diff --git a/fs/intermezzo/sysctl.c b/fs/intermezzo/sysctl.c deleted file mode 100644 index 9436adf7a..000000000 --- a/fs/intermezzo/sysctl.c +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 1999 Peter J. Braam - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sysctrl entries for Intermezzo! - */ - -#include /* for CONFIG_PROC_FS */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -/* /proc entries */ - -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_fs_intermezzo; -int intermezzo_mount_get_info( char * buffer, char ** start, off_t offset, - int length) -{ - int len=0; - - /* this works as long as we are below 1024 characters! */ - *start = buffer + offset; - len -= offset; - - if ( len < 0 ) - return -EINVAL; - - return len; -} - -#endif - - -/* SYSCTL below */ - -static struct ctl_table_header *intermezzo_table_header = NULL; -/* 0x100 to avoid any chance of collisions at any point in the tree with - * non-directories - */ -#define PSDEV_INTERMEZZO (0x100) - -#define PSDEV_DEBUG 1 /* control debugging */ -#define PSDEV_TRACE 2 /* control enter/leave pattern */ -#define PSDEV_TIMEOUT 3 /* timeout on upcalls to become intrble */ -#define PSDEV_HARD 4 /* mount type "hard" or "soft" */ -#define PSDEV_NO_FILTER 5 /* controls presto_chk */ -#define PSDEV_NO_JOURNAL 6 /* controls presto_chk */ -#define PSDEV_NO_UPCALL 7 /* controls lento_upcall */ -#define PSDEV_ERRORVAL 8 /* controls presto_debug_fail_blkdev */ -#define PSDEV_EXCL_GID 9 /* which GID is ignored by presto */ -#define PSDEV_BYTES_TO_CLOSE 11 /* bytes to write before close */ - -/* These are global presto control options */ -#define PRESTO_PRIMARY_CTLCNT 2 -static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] = -{ - {PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec}, - {PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec}, -}; - -/* - * Intalling the sysctl entries: strategy - * - have templates for each /proc/sys/intermezzo/ entry - * such an entry exists for each /dev/presto - * (proto_channel_entry) - * - have a template for the contents of such directories - * (proto_psdev_table) - * - have the master table (presto_table) - * - * When installing, malloc, memcpy and fix up the pointers to point to - * the appropriate constants in izo_channels[your_minor] - */ - -static ctl_table proto_psdev_table[] = { - {PSDEV_HARD, "hard", 0, sizeof(int), 0644, NULL, &proc_dointvec}, - {PSDEV_NO_FILTER, "no_filter", 0, sizeof(int), 0644, NULL, &proc_dointvec}, - {PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, - {PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, - {PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, -#ifdef PRESTO_DEBUG - {PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, -#endif - { 0 } -}; - -static ctl_table proto_channel_entry = { - PSDEV_INTERMEZZO, 0, NULL, 0, 0555, 0, -}; - -static ctl_table intermezzo_table[2] = { - {PSDEV_INTERMEZZO, "intermezzo", NULL, 0, 0555, presto_table}, - {0} -}; - -/* support for external setting and getting of opts. */ -/* particularly via ioctl. The Right way to do this is via sysctl, - * but that will have to wait until intermezzo gets its own nice set of - * sysctl IDs - */ -/* we made these separate as setting may in future be more restricted - * than getting - */ -#ifdef RON_MINNICH -int dosetopt(int minor, struct psdev_opt *opt) -{ - int retval = 0; - int newval = opt->optval; - - ENTRY; - - switch(opt->optname) { - - case PSDEV_TIMEOUT: - izo_channels[minor].uc_timeout = newval; - break; - - case PSDEV_HARD: - izo_channels[minor].uc_hard = newval; - break; - - case PSDEV_NO_FILTER: - izo_channels[minor].uc_no_filter = newval; - break; - - case PSDEV_NO_JOURNAL: - izo_channels[minor].uc_no_journal = newval; - break; - - case PSDEV_NO_UPCALL: - izo_channels[minor].uc_no_upcall = newval; - break; - -#ifdef PRESTO_DEBUG - case PSDEV_ERRORVAL: { - /* If we have a positive arg, set a breakpoint for that - * value. If we have a negative arg, make that device - * read-only. FIXME It would be much better to only - * allow setting the underlying device read-only for the - * current presto cache. - */ - int errorval = izo_channels[minor].uc_errorval; - if (errorval < 0) { - if (newval == 0) - set_device_ro(-errorval, 0); - else - CERROR("device %s already read only\n", - kdevname(-errorval)); - } else { - if (newval < 0) - set_device_ro(-newval, 1); - izo_channels[minor].uc_errorval = newval; - CDEBUG(D_PSDEV, "setting errorval to %d\n", newval); - } - - break; - } -#endif - - case PSDEV_TRACE: - case PSDEV_DEBUG: - case PSDEV_BYTES_TO_CLOSE: - default: - CDEBUG(D_PSDEV, - "ioctl: dosetopt: minor %d, bad optname 0x%x, \n", - minor, opt->optname); - - retval = -EINVAL; - } - - EXIT; - return retval; -} - -int dogetopt(int minor, struct psdev_opt *opt) -{ - int retval = 0; - - ENTRY; - - switch(opt->optname) { - - case PSDEV_TIMEOUT: - opt->optval = izo_channels[minor].uc_timeout; - break; - - case PSDEV_HARD: - opt->optval = izo_channels[minor].uc_hard; - break; - - case PSDEV_NO_FILTER: - opt->optval = izo_channels[minor].uc_no_filter; - break; - - case PSDEV_NO_JOURNAL: - opt->optval = izo_channels[minor].uc_no_journal; - break; - - case PSDEV_NO_UPCALL: - opt->optval = izo_channels[minor].uc_no_upcall; - break; - -#ifdef PSDEV_DEBUG - case PSDEV_ERRORVAL: { - int errorval = izo_channels[minor].uc_errorval; - if (errorval < 0 && is_read_only(-errorval)) - CERROR("device %s has been set read-only\n", - kdevname(-errorval)); - opt->optval = izo_channels[minor].uc_errorval; - break; - } -#endif - - case PSDEV_TRACE: - case PSDEV_DEBUG: - case PSDEV_BYTES_TO_CLOSE: - default: - CDEBUG(D_PSDEV, - "ioctl: dogetopt: minor %d, bad optval 0x%x, \n", - minor, opt->optname); - - retval = -EINVAL; - } - - EXIT; - return retval; -} -#endif - - -/* allocate the tables for the presto devices. We need - * sizeof(proto_channel_table)/sizeof(proto_channel_table[0]) - * entries for each dev - */ -int /* __init */ init_intermezzo_sysctl(void) -{ - int i; - int total_dev = MAX_CHANNEL; - int entries_per_dev = sizeof(proto_psdev_table) / - sizeof(proto_psdev_table[0]); - int total_entries = entries_per_dev * total_dev; - ctl_table *dev_ctl_table; - - PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries); - - if (! dev_ctl_table) { - CERROR("WARNING: presto couldn't allocate dev_ctl_table\n"); - EXIT; - return -ENOMEM; - } - - /* now fill in the entries ... we put the individual presto - * entries at the end of the table, and the per-presto stuff - * starting at the front. We assume that the compiler makes - * this code more efficient, but really, who cares ... it - * happens once per reboot. - */ - for(i = 0; i < total_dev; i++) { - void *p; - - /* entry for this /proc/sys/intermezzo/intermezzo"i" */ - ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; - /* entries for the individual "files" in this "directory" */ - ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev]; - /* init the psdev and psdev_entries with the prototypes */ - *psdev = proto_channel_entry; - memcpy(psdev_entries, proto_psdev_table, - sizeof(proto_psdev_table)); - /* now specialize them ... */ - /* the psdev has to point to psdev_entries, and fix the number */ - psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */ - - PRESTO_ALLOC(p, PROCNAME_SIZE); - psdev->procname = p; - if (!psdev->procname) { - PRESTO_FREE(dev_ctl_table, - sizeof(ctl_table) * total_entries); - return -ENOMEM; - } - sprintf((char *) psdev->procname, "intermezzo%d", i); - /* hook presto into */ - psdev->child = psdev_entries; - - /* now for each psdev entry ... */ - psdev_entries[0].data = &(izo_channels[i].uc_hard); - psdev_entries[1].data = &(izo_channels[i].uc_no_filter); - psdev_entries[2].data = &(izo_channels[i].uc_no_journal); - psdev_entries[3].data = &(izo_channels[i].uc_no_upcall); - psdev_entries[4].data = &(izo_channels[i].uc_timeout); -#ifdef PRESTO_DEBUG - psdev_entries[5].data = &(izo_channels[i].uc_errorval); -#endif - } - - -#ifdef CONFIG_SYSCTL - if ( !intermezzo_table_header ) - intermezzo_table_header = - register_sysctl_table(intermezzo_table, 0); -#endif -#ifdef CONFIG_PROC_FS - proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs); - proc_fs_intermezzo->owner = THIS_MODULE; - create_proc_info_entry("mounts", 0, proc_fs_intermezzo, - intermezzo_mount_get_info); -#endif - return 0; -} - -void cleanup_intermezzo_sysctl(void) -{ - int total_dev = MAX_CHANNEL; - int entries_per_dev = sizeof(proto_psdev_table) / - sizeof(proto_psdev_table[0]); - int total_entries = entries_per_dev * total_dev; - int i; - -#ifdef CONFIG_SYSCTL - if ( intermezzo_table_header ) - unregister_sysctl_table(intermezzo_table_header); - intermezzo_table_header = NULL; -#endif - for(i = 0; i < total_dev; i++) { - /* entry for this /proc/sys/intermezzo/intermezzo"i" */ - ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; - PRESTO_FREE(psdev->procname, PROCNAME_SIZE); - } - /* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the - * dev_ctl_table previously allocated in init_intermezzo_psdev() - */ - PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("mounts", proc_fs_intermezzo); - remove_proc_entry("intermezzo", proc_root_fs); -#endif -} - diff --git a/fs/intermezzo/upcall.c b/fs/intermezzo/upcall.c deleted file mode 100644 index 8019157dd..000000000 --- a/fs/intermezzo/upcall.c +++ /dev/null @@ -1,559 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001, 2002 Cluster File Systems, Inc. - * Copyright (C) 2001 Tacit Networks, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Mostly platform independent upcall operations to a cache manager: - * -- upcalls - * -- upcall routines - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intermezzo_lib.h" -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#include "intermezzo_idl.h" - -/* - At present: - -- Asynchronous calls: - - kml: give a "more" kml indication to userland - - kml_truncate: initiate KML truncation - - release_permit: kernel is done with permit - -- Synchronous - - open: fetch file - - permit: get a permit - - Errors returned by user level code are positive - - */ - -static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path, - char *fsetname, int reclen, char *rec, - int *size) -{ - struct izo_upcall_hdr *hdr; - char *ptr; - ENTRY; - - *size = sizeof(struct izo_upcall_hdr); - if ( fsetname ) { - *size += round_strlen(fsetname); - } - if ( path ) { - *size += round_strlen(path); - } - if ( rec ) { - *size += size_round(reclen); - } - PRESTO_ALLOC(hdr, *size); - if (!hdr) { - CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode); - EXIT; - return NULL; - } - memset(hdr, 0, *size); - - ptr = (char *)hdr + sizeof(*hdr); - - /* XXX do we need fsuid ? */ - hdr->u_len = *size; - hdr->u_version = IZO_UPC_VERSION; - hdr->u_opc = opcode; - hdr->u_pid = current->pid; - hdr->u_uid = current->fsuid; - - if (path) { - /*XXX Robert: please review what len to pass in for - NUL terminated strings */ - hdr->u_pathlen = strlen(path); - LOGL0(path, hdr->u_pathlen, ptr); - } - if (fsetname) { - hdr->u_fsetlen = strlen(fsetname); - LOGL0(fsetname, strlen(fsetname), ptr); - } - if (rec) { - hdr->u_reclen = reclen; - LOGL(rec, reclen, ptr); - } - - EXIT; - return hdr; -} - -/* the upcalls */ -int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - - ENTRY; - if (!presto_lento_up(minor)) { - EXIT; - return 0; - } - - hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - hdr->u_offset = offset; - hdr->u_first_recno = first_recno; - hdr->u_length = length; - hdr->u_last_recno = last_recno; - - CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, " - "first %u, last %d; minor %d\n", - fsetname, - (unsigned long long) hdr->u_offset, - (unsigned long long) hdr->u_length, - hdr->u_first_recno, - hdr->u_last_recno, minor); - - error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS); - - EXIT; - return -error; -} - -int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - - ENTRY; - if (!presto_lento_up(minor)) { - EXIT; - return 0; - } - - hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - hdr->u_length = length; - hdr->u_last_recno = last_recno; - - CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, " - "last recno %d, minor %d\n", - fsetname, - (unsigned long long) hdr->u_length, - hdr->u_last_recno, minor); - - error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS); - - EXIT; - return error; -} - -int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname, - sizeof(*info), (char*)info, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - CDEBUG(D_UPCALL, "path %s\n", path); - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, - __u32 pathlen, char *path, char *fsetname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - CDEBUG(D_UPCALL, "path %s\n", path); - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname, - sizeof(*info), (char *)info, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - /* This is currently synchronous, kml_reint_record blocks */ - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path, - char *fsetname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - - ENTRY; - - hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path); - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - - if (error == -EROFS) { - int err; - CERROR("InterMezzo: ERROR - requested permit for read-only " - "fileset.\n Setting \"%s\" read-only!\n", path); - err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL); - if (err) - CERROR("InterMezzo ERROR: mark_cache %d\n", err); - } else if (error) { - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - } - - EXIT; - return error; -} - -/* This is a ping-pong upcall handled on the server when a client (uuid) - * requests the permit for itself. */ -int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16]) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - - ENTRY; - - hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid)); - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16], - __u64 kmlsize) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - hdr->u_offset = kmlsize; - memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid)); - - error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS); - if (error) - CERROR("%s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16], - int client_flag) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - hdr->u_offset = ip_address; - hdr->u_length = port; - memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid)); - hdr->u_first_recno = client_flag; - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) { - CERROR("%s: error %d\n", __FUNCTION__, error); - } - - EXIT; - return -error; -} - -int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid)); - hdr->u_length = kmlsize; - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("%s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_repstatus(int minor, char * fsetname, struct izo_rcvd_rec *lr_server) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname, - sizeof(*lr_server), (char*)lr_server, - &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("%s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - - -#if 0 -int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname, - char *branchname) -{ - int size, error; - struct izo_upcall_hdr *hdr; - int pathlen; - char *path; - ENTRY; - - hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname, - fsetname, strlen(branchname) + 1, branchname, &size); - if (!hdr || IS_ERR(hdr)) { - error = -PTR_ERR(hdr); - goto error; - } - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: error %d\n", error); - - error: - PRESTO_FREE(path, pathlen); - EXIT; - return error; -} -#endif - -int izo_upc_server_make_branch(int minor, char *fsetname) -{ - int size, error; - struct izo_upcall_hdr *hdr; - ENTRY; - - hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - error = -PTR_ERR(hdr); - goto error; - } - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: error %d\n", error); - - error: - EXIT; - return -error; -} - -int izo_upc_branch_undo(int minor, char *fsetname, char *branchname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname, - fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} - -int izo_upc_branch_redo(int minor, char *fsetname, char *branchname) -{ - int size; - int error; - struct izo_upcall_hdr *hdr; - ENTRY; - - if (!presto_lento_up(minor)) { - EXIT; - return -EIO; - } - - hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname, - fsetname, 0, NULL, &size); - if (!hdr || IS_ERR(hdr)) { - EXIT; - return -PTR_ERR(hdr); - } - - error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS); - if (error) - CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error); - - EXIT; - return -error; -} diff --git a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c deleted file mode 100644 index 84b5882a5..000000000 --- a/fs/intermezzo/vfs.c +++ /dev/null @@ -1,2416 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * - * Copyright (C) 2001, 2002 Cluster File Systems, Inc. - * Copyright (C) 2000 Stelias Computing, Inc. - * Copyright (C) 2000 Red Hat, Inc. - * - * This file is part of InterMezzo, http://www.inter-mezzo.org. - * - * InterMezzo is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * InterMezzo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with InterMezzo; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * vfs.c - * - * This file implements kernel downcalls from lento. - * - * Author: Rob Simmonds - * Andreas Dilger - * Copyright (C) 2000 Stelias Computing Inc - * Copyright (C) 2000 Red Hat Inc. - * - * Extended attribute support - * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. - * - * This code is based on code from namei.c in the linux file system; - * see copyright notice below. - */ - -/** namei.c copyright **/ - -/* - * linux/fs/namei.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ -/* - * Some corrections by tytso. - */ - -/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname - * lookup logic. - */ - -/** end of namei.c copyright **/ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "intermezzo_fs.h" -#include "intermezzo_psdev.h" - -#ifdef CONFIG_FS_EXT_ATTR -# include - -# if 0 /* was a broken check for Posix ACLs */ -# include -# endif -#endif - -extern struct inode_operations presto_sym_iops; - -/* Write the last_rcvd values to the last_rcvd file. We don't know what the - * UUID or last_ctime values are, so we have to read from the file first - * (sigh). - * exported for branch_reinter in kml_reint.c*/ -int presto_write_last_rcvd(struct rec_info *recinfo, - struct presto_file_set *fset, - struct lento_vfs_context *info) -{ - int rc; - struct izo_rcvd_rec rcvd_rec; - - ENTRY; - - memset(&rcvd_rec, 0, sizeof(rcvd_rec)); - memcpy(rcvd_rec.lr_uuid, info->uuid, sizeof(rcvd_rec.lr_uuid)); - rcvd_rec.lr_remote_recno = HTON__u64(info->recno); - rcvd_rec.lr_remote_offset = HTON__u64(info->kml_offset); - rcvd_rec.lr_local_recno = HTON__u64(recinfo->recno); - rcvd_rec.lr_local_offset = HTON__u64(recinfo->offset + recinfo->size); - - rc = izo_rcvd_write(fset, &rcvd_rec); - if (rc < 0) { - /* izo_rcvd_write returns negative errors and non-negative - * offsets */ - CERROR("InterMezzo: izo_rcvd_write failed: %d\n", rc); - EXIT; - return rc; - } - EXIT; - return 0; -} - -/* - * It's inline, so penalty for filesystems that don't use sticky bit is - * minimal. - */ -static inline int check_sticky(struct inode *dir, struct inode *inode) -{ - if (!(dir->i_mode & S_ISVTX)) - return 0; - if (inode->i_uid == current->fsuid) - return 0; - if (dir->i_uid == current->fsuid) - return 0; - return !capable(CAP_FOWNER); -} - -/* from linux/fs/namei.c */ -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; - error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); - if (error) - return error; - if (IS_APPEND(dir)) - return -EPERM; - if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| - IS_IMMUTABLE(victim->d_inode)) - return -EPERM; - if (isdir) { - if (!S_ISDIR(victim->d_inode->i_mode)) - return -ENOTDIR; - if (IS_ROOT(victim)) - return -EBUSY; - } else if (S_ISDIR(victim->d_inode->i_mode)) - return -EISDIR; - return 0; -} - -/* from linux/fs/namei.c */ -static inline int may_create(struct inode *dir, struct dentry *child) { - if (child->d_inode) - return -EEXIST; - if (IS_DEADDIR(dir)) - return -ENOENT; - return permission(dir,MAY_WRITE | MAY_EXEC, NULL); -} - -#ifdef PRESTO_DEBUG -/* The loop_discard_io() function is available via a kernel patch to the - * loop block device. It "works" by accepting writes, but throwing them - * away, rather than trying to write them to disk. The old method worked - * by setting the underlying device read-only, but that has the problem - * that dirty buffers are kept in memory, and ext3 didn't like that at all. - */ -#ifdef CONFIG_LOOP_DISCARD -#define BLKDEV_FAIL(dev,fail) loop_discard_io(dev,fail) -#else -#define BLKDEV_FAIL(dev,fail) set_device_ro(dev, 1) -#endif - -/* If a breakpoint has been set via /proc/sys/intermezzo/intermezzoX/errorval, - * that is the same as "value", the underlying device will "fail" now. - */ -inline void presto_debug_fail_blkdev(struct presto_file_set *fset, - unsigned long value) -{ - int minor = presto_f2m(fset); - int errorval = izo_channels[minor].uc_errorval; - struct block_device *bdev = fset->fset_dentry->d_inode->i_sb->s_bdev; - char b[BDEVNAME_SIZE]; - - if (errorval && errorval == (long)value && !bdev_read_only(bdev)) { - CDEBUG(D_SUPER, "setting device %s read only\n", - bdevname(bdev, b)); - BLKDEV_FAIL(bdev, 1); - izo_channels[minor].uc_errorval = -bdev->bd_dev; - } -} -#else -#define presto_debug_fail_blkdev(dev,value) do {} while (0) -#endif - - -static inline int presto_do_kml(struct lento_vfs_context *info, - struct dentry *dentry) -{ - if ( ! (info->flags & LENTO_FL_KML) ) - return 0; - if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) ) - return 0; - return 1; -} - -static inline int presto_do_rcvd(struct lento_vfs_context *info, - struct dentry *dentry) -{ - if ( ! (info->flags & LENTO_FL_EXPECT) ) - return 0; - if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) ) - return 0; - return 1; -} - - -/* XXX fixme: this should not fail, all these dentries are in memory - when _we_ call this */ -int presto_settime(struct presto_file_set *fset, - struct dentry *newobj, - struct dentry *parent, - struct dentry *target, - struct lento_vfs_context *ctx, - int valid) -{ - int error = 0; - struct dentry *dentry; - struct inode *inode; - struct inode_operations *iops; - struct iattr iattr; - - ENTRY; - if (ctx->flags & LENTO_FL_IGNORE_TIME ) { - EXIT; - return 0; - } - - iattr.ia_ctime = ctx->updated_time; - iattr.ia_mtime = ctx->updated_time; - iattr.ia_valid = valid; - - while (1) { - if (parent && ctx->flags & LENTO_FL_TOUCH_PARENT) { - dentry = parent; - parent = NULL; - } else if (newobj && ctx->flags & LENTO_FL_TOUCH_NEWOBJ) { - dentry = newobj; - newobj = NULL; - } else if (target) { - dentry = target; - target = NULL; - } else - break; - - inode = dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) { - EXIT; - return -EROFS; - } - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - EXIT; - return -EPERM; - } - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops) { - EXIT; - return error; - } - - if (iops->setattr != NULL) - error = iops->setattr(dentry, &iattr); - else { - error = 0; - inode_setattr(dentry->d_inode, &iattr); - } - } - EXIT; - return error; -} - -void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb) -{ - rb->rb_mode = (__u32)inode->i_mode; - rb->rb_rdev = (__u32)old_encode_dev(inode->i_rdev); - rb->rb_uid = (__u64)inode->i_uid; - rb->rb_gid = (__u64)inode->i_gid; -} - - -int presto_do_close(struct presto_file_set *fset, struct file *file) -{ - struct rec_info rec; - int rc = -ENOSPC; - void *handle; - struct inode *inode = file->f_dentry->d_inode; - struct presto_file_data *fdata = - (struct presto_file_data *)file->private_data; - - ENTRY; - presto_getversion(&fdata->fd_info.remote_version, inode); - - rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (rc) { - EXIT; - return rc; - } - - handle = presto_trans_start(fset, file->f_dentry->d_inode, - KML_OPCODE_RELEASE); - if ( IS_ERR(handle) ) { - CERROR("presto_release: no space for transaction\n"); - return rc; - } - - if (fdata->fd_info.flags & LENTO_FL_KML) - rc = presto_journal_close(&rec, fset, fdata, file->f_dentry, - &fdata->fd_version, - &fdata->fd_info.remote_version); - if (rc) { - CERROR("presto_close: cannot journal close\n"); - goto out; - } - - if (fdata->fd_info.flags & LENTO_FL_EXPECT) - rc = presto_write_last_rcvd(&rec, fset, &fdata->fd_info); - - if (rc) { - CERROR("presto_close: cannot journal last_rcvd\n"); - goto out; - } - presto_trans_commit(fset, handle); - - /* cancel the LML record */ - handle = presto_trans_start(fset, inode, KML_OPCODE_WRITE); - if ( IS_ERR(handle) ) { - CERROR("presto_release: no space for clear\n"); - return -ENOSPC; - } - - rc = presto_clear_lml_close(fset, fdata->fd_lml_offset); - if (rc < 0 ) { - CERROR("presto_close: cannot journal close\n"); - goto out; - } - presto_truncate_lml(fset); - - out: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - presto_trans_commit(fset, handle); - EXIT; - return rc; -} - -int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry, - struct iattr *iattr, struct lento_vfs_context *info) -{ - struct rec_info rec; - struct inode *inode = dentry->d_inode; - struct inode_operations *iops; - int error; - struct presto_version old_ver, new_ver; - struct izo_rollback_data rb; - void *handle; - loff_t old_size=inode->i_size; - - ENTRY; - error = -EROFS; - if (IS_RDONLY(inode)) { - EXIT; - return -EROFS; - } - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - EXIT; - return -EPERM; - } - - presto_getversion(&old_ver, dentry->d_inode); - izo_get_rollback_data(dentry->d_inode, &rb); - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - - error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); - if (error) { - EXIT; - return error; - } - - if (iattr->ia_valid & ATTR_SIZE) { - if (izo_mark_dentry(dentry, ~PRESTO_DATA, 0, NULL) != 0) - CERROR("izo_mark_dentry(inode %ld, ~PRESTO_DATA) " - "failed\n", dentry->d_inode->i_ino); - handle = presto_trans_start(fset, dentry->d_inode, - KML_OPCODE_TRUNC); - } else { - handle = presto_trans_start(fset, dentry->d_inode, - KML_OPCODE_SETATTR); - } - - if ( IS_ERR(handle) ) { - CERROR("presto_do_setattr: no space for transaction\n"); - presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); - return -ENOSPC; - } - - if (dentry->d_inode && iops && iops->setattr) { - error = iops->setattr(dentry, iattr); - } else { - error = inode_change_ok(dentry->d_inode, iattr); - if (!error) - inode_setattr(inode, iattr); - } - - if (!error && (iattr->ia_valid & ATTR_SIZE)) - vmtruncate(inode, iattr->ia_size); - - if (error) { - EXIT; - goto exit; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x10); - - if ( presto_do_kml(info, dentry) ) { - if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) { - /* Journal a close whenever we see a potential truncate - * At the receiving end, lento should explicitly remove - * ATTR_SIZE from the list of valid attributes */ - presto_getversion(&new_ver, inode); - error = presto_journal_close(&rec, fset, NULL, dentry, - &old_ver, &new_ver); - } - - if (!error) - error = presto_journal_setattr(&rec, fset, dentry, - &old_ver, &rb, iattr); - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x20); - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x30); - - EXIT; -exit: - presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); - presto_trans_commit(fset, handle); - return error; -} - -int lento_setattr(const char *name, struct iattr *iattr, - struct lento_vfs_context *info) -{ - struct nameidata nd; - struct dentry *dentry; - struct presto_file_set *fset; - int error; -#if 0 /* was a broken check for Posix ACLs */ - int (*set_posix_acl)(struct inode *, int type, posix_acl_t *)=NULL; -#endif - - ENTRY; - CDEBUG(D_PIOCTL,"name %s, valid %#x, mode %#o, uid %d, gid %d, size %Ld\n", - name, iattr->ia_valid, iattr->ia_mode, iattr->ia_uid, - iattr->ia_gid, iattr->ia_size); - CDEBUG(D_PIOCTL, "atime %#lx, mtime %#lx, ctime %#lx, attr_flags %#x\n", - iattr->ia_atime.tv_sec, iattr->ia_mtime.tv_sec, iattr->ia_ctime.tv_sec, - iattr->ia_attr_flags); - CDEBUG(D_PIOCTL, "offset %d, recno %d, flags %#x\n", - info->slot_offset, info->recno, info->flags); - - lock_kernel(); - error = presto_walk(name, &nd); - if (error) { - EXIT; - goto exit; - } - dentry = nd.dentry; - - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit_lock; - } - - /* NOTE: this prevents us from changing the filetype on setattr, - * as we normally only want to change permission bits. - * If this is not correct, then we need to fix the perl code - * to always send the file type OR'ed with the permission. - */ - if (iattr->ia_valid & ATTR_MODE) { - int set_mode = iattr->ia_mode; - iattr->ia_mode = (iattr->ia_mode & S_IALLUGO) | - (dentry->d_inode->i_mode & ~S_IALLUGO); - CDEBUG(D_PIOCTL, "chmod: orig %#o, set %#o, result %#o\n", - dentry->d_inode->i_mode, set_mode, iattr->ia_mode); -#if 0 /* was a broken check for Posix ACLs */ - /* ACl code interacts badly with setattr - * since it tries to modify the ACL using - * set_ext_attr which recurses back into presto. - * This only happens if ATTR_MODE is set. - * Here we are doing a "forced" mode set - * (initiated by lento), so we disable the - * set_posix_acl operation which - * prevents such recursion. -SHP - * - * This will probably still be required when native - * acl journalling is in place. - */ - set_posix_acl=dentry->d_inode->i_op->set_posix_acl; - dentry->d_inode->i_op->set_posix_acl=NULL; -#endif - } - - error = presto_do_setattr(fset, dentry, iattr, info); - - if (info->flags & LENTO_FL_SET_DDFILEID) { - struct presto_dentry_data *dd = presto_d2d(dentry); - if (dd) { - dd->remote_ino = info->remote_ino; - dd->remote_generation = info->remote_generation; - } - } - -#if 0 /* was a broken check for Posix ACLs */ - /* restore the inode_operations if we changed them*/ - if (iattr->ia_valid & ATTR_MODE) - dentry->d_inode->i_op->set_posix_acl=set_posix_acl; -#endif - - - EXIT; -exit_lock: - path_release(&nd); -exit: - unlock_kernel(); - return error; -} - -int presto_do_create(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, - struct lento_vfs_context *info) -{ - struct rec_info rec; - int error; - struct presto_version tgt_dir_ver, new_file_ver; - struct inode_operations *iops; - void *handle; - - ENTRY; - mode &= S_IALLUGO; - mode |= S_IFREG; - - // down(&dir->d_inode->i_zombie); - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - error = may_create(dir->d_inode, dentry); - if (error) { - EXIT; - goto exit_pre_lock; - } - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->create) { - EXIT; - goto exit_pre_lock; - } - - presto_getversion(&tgt_dir_ver, dir->d_inode); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_CREATE); - if ( IS_ERR(handle) ) { - EXIT; - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - CERROR("presto_do_create: no space for transaction\n"); - error=-ENOSPC; - goto exit_pre_lock; - } - DQUOT_INIT(dir->d_inode); - lock_kernel(); - error = iops->create(dir->d_inode, dentry, mode, NULL); - if (error) { - EXIT; - goto exit_lock; - } - - if (dentry->d_inode) { - struct presto_cache *cache = fset->fset_cache; - /* was this already done? */ - presto_set_ops(dentry->d_inode, cache->cache_filter); - - filter_setup_dentry_ops(cache->cache_filter, - dentry->d_op, - &presto_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - - /* if Lento creates this file, we won't have data */ - if ( ISLENTO(presto_c2m(cache)) ) { - presto_set(dentry, PRESTO_ATTR); - } else { - presto_set(dentry, PRESTO_ATTR | PRESTO_DATA); - } - } - - info->flags |= LENTO_FL_TOUCH_PARENT; - error = presto_settime(fset, NULL, dir, dentry, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - goto exit_lock; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x10); - - if ( presto_do_kml(info, dentry) ) { - presto_getversion(&new_file_ver, dentry->d_inode); - error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver, - &new_file_ver, - dentry->d_inode->i_mode); - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x20); - - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x30); - - /* add inode dentry */ - if (fset->fset_cache->cache_filter->o_trops->tr_add_ilookup ) { - struct dentry *d; - d = fset->fset_cache->cache_filter->o_trops->tr_add_ilookup - (dir->d_inode->i_sb->s_root, dentry); - } - - EXIT; - - exit_lock: - unlock_kernel(); - presto_trans_commit(fset, handle); - exit_pre_lock: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - // up(&dir->d_inode->i_zombie); - return error; -} - -int lento_create(const char *name, int mode, struct lento_vfs_context *info) -{ - int error; - struct nameidata nd; - char * pathname; - struct dentry *dentry; - struct presto_file_set *fset; - - ENTRY; - pathname = getname(name); - error = PTR_ERR(pathname); - if (IS_ERR(pathname)) { - EXIT; - goto exit; - } - - /* this looks up the parent */ - error = path_lookup(pathname, LOOKUP_PARENT, &nd); - if (error) { - EXIT; - goto exit; - } - dentry = lookup_create(&nd, 0); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - EXIT; - goto exit_lock; - } - - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit_lock; - } - error = presto_do_create(fset, dentry->d_parent, dentry, (mode&S_IALLUGO)|S_IFREG, - info); - - EXIT; - - exit_lock: - path_release (&nd); - dput(dentry); - up(&dentry->d_parent->d_inode->i_sem); - putname(pathname); -exit: - return error; -} - -int presto_do_link(struct presto_file_set *fset, struct dentry *old_dentry, - struct dentry *dir, struct dentry *new_dentry, - struct lento_vfs_context *info) -{ - struct rec_info rec; - struct inode *inode; - int error; - struct inode_operations *iops; - struct presto_version tgt_dir_ver; - struct presto_version new_link_ver; - void *handle; - - // down(&dir->d_inode->i_zombie); - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - error = -ENOENT; - inode = old_dentry->d_inode; - if (!inode) - goto exit_lock; - - error = may_create(dir->d_inode, new_dentry); - if (error) - goto exit_lock; - - error = -EXDEV; - if (dir->d_inode->i_sb != inode->i_sb) - goto exit_lock; - - /* - * A link to an append-only or immutable file cannot be created. - */ - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { - EXIT; - goto exit_lock; - } - - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->link) { - EXIT; - goto exit_lock; - } - - - presto_getversion(&tgt_dir_ver, dir->d_inode); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_LINK); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - CERROR("presto_do_link: no space for transaction\n"); - return -ENOSPC; - } - - DQUOT_INIT(dir->d_inode); - lock_kernel(); - error = iops->link(old_dentry, dir->d_inode, new_dentry); - unlock_kernel(); - if (error) { - EXIT; - goto exit_lock; - } - - /* link dd data to that of existing dentry */ - old_dentry->d_op->d_release(new_dentry); - if (!presto_d2d(old_dentry)) - BUG(); - presto_d2d(old_dentry)->dd_count++; - - new_dentry->d_fsdata = presto_d2d(old_dentry); - - info->flags |= LENTO_FL_TOUCH_PARENT; - error = presto_settime(fset, NULL, dir, new_dentry, - info, ATTR_CTIME); - if (error) { - EXIT; - goto exit_lock; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x10); - presto_getversion(&new_link_ver, new_dentry->d_inode); - if ( presto_do_kml(info, old_dentry) ) - error = presto_journal_link(&rec, fset, old_dentry, new_dentry, - &tgt_dir_ver, &new_link_ver); - - presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x20); - if ( presto_do_rcvd(info, old_dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x30); - EXIT; - presto_trans_commit(fset, handle); -exit_lock: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - // up(&dir->d_inode->i_zombie); - return error; -} - - -int lento_link(const char * oldname, const char * newname, - struct lento_vfs_context *info) -{ - int error; - char * to; - struct presto_file_set *fset; - - to = getname(newname); - error = PTR_ERR(to); - if (!IS_ERR(to)) { - struct dentry *new_dentry; - struct nameidata nd, old_nd; - - error = __user_walk(oldname, 0, &old_nd); - if (error) - goto exit; - error = path_lookup(to, LOOKUP_PARENT, &nd); - if (error) - goto out; - error = -EXDEV; - if (old_nd.mnt != nd.mnt) - goto out; - new_dentry = lookup_create(&nd, 0); - error = PTR_ERR(new_dentry); - - if (!IS_ERR(new_dentry)) { - fset = presto_fset(new_dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto out2; - } - error = presto_do_link(fset, old_nd.dentry, - nd.dentry, - new_dentry, info); - dput(new_dentry); - } - out2: - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); - out: - path_release(&old_nd); - exit: - putname(to); - } - return error; -} - -int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, struct lento_vfs_context *info) -{ - struct rec_info rec; - struct inode_operations *iops; - struct presto_version tgt_dir_ver, old_file_ver; - struct izo_rollback_data rb; - void *handle; - int do_kml = 0, do_rcvd = 0, linkno = 0, error, old_targetlen = 0; - char *old_target = NULL; - - ENTRY; - // down(&dir->d_inode->i_zombie); - error = may_delete(dir->d_inode, dentry, 0); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->unlink) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - - if (presto_d2d(dentry)) { - struct presto_dentry_data *dd = presto_d2d(dentry); - struct dentry *de = dd->dd_inodentry; - if (de && dentry->d_inode->i_nlink == 1) { - dd->dd_count--; - dd->dd_inodentry = NULL; - de->d_fsdata = NULL; - atomic_dec(&de->d_inode->i_count); - de->d_inode = NULL; - dput(de); - } - } - - presto_getversion(&tgt_dir_ver, dir->d_inode); - presto_getversion(&old_file_ver, dentry->d_inode); - izo_get_rollback_data(dentry->d_inode, &rb); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_UNLINK); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQLOW); - CERROR("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n"); - // up(&dir->d_inode->i_zombie); - return -ENOSPC; - } - DQUOT_INIT(dir->d_inode); - if (d_mountpoint(dentry)) - error = -EBUSY; - else { - lock_kernel(); - linkno = dentry->d_inode->i_nlink; - if (linkno > 1) { - dget(dentry); - } - - if (S_ISLNK(dentry->d_inode->i_mode)) { - mm_segment_t old_fs; - struct inode_operations *riops; - riops = filter_c2csiops(fset->fset_cache->cache_filter); - - PRESTO_ALLOC(old_target, PATH_MAX); - if (old_target == NULL) { - error = -ENOMEM; - EXIT; - goto exit; - } - - old_fs = get_fs(); - set_fs(get_ds()); - - if (riops->readlink == NULL) - CERROR("InterMezzo %s: no readlink iops.\n", - __FUNCTION__); - else - old_targetlen = - riops->readlink(dentry, old_target, - PATH_MAX); - if (old_targetlen < 0) { - CERROR("InterMezzo: readlink failed: %ld\n", - PTR_ERR(old_target)); - PRESTO_FREE(old_target, PATH_MAX); - old_target = NULL; - old_targetlen = 0; - } - set_fs(old_fs); - } - - do_kml = presto_do_kml(info, dir); - do_rcvd = presto_do_rcvd(info, dir); - error = iops->unlink(dir->d_inode, dentry); - unlock_kernel(); - } - - if (linkno > 1) { - /* FIXME: Combine this with the next call? */ - error = presto_settime(fset, NULL, NULL, dentry, - info, ATTR_CTIME); - dput(dentry); - if (error) { - EXIT; - goto exit; - } - } - - error = presto_settime(fset, NULL, NULL, dir, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - goto exit; - } - - // up(&dir->d_inode->i_zombie); - - presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x10); - if ( do_kml ) - error = presto_journal_unlink(&rec, fset, dir, &tgt_dir_ver, - &old_file_ver, &rb, dentry, - old_target, old_targetlen); - presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x20); - if ( do_rcvd ) { - error = presto_write_last_rcvd(&rec, fset, info); - } - presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x30); - EXIT; -exit: - presto_release_space(fset->fset_cache, PRESTO_REQLOW); - presto_trans_commit(fset, handle); - if (old_target != NULL) - PRESTO_FREE(old_target, PATH_MAX); - return error; -} - - -int lento_unlink(const char *pathname, struct lento_vfs_context *info) -{ - int error = 0; - char * name; - struct dentry *dentry; - struct nameidata nd; - struct presto_file_set *fset; - - ENTRY; - - name = getname(pathname); - if(IS_ERR(name)) - return PTR_ERR(name); - - error = path_lookup(name, LOOKUP_PARENT, &nd); - if (error) - goto exit; - error = -EISDIR; - if (nd.last_type != LAST_NORM) - goto exit1; - down(&nd.dentry->d_inode->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit2; - } - /* Why not before? Because we want correct error value */ - if (nd.last.name[nd.last.len]) - goto slashes; - error = presto_do_unlink(fset, nd.dentry, dentry, info); - if (!error) - d_delete(dentry); - exit2: - EXIT; - dput(dentry); - } - up(&nd.dentry->d_inode->i_sem); -exit1: - path_release(&nd); -exit: - putname(name); - - return error; - -slashes: - error = !dentry->d_inode ? -ENOENT : - S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; - goto exit2; -} - -int presto_do_symlink(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, const char *oldname, - struct lento_vfs_context *info) -{ - struct rec_info rec; - int error; - struct presto_version tgt_dir_ver, new_link_ver; - struct inode_operations *iops; - void *handle; - - ENTRY; - // down(&dir->d_inode->i_zombie); - /* record + max path len + space to free */ - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - error = may_create(dir->d_inode, dentry); - if (error) { - EXIT; - goto exit_lock; - } - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->symlink) { - EXIT; - goto exit_lock; - } - - presto_getversion(&tgt_dir_ver, dir->d_inode); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_SYMLINK); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - CERROR("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); - EXIT; - // up(&dir->d_inode->i_zombie); - return -ENOSPC; - } - DQUOT_INIT(dir->d_inode); - lock_kernel(); - error = iops->symlink(dir->d_inode, dentry, oldname); - if (error) { - EXIT; - goto exit; - } - - if (dentry->d_inode) { - struct presto_cache *cache = fset->fset_cache; - - presto_set_ops(dentry->d_inode, cache->cache_filter); - - filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, - &presto_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - /* XXX ? Cache state ? if Lento creates a symlink */ - if ( ISLENTO(presto_c2m(cache)) ) { - presto_set(dentry, PRESTO_ATTR); - } else { - presto_set(dentry, PRESTO_ATTR | PRESTO_DATA); - } - } - - info->flags |= LENTO_FL_TOUCH_PARENT; - error = presto_settime(fset, NULL, dir, dentry, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - goto exit; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x10); - presto_getversion(&new_link_ver, dentry->d_inode); - if ( presto_do_kml(info, dentry) ) - error = presto_journal_symlink(&rec, fset, dentry, oldname, - &tgt_dir_ver, &new_link_ver); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x20); - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x30); - EXIT; -exit: - unlock_kernel(); - presto_trans_commit(fset, handle); - exit_lock: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - // up(&dir->d_inode->i_zombie); - return error; -} - -int lento_symlink(const char *oldname, const char *newname, - struct lento_vfs_context *info) -{ - int error; - char *from; - char *to; - struct dentry *dentry; - struct presto_file_set *fset; - struct nameidata nd; - - ENTRY; - lock_kernel(); - from = getname(oldname); - error = PTR_ERR(from); - if (IS_ERR(from)) { - EXIT; - goto exit; - } - - to = getname(newname); - error = PTR_ERR(to); - if (IS_ERR(to)) { - EXIT; - goto exit_from; - } - - error = path_lookup(to, LOOKUP_PARENT, &nd); - if (error) { - EXIT; - goto exit_to; - } - - dentry = lookup_create(&nd, 0); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - path_release(&nd); - EXIT; - goto exit_to; - } - - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - path_release(&nd); - EXIT; - goto exit_lock; - } - error = presto_do_symlink(fset, nd.dentry, - dentry, from, info); - path_release(&nd); - EXIT; - exit_lock: - up(&nd.dentry->d_inode->i_sem); - dput(dentry); - exit_to: - putname(to); - exit_from: - putname(from); - exit: - unlock_kernel(); - return error; -} - -int presto_do_mkdir(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, - struct lento_vfs_context *info) -{ - struct rec_info rec; - int error; - struct presto_version tgt_dir_ver, new_dir_ver; - void *handle; - - ENTRY; - // down(&dir->d_inode->i_zombie); - - /* one journal record + directory block + room for removals*/ - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - error = may_create(dir->d_inode, dentry); - if (error) { - EXIT; - goto exit_lock; - } - - error = -EPERM; - if (!filter_c2cdiops(fset->fset_cache->cache_filter)->mkdir) { - EXIT; - goto exit_lock; - } - - error = -ENOSPC; - presto_getversion(&tgt_dir_ver, dir->d_inode); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKDIR); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - CERROR("presto_do_mkdir: no space for transaction\n"); - goto exit_lock; - } - - DQUOT_INIT(dir->d_inode); - mode &= (S_IRWXUGO|S_ISVTX); - lock_kernel(); - error = filter_c2cdiops(fset->fset_cache->cache_filter)->mkdir(dir->d_inode, dentry, mode); - if (error) { - EXIT; - goto exit; - } - - if ( dentry->d_inode && !error) { - struct presto_cache *cache = fset->fset_cache; - - presto_set_ops(dentry->d_inode, cache->cache_filter); - - filter_setup_dentry_ops(cache->cache_filter, - dentry->d_op, - &presto_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - /* if Lento does this, we won't have data */ - if ( ISLENTO(presto_c2m(cache)) ) { - presto_set(dentry, PRESTO_ATTR); - } else { - presto_set(dentry, PRESTO_ATTR | PRESTO_DATA); - } - } - - info->flags |= LENTO_FL_TOUCH_PARENT; - error = presto_settime(fset, NULL, dir, dentry, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - goto exit; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x10); - presto_getversion(&new_dir_ver, dentry->d_inode); - if ( presto_do_kml(info, dir) ) - error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver, - &new_dir_ver, - dentry->d_inode->i_mode); - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x20); - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x30); - EXIT; -exit: - unlock_kernel(); - presto_trans_commit(fset, handle); - exit_lock: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); - // up(&dir->d_inode->i_zombie); - return error; -} - -/* - * Look out: this function may change a normal dentry - * into a directory dentry (different size).. - */ -int lento_mkdir(const char *name, int mode, struct lento_vfs_context *info) -{ - int error; - char *pathname; - struct dentry *dentry; - struct presto_file_set *fset; - struct nameidata nd; - - ENTRY; - CDEBUG(D_PIOCTL, "name: %s, mode %o, offset %d, recno %d, flags %x\n", - name, mode, info->slot_offset, info->recno, info->flags); - pathname = getname(name); - error = PTR_ERR(pathname); - if (IS_ERR(pathname)) { - EXIT; - return error; - } - - error = path_lookup(pathname, LOOKUP_PARENT, &nd); - if (error) - goto out_name; - - dentry = lookup_create(&nd, 1); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - fset = presto_fset(dentry); - error = -EINVAL; - if (!fset) { - CERROR("No fileset!\n"); - EXIT; - goto out_dput; - } - - error = presto_do_mkdir(fset, nd.dentry, dentry, - mode & S_IALLUGO, info); -out_dput: - dput(dentry); - } - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); -out_name: - EXIT; - putname(pathname); - CDEBUG(D_PIOCTL, "error: %d\n", error); - return error; -} - -static void d_unhash(struct dentry *dentry) -{ - dget(dentry); - switch (atomic_read(&dentry->d_count)) { - default: - shrink_dcache_parent(dentry); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - d_drop(dentry); - } -} - -int presto_do_rmdir(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, struct lento_vfs_context *info) -{ - struct rec_info rec; - int error; - struct presto_version tgt_dir_ver, old_dir_ver; - struct izo_rollback_data rb; - struct inode_operations *iops; - void *handle; - int do_kml, do_rcvd; - int size; - - ENTRY; - error = may_delete(dir->d_inode, dentry, 1); - if (error) - return error; - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->rmdir) { - EXIT; - return error; - } - - size = PRESTO_REQHIGH - dentry->d_inode->i_size; - error = presto_reserve_space(fset->fset_cache, size); - if (error) { - EXIT; - return error; - } - - presto_getversion(&tgt_dir_ver, dir->d_inode); - presto_getversion(&old_dir_ver, dentry->d_inode); - izo_get_rollback_data(dentry->d_inode, &rb); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_RMDIR); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, size); - CERROR("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n"); - return -ENOSPC; - } - - DQUOT_INIT(dir->d_inode); - - do_kml = presto_do_kml(info, dir); - do_rcvd = presto_do_rcvd(info, dir); - - // double_down(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie); - d_unhash(dentry); - if (IS_DEADDIR(dir->d_inode)) - error = -ENOENT; - else if (d_mountpoint(dentry)) { - CERROR("foo: d_mountpoint(dentry): ino %ld\n", - dentry->d_inode->i_ino); - error = -EBUSY; - } else { - lock_kernel(); - error = iops->rmdir(dir->d_inode, dentry); - unlock_kernel(); - if (!error) { - dentry->d_inode->i_flags |= S_DEAD; - error = presto_settime(fset, NULL, NULL, dir, info, - ATTR_CTIME | ATTR_MTIME); - } - } - // double_up(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie); - if (!error) - d_delete(dentry); - dput(dentry); - - presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x10); - if ( !error && do_kml ) - error = presto_journal_rmdir(&rec, fset, dir, &tgt_dir_ver, - &old_dir_ver, &rb, - dentry->d_name.len, - dentry->d_name.name); - - presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x20); - if ( !error && do_rcvd ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x30); - EXIT; - - presto_trans_commit(fset, handle); - presto_release_space(fset->fset_cache, size); - return error; -} - -int lento_rmdir(const char *pathname, struct lento_vfs_context *info) -{ - int error = 0; - char * name; - struct dentry *dentry; - struct presto_file_set *fset; - struct nameidata nd; - - ENTRY; - name = getname(pathname); - if(IS_ERR(name)) { - EXIT; - return PTR_ERR(name); - } - - error = path_lookup(name, LOOKUP_PARENT, &nd); - if (error) { - EXIT; - goto exit; - } - switch(nd.last_type) { - case LAST_DOTDOT: - error = -ENOTEMPTY; - EXIT; - goto exit1; - case LAST_ROOT: - case LAST_DOT: - error = -EBUSY; - EXIT; - goto exit1; - } - down(&nd.dentry->d_inode->i_sem); - dentry = lookup_hash(&nd.last, nd.dentry); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit_put; - } - error = presto_do_rmdir(fset, nd.dentry, dentry, info); - exit_put: - dput(dentry); - } - up(&nd.dentry->d_inode->i_sem); -exit1: - path_release(&nd); -exit: - putname(name); - EXIT; - return error; -} - -int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir, - struct dentry *dentry, int mode, dev_t dev, - struct lento_vfs_context *info) -{ - struct rec_info rec; - int error = -EPERM; - struct presto_version tgt_dir_ver, new_node_ver; - struct inode_operations *iops; - void *handle; - - ENTRY; - - // down(&dir->d_inode->i_zombie); - /* one KML entry */ - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (error) { - EXIT; - // up(&dir->d_inode->i_zombie); - return error; - } - - if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) { - EXIT; - goto exit_lock; - } - - error = may_create(dir->d_inode, dentry); - if (error) { - EXIT; - goto exit_lock; - } - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops->mknod) { - EXIT; - goto exit_lock; - } - - DQUOT_INIT(dir->d_inode); - lock_kernel(); - - error = -ENOSPC; - presto_getversion(&tgt_dir_ver, dir->d_inode); - handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKNOD); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - CERROR("presto_do_mknod: no space for transaction\n"); - goto exit_lock2; - } - - error = iops->mknod(dir->d_inode, dentry, mode, dev); - if (error) { - EXIT; - goto exit_commit; - } - if ( dentry->d_inode) { - struct presto_cache *cache = fset->fset_cache; - - presto_set_ops(dentry->d_inode, cache->cache_filter); - - filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, - &presto_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - - /* if Lento does this, we won't have data */ - if ( ISLENTO(presto_c2m(cache)) ) { - presto_set(dentry, PRESTO_ATTR); - } else { - presto_set(dentry, PRESTO_ATTR | PRESTO_DATA); - } - } - - error = presto_settime(fset, NULL, NULL, dir, - info, ATTR_MTIME); - if (error) { - EXIT; - } - error = presto_settime(fset, NULL, NULL, dentry, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - } - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x10); - presto_getversion(&new_node_ver, dentry->d_inode); - if ( presto_do_kml(info, dentry) ) - error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver, - &new_node_ver, - dentry->d_inode->i_mode, - MAJOR(dev), MINOR(dev) ); - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x20); - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x30); - EXIT; - exit_commit: - presto_trans_commit(fset, handle); - exit_lock2: - unlock_kernel(); - exit_lock: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - // up(&dir->d_inode->i_zombie); - return error; -} - -int lento_mknod(const char *filename, int mode, dev_t dev, - struct lento_vfs_context *info) -{ - int error = 0; - char * tmp; - struct dentry * dentry; - struct nameidata nd; - struct presto_file_set *fset; - - ENTRY; - - if (S_ISDIR(mode)) - return -EPERM; - tmp = getname(filename); - if (IS_ERR(tmp)) - return PTR_ERR(tmp); - - error = path_lookup(tmp, LOOKUP_PARENT, &nd); - if (error) - goto out; - dentry = lookup_create(&nd, 0); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - fset = presto_fset(dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit_put; - } - switch (mode & S_IFMT) { - case 0: case S_IFREG: - error = -EOPNOTSUPP; - break; - case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - error = presto_do_mknod(fset, nd.dentry, dentry, - mode, dev, info); - break; - case S_IFDIR: - error = -EPERM; - break; - default: - error = -EINVAL; - } - exit_put: - dput(dentry); - } - up(&nd.dentry->d_inode->i_sem); - path_release(&nd); -out: - putname(tmp); - - return error; -} - -int do_rename(struct presto_file_set *fset, - struct dentry *old_parent, struct dentry *old_dentry, - struct dentry *new_parent, struct dentry *new_dentry, - struct lento_vfs_context *info) -{ - struct rec_info rec; - int error; - struct inode_operations *iops; - struct presto_version src_dir_ver, tgt_dir_ver; - void *handle; - int new_inode_unlink = 0; - struct inode *old_dir = old_parent->d_inode; - struct inode *new_dir = new_parent->d_inode; - - ENTRY; - presto_getversion(&src_dir_ver, old_dir); - presto_getversion(&tgt_dir_ver, new_dir); - - error = -EPERM; - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops || !iops->rename) { - EXIT; - return error; - } - - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (error) { - EXIT; - return error; - } - handle = presto_trans_start(fset, old_dir, KML_OPCODE_RENAME); - if ( IS_ERR(handle) ) { - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - CERROR("presto_do_rename: no space for transaction\n"); - return -ENOSPC; - } - if (new_dentry->d_inode && new_dentry->d_inode->i_nlink > 1) { - dget(new_dentry); - new_inode_unlink = 1; - } - - error = iops->rename(old_dir, old_dentry, new_dir, new_dentry); - - if (error) { - EXIT; - goto exit; - } - - if (new_inode_unlink) { - error = presto_settime(fset, NULL, NULL, old_dentry, - info, ATTR_CTIME); - dput(old_dentry); - if (error) { - EXIT; - goto exit; - } - } - info->flags |= LENTO_FL_TOUCH_PARENT; - error = presto_settime(fset, NULL, new_parent, old_parent, - info, ATTR_CTIME | ATTR_MTIME); - if (error) { - EXIT; - goto exit; - } - - /* XXX make a distinction between cross file set - * and intra file set renames here - */ - presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x10); - if ( presto_do_kml(info, old_dentry) ) - error = presto_journal_rename(&rec, fset, old_dentry, - new_dentry, - &src_dir_ver, &tgt_dir_ver); - - presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x20); - - if ( presto_do_rcvd(info, old_dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x30); - EXIT; -exit: - presto_trans_commit(fset, handle); - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - return error; -} - -static -int presto_rename_dir(struct presto_file_set *fset, struct dentry *old_parent, - struct dentry *old_dentry, struct dentry *new_parent, - struct dentry *new_dentry, struct lento_vfs_context *info) -{ - int error; - struct inode *target; - struct inode *old_dir = old_parent->d_inode; - struct inode *new_dir = new_parent->d_inode; - - if (old_dentry->d_inode == new_dentry->d_inode) - return 0; - - error = may_delete(old_dir, old_dentry, 1); - if (error) - return error; - - if (new_dir->i_sb != old_dir->i_sb) - return -EXDEV; - - if (!new_dentry->d_inode) - error = may_create(new_dir, new_dentry); - else - error = may_delete(new_dir, new_dentry, 1); - if (error) - return error; - - if (!old_dir->i_op || !old_dir->i_op->rename) - return -EPERM; - - /* - * If we are going to change the parent - check write permissions, - * we'll need to flip '..'. - */ - if (new_dir != old_dir) { - error = permission(old_dentry->d_inode, MAY_WRITE, NULL); - } - if (error) - return error; - - DQUOT_INIT(old_dir); - DQUOT_INIT(new_dir); - down(&old_dir->i_sb->s_vfs_rename_sem); - error = -EINVAL; - if (is_subdir(new_dentry, old_dentry)) - goto out_unlock; - target = new_dentry->d_inode; - if (target) { /* Hastur! Hastur! Hastur! */ - // triple_down(&old_dir->i_zombie, - // &new_dir->i_zombie, - // &target->i_zombie); - d_unhash(new_dentry); - } else - // double_down(&old_dir->i_zombie, - // &new_dir->i_zombie); - 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 = do_rename(fset, old_parent, old_dentry, - new_parent, new_dentry, info); - if (target) { - if (!error) - target->i_flags |= S_DEAD; - // triple_up(&old_dir->i_zombie, - // &new_dir->i_zombie, - // &target->i_zombie); - if (d_unhashed(new_dentry)) - d_rehash(new_dentry); - dput(new_dentry); - } else - // double_up(&old_dir->i_zombie, - // &new_dir->i_zombie); - - if (!error) - d_move(old_dentry,new_dentry); -out_unlock: - up(&old_dir->i_sb->s_vfs_rename_sem); - return error; -} - -static -int presto_rename_other(struct presto_file_set *fset, struct dentry *old_parent, - struct dentry *old_dentry, struct dentry *new_parent, - struct dentry *new_dentry, struct lento_vfs_context *info) -{ - struct inode *old_dir = old_parent->d_inode; - struct inode *new_dir = new_parent->d_inode; - int error; - - if (old_dentry->d_inode == new_dentry->d_inode) - return 0; - - error = may_delete(old_dir, old_dentry, 0); - if (error) - return error; - - if (new_dir->i_sb != old_dir->i_sb) - return -EXDEV; - - if (!new_dentry->d_inode) - error = may_create(new_dir, new_dentry); - else - error = may_delete(new_dir, new_dentry, 0); - if (error) - return error; - - if (!old_dir->i_op || !old_dir->i_op->rename) - return -EPERM; - - DQUOT_INIT(old_dir); - DQUOT_INIT(new_dir); - // double_down(&old_dir->i_zombie, &new_dir->i_zombie); - if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) - error = -EBUSY; - else - error = do_rename(fset, old_parent, old_dentry, - new_parent, new_dentry, info); - // double_up(&old_dir->i_zombie, &new_dir->i_zombie); - if (error) - return error; - /* The following d_move() should become unconditional */ - if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) { - d_move(old_dentry, new_dentry); - } - return 0; -} - -int presto_do_rename(struct presto_file_set *fset, - struct dentry *old_parent, struct dentry *old_dentry, - struct dentry *new_parent, struct dentry *new_dentry, - struct lento_vfs_context *info) -{ - if (S_ISDIR(old_dentry->d_inode->i_mode)) - return presto_rename_dir(fset, old_parent,old_dentry,new_parent, - new_dentry, info); - else - return presto_rename_other(fset, old_parent, old_dentry, - new_parent,new_dentry, info); -} - - -int lento_do_rename(const char *oldname, const char *newname, - struct lento_vfs_context *info) -{ - int error = 0; - struct dentry * old_dir, * new_dir; - struct dentry * old_dentry, *new_dentry; - struct nameidata oldnd, newnd; - struct presto_file_set *fset; - - ENTRY; - - error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); - if (error) - goto exit; - - error = path_lookup(newname, LOOKUP_PARENT, &newnd); - if (error) - goto exit1; - - error = -EXDEV; - if (oldnd.mnt != newnd.mnt) - goto exit2; - - old_dir = oldnd.dentry; - error = -EBUSY; - if (oldnd.last_type != LAST_NORM) - goto exit2; - - new_dir = newnd.dentry; - if (newnd.last_type != LAST_NORM) - goto exit2; - - lock_rename(new_dir, old_dir); - - old_dentry = lookup_hash(&oldnd.last, old_dir); - error = PTR_ERR(old_dentry); - if (IS_ERR(old_dentry)) - goto exit3; - /* source must exist */ - error = -ENOENT; - if (!old_dentry->d_inode) - goto exit4; - fset = presto_fset(old_dentry); - error = -EINVAL; - if ( !fset ) { - CERROR("No fileset!\n"); - EXIT; - goto exit4; - } - /* unless the source is a directory trailing slashes give -ENOTDIR */ - if (!S_ISDIR(old_dentry->d_inode->i_mode)) { - error = -ENOTDIR; - if (oldnd.last.name[oldnd.last.len]) - goto exit4; - if (newnd.last.name[newnd.last.len]) - goto exit4; - } - new_dentry = lookup_hash(&newnd.last, new_dir); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) - goto exit4; - - lock_kernel(); - error = presto_do_rename(fset, old_dir, old_dentry, - new_dir, new_dentry, info); - unlock_kernel(); - - dput(new_dentry); -exit4: - dput(old_dentry); -exit3: - unlock_rename(new_dir, old_dir); -exit2: - path_release(&newnd); -exit1: - path_release(&oldnd); -exit: - return error; -} - -int lento_rename(const char * oldname, const char * newname, - struct lento_vfs_context *info) -{ - int error; - char * from; - char * to; - - from = getname(oldname); - if(IS_ERR(from)) - return PTR_ERR(from); - to = getname(newname); - error = PTR_ERR(to); - if (!IS_ERR(to)) { - error = lento_do_rename(from,to, info); - putname(to); - } - putname(from); - return error; -} - -struct dentry *presto_iopen(struct dentry *dentry, - ino_t ino, unsigned int generation) -{ - struct presto_file_set *fset; - char name[48]; - int error; - - ENTRY; - /* see if we already have the dentry we want */ - if (dentry->d_inode && dentry->d_inode->i_ino == ino && - dentry->d_inode->i_generation == generation) { - EXIT; - return dentry; - } - - /* Make sure we have a cache beneath us. We should always find at - * least one dentry inside the cache (if it exists), otherwise not - * even the cache root exists, or we passed in a bad name. - */ - fset = presto_fset(dentry); - error = -EINVAL; - if (!fset) { - CERROR("No fileset for %*s!\n", - dentry->d_name.len, dentry->d_name.name); - EXIT; - dput(dentry); - return ERR_PTR(error); - } - dput(dentry); - - sprintf(name, "%s%#lx%c%#x", - PRESTO_ILOOKUP_MAGIC, ino, PRESTO_ILOOKUP_SEP, generation); - CDEBUG(D_PIOCTL, "opening %ld by number (as %s)\n", ino, name); - return lookup_one_len(name, fset->fset_dentry, strlen(name)); -} - -static struct file *presto_filp_dopen(struct dentry *dentry, int flags) -{ - struct file *f; - struct inode *inode; - int flag, error; - - ENTRY; - error = -ENFILE; - f = get_empty_filp(); - if (!f) { - CDEBUG(D_PIOCTL, "error getting file pointer\n"); - EXIT; - goto out; - } - f->f_flags = flag = flags; - f->f_mode = (flag+1) & O_ACCMODE; - inode = dentry->d_inode; - if (f->f_mode & FMODE_WRITE) { - error = get_write_access(inode); - if (error) { - CDEBUG(D_PIOCTL, "error getting write access\n"); - EXIT; goto cleanup_file; - } - } - - /* XXX: where the fuck is ->f_vfsmnt? */ - f->f_dentry = dentry; - f->f_mapping = dentry->d_inode->i_mapping; - f->f_pos = 0; - //f->f_reada = 0; - f->f_op = NULL; - if (inode->i_op) - /* XXX should we set to presto ops, or leave at cache ops? */ - f->f_op = inode->i_fop; - if (f->f_op && f->f_op->open) { - error = f->f_op->open(inode, f); - if (error) { - CDEBUG(D_PIOCTL, "error calling cache 'open'\n"); - EXIT; - goto cleanup_all; - } - } - f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - - return f; - -cleanup_all: - if (f->f_mode & FMODE_WRITE) - put_write_access(inode); -cleanup_file: - put_filp(f); -out: - return ERR_PTR(error); -} - - -/* Open an inode by number. We pass in the cache root name (or a subdirectory - * from the cache that is guaranteed to exist) to be able to access the cache. - */ -int lento_iopen(const char *name, ino_t ino, unsigned int generation, - int flags) -{ - char * tmp; - struct dentry *dentry; - struct nameidata nd; - int fd; - int error; - - ENTRY; - CDEBUG(D_PIOCTL, - "open %s:inode %#lx (%ld), generation %x (%d), flags %d \n", - name, ino, ino, generation, generation, flags); - /* We don't allow creation of files by number only, as it would - * lead to a dangling files not in any directory. We could also - * just turn off the flag and ignore it. - */ - if (flags & O_CREAT) { - CERROR("%s: create file by inode number (%ld) not allowed\n", - __FUNCTION__, ino); - EXIT; - return -EACCES; - } - - tmp = getname(name); - if (IS_ERR(tmp)) { - EXIT; - return PTR_ERR(tmp); - } - - lock_kernel(); -again: /* look the named file or a parent directory so we can get the cache */ - error = presto_walk(tmp, &nd); - if ( error && error != -ENOENT ) { - EXIT; - unlock_kernel(); - putname(tmp); - return error; - } - if (error == -ENOENT) - dentry = NULL; - else - dentry = nd.dentry; - - /* we didn't find the named file, so see if a parent exists */ - if (!dentry) { - char *slash; - - slash = strrchr(tmp, '/'); - if (slash && slash != tmp) { - *slash = '\0'; - path_release(&nd); - goto again; - } - /* we should never get here... */ - CDEBUG(D_PIOCTL, "no more path components to try!\n"); - fd = -ENOENT; - goto exit; - } - CDEBUG(D_PIOCTL, "returned dentry %p\n", dentry); - - dentry = presto_iopen(dentry, ino, generation); - fd = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - EXIT; - goto exit; - } - - /* XXX start of code that might be replaced by something like: - * if (flags & (O_WRONLY | O_RDWR)) { - * error = get_write_access(dentry->d_inode); - * if (error) { - * EXIT; - * goto cleanup_dput; - * } - * } - * fd = open_dentry(dentry, flags); - * - * including the presto_filp_dopen() function (check dget counts!) - */ - fd = get_unused_fd(); - if (fd < 0) { - EXIT; - goto exit; - } - - { - int error; - struct file * f = presto_filp_dopen(dentry, flags); - error = PTR_ERR(f); - if (IS_ERR(f)) { - put_unused_fd(fd); - fd = error; - } else { - fd_install(fd, f); - } - } - /* end of code that might be replaced by open_dentry */ - - EXIT; -exit: - unlock_kernel(); - path_release(&nd); - putname(tmp); - return fd; -} - -#ifdef CONFIG_FS_EXT_ATTR - -#if 0 /* was a broken check for Posix ACLs */ -/* Posix ACL code changes i_mode without using a notify_change (or - * a mark_inode_dirty!). We need to duplicate this at the reintegrator - * which is done by this function. This function also takes care of - * resetting the cached posix acls in this inode. If we don't reset these - * VFS continues using the old acl information, which by now may be out of - * date. - */ -int presto_setmode(struct presto_file_set *fset, struct dentry *dentry, - mode_t mode) -{ - struct inode *inode = dentry->d_inode; - - ENTRY; - /* The extended attributes for this inode were modified. - * At this point we can not be sure if any of the ACL - * information for this inode was updated. So we will - * force VFS to reread the acls. Note that we do this - * only when called from the SETEXTATTR ioctl, which is why we - * do this while setting the mode of the file. Also note - * that mark_inode_dirty is not be needed for i_*acl only - * to force i_mode info to disk, and should be removed once - * we use notify_change to update the mode. - * XXX: is mode setting really needed? Just setting acl's should - * be enough! VFS should change the i_mode as needed? SHP - */ - if (inode->i_acl && - inode->i_acl != POSIX_ACL_NOT_CACHED) - posix_acl_release(inode->i_acl); - if (inode->i_default_acl && - inode->i_default_acl != POSIX_ACL_NOT_CACHED) - posix_acl_release(inode->i_default_acl); - inode->i_acl = POSIX_ACL_NOT_CACHED; - inode->i_default_acl = POSIX_ACL_NOT_CACHED; - inode->i_mode = mode; - /* inode should already be dirty...but just in case */ - mark_inode_dirty(inode); - return 0; - -#if 0 - /* XXX: The following code is the preferred way to set mode, - * however, I need to carefully go through possible recursion - * paths back into presto. See comments in presto_do_setattr. - */ - { - int error=0; - struct super_operations *sops; - struct iattr iattr; - - iattr.ia_mode = mode; - iattr.ia_valid = ATTR_MODE|ATTR_FORCE; - - error = -EPERM; - sops = filter_c2csops(fset->fset_cache->cache_filter); - if (!sops && - !sops->notify_change) { - EXIT; - return error; - } - - error = sops->notify_change(dentry, &iattr); - - EXIT; - return error; - } -#endif -} -#endif - -/* setextattr Interface to cache filesystem */ -int presto_do_set_ext_attr(struct presto_file_set *fset, - struct dentry *dentry, - const char *name, void *buffer, - size_t buffer_len, int flags, mode_t *mode, - struct lento_vfs_context *info) -{ - struct rec_info rec; - struct inode *inode = dentry->d_inode; - struct inode_operations *iops; - int error; - struct presto_version ver; - void *handle; - char temp[PRESTO_EXT_ATTR_NAME_MAX+1]; - - ENTRY; - error = -EROFS; - if (IS_RDONLY(inode)) { - EXIT; - return -EROFS; - } - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - EXIT; - return -EPERM; - } - - presto_getversion(&ver, inode); - error = -EPERM; - /* We need to invoke different filters based on whether - * this dentry is a regular file, directory or symlink. - */ - switch (inode->i_mode & S_IFMT) { - case S_IFLNK: /* symlink */ - iops = filter_c2csiops(fset->fset_cache->cache_filter); - break; - case S_IFDIR: /* directory */ - iops = filter_c2cdiops(fset->fset_cache->cache_filter); - break; - case S_IFREG: - default: /* everything else including regular files */ - iops = filter_c2cfiops(fset->fset_cache->cache_filter); - } - - if (!iops && !iops->set_ext_attr) { - EXIT; - return error; - } - - error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); - if (error) { - EXIT; - return error; - } - - - handle = presto_trans_start(fset,dentry->d_inode,KML_OPCODE_SETEXTATTR); - if ( IS_ERR(handle) ) { - CERROR("presto_do_set_ext_attr: no space for transaction\n"); - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - return -ENOSPC; - } - - /* We first "truncate" name to the maximum allowable in presto */ - /* This simulates the strncpy_from_use code in fs/ext_attr.c */ - strlcpy(temp,name,sizeof(temp)); - - /* Pass down to cache*/ - error = iops->set_ext_attr(inode,temp,buffer,buffer_len,flags); - if (error) { - EXIT; - goto exit; - } - -#if 0 /* was a broken check for Posix ACLs */ - /* Reset mode if specified*/ - /* XXX: when we do native acl support, move this code out! */ - if (mode != NULL) { - error = presto_setmode(fset, dentry, *mode); - if (error) { - EXIT; - goto exit; - } - } -#endif - - /* Reset ctime. Only inode change time (ctime) is affected */ - error = presto_settime(fset, NULL, NULL, dentry, info, ATTR_CTIME); - if (error) { - EXIT; - goto exit; - } - - if (flags & EXT_ATTR_FLAG_USER) { - CERROR(" USER flag passed to presto_do_set_ext_attr!\n"); - BUG(); - } - - /* We are here, so set_ext_attr succeeded. We no longer need to keep - * track of EXT_ATTR_FLAG_{EXISTS,CREATE}, instead, we will force - * the attribute value during log replay. -SHP - */ - flags &= ~(EXT_ATTR_FLAG_EXISTS | EXT_ATTR_FLAG_CREATE); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x10); - if ( presto_do_kml(info, dentry) ) - error = presto_journal_set_ext_attr - (&rec, fset, dentry, &ver, name, buffer, - buffer_len, flags); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x20); - if ( presto_do_rcvd(info, dentry) ) - error = presto_write_last_rcvd(&rec, fset, info); - - presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x30); - EXIT; -exit: - presto_release_space(fset->fset_cache, PRESTO_REQHIGH); - presto_trans_commit(fset, handle); - - return error; -} -#endif diff --git a/fs/ioctl.c b/fs/ioctl.c index aef5391e4..12f3e71d2 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -9,10 +9,18 @@ #include #include #include +#include +#include +#include #include #include +#ifdef CONFIG_VSERVER_LEGACY +extern int vx_proc_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); +#endif + static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) { int error; @@ -120,6 +128,48 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) else error = -ENOTTY; break; +#ifdef CONFIG_VSERVER_LEGACY +#ifndef CONFIG_INOXID_NONE + case FIOC_GETXID: { + struct inode *inode = filp->f_dentry->d_inode; + + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + if (capable(CAP_CONTEXT)) + error = put_user(inode->i_xid, (int *) arg); + break; + } + case FIOC_SETXID: { + struct inode *inode = filp->f_dentry->d_inode; + int xid; + + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + if (!capable(CAP_CONTEXT)) + break; + error = -EROFS; + if (IS_RDONLY(inode)) + break; + error = -ENOSYS; + if (!(inode->i_sb->s_flags & MS_TAGXID)) + break; + error = -EFAULT; + if (get_user(xid, (int *) arg)) + break; + error = 0; + inode->i_xid = (xid & 0xFFFF); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + break; + } +#endif + case FIOC_GETXFLG: + case FIOC_SETXFLG: + error = -ENOTTY; + if (filp->f_dentry->d_inode->i_sb->s_magic == PROC_SUPER_MAGIC) + error = vx_proc_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + break; +#endif default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) diff --git a/fs/isofs/export.c b/fs/isofs/export.c new file mode 100644 index 000000000..e4252c960 --- /dev/null +++ b/fs/isofs/export.c @@ -0,0 +1,228 @@ +/* + * fs/isofs/export.c + * + * (C) 2004 Paul Serice - The new inode scheme requires switching + * from iget() to iget5_locked() which means + * the NFS export operations have to be hand + * coded because the default routines rely on + * iget(). + * + * The following files are helpful: + * + * Documentation/filesystems/Exporting + * fs/exportfs/expfs.c. + */ + +#include +#include +#include +#include +#include + +static struct dentry * +isofs_export_iget(struct super_block *sb, + unsigned long block, + unsigned long offset, + __u32 generation) +{ + struct inode *inode; + struct dentry *result; + if (block == 0) + return ERR_PTR(-ESTALE); + inode = isofs_iget(sb, block, offset); + if (inode == NULL) + return ERR_PTR(-ENOMEM); + if (is_bad_inode(inode) + || (generation && inode->i_generation != generation)) + { + iput(inode); + return ERR_PTR(-ESTALE); + } + result = d_alloc_anon(inode); + if (!result) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + return result; +} + +static struct dentry * +isofs_export_get_dentry(struct super_block *sb, void *vobjp) +{ + __u32 *objp = vobjp; + unsigned long block = objp[0]; + unsigned long offset = objp[1]; + __u32 generation = objp[2]; + return isofs_export_iget(sb, block, offset, generation); +} + +/* This function is surprisingly simple. The trick is understanding + * that "child" is always a directory. So, to find its parent, you + * simply need to find its ".." entry, normalize its block and offset, + * and return the underlying inode. See the comments for + * isofs_normalize_block_and_offset(). */ +static struct dentry *isofs_export_get_parent(struct dentry *child) +{ + unsigned long parent_block = 0; + unsigned long parent_offset = 0; + struct inode *child_inode = child->d_inode; + struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); + struct inode *parent_inode = NULL; + struct iso_directory_record *de = NULL; + struct buffer_head * bh = NULL; + struct dentry *rv = NULL; + + /* "child" must always be a directory. */ + if (!S_ISDIR(child_inode->i_mode)) { + printk(KERN_ERR "isofs: isofs_export_get_parent(): " + "child is not a directory!\n"); + rv = ERR_PTR(-EACCES); + goto out; + } + + /* It is an invariant that the directory offset is zero. If + * it is not zero, it means the directory failed to be + * normalized for some reason. */ + if (e_child_inode->i_iget5_offset != 0) { + printk(KERN_ERR "isofs: isofs_export_get_parent(): " + "child directory not normalized!\n"); + rv = ERR_PTR(-EACCES); + goto out; + } + + /* The child inode has been normalized such that its + * i_iget5_block value points to the "." entry. Fortunately, + * the ".." entry is located in the same block. */ + parent_block = e_child_inode->i_iget5_block; + + /* Get the block in question. */ + bh = sb_bread(child_inode->i_sb, parent_block); + if (bh == NULL) { + rv = ERR_PTR(-EACCES); + goto out; + } + + /* This is the "." entry. */ + de = (struct iso_directory_record*)bh->b_data; + + /* The ".." entry is always the second entry. */ + parent_offset = (unsigned long)isonum_711(de->length); + de = (struct iso_directory_record*)(bh->b_data + parent_offset); + + /* Verify it is in fact the ".." entry. */ + if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) { + printk(KERN_ERR "isofs: Unable to find the \"..\" " + "directory for NFS.\n"); + rv = ERR_PTR(-EACCES); + goto out; + } + + /* Normalize */ + isofs_normalize_block_and_offset(de, &parent_block, &parent_offset); + + /* Get the inode. */ + parent_inode = isofs_iget(child_inode->i_sb, + parent_block, + parent_offset); + if (parent_inode == NULL) { + rv = ERR_PTR(-EACCES); + goto out; + } + + /* Allocate the dentry. */ + rv = d_alloc_anon(parent_inode); + if (rv == NULL) { + rv = ERR_PTR(-ENOMEM); + goto out; + } + + out: + if (bh) { + brelse(bh); + } + return rv; +} + +static int +isofs_export_encode_fh(struct dentry *dentry, + __u32 *fh32, + int *max_len, + int connectable) +{ + struct inode * inode = dentry->d_inode; + struct iso_inode_info * ei = ISOFS_I(inode); + int len = *max_len; + int type = 1; + __u16 *fh16 = (__u16*)fh32; + + /* + * WARNING: max_len is 5 for NFSv2. Because of this + * limitation, we use the lower 16 bits of fh32[1] to hold the + * offset of the inode and the upper 16 bits of fh32[1] to + * hold the offset of the parent. + */ + + if (len < 3 || (connectable && len < 5)) + return 255; + + len = 3; + fh32[0] = ei->i_iget5_block; + fh16[2] = (__u16)ei->i_iget5_offset; /* fh16 [sic] */ + fh32[2] = inode->i_generation; + if (connectable && !S_ISDIR(inode->i_mode)) { + struct inode *parent; + struct iso_inode_info *eparent; + spin_lock(&dentry->d_lock); + parent = dentry->d_parent->d_inode; + eparent = ISOFS_I(parent); + fh32[3] = eparent->i_iget5_block; + fh16[3] = (__u16)eparent->i_iget5_offset; /* fh16 [sic] */ + fh32[4] = parent->i_generation; + spin_unlock(&dentry->d_lock); + len = 5; + type = 2; + } + *max_len = len; + return type; +} + + +static struct dentry * +isofs_export_decode_fh(struct super_block *sb, + __u32 *fh32, + int fh_len, + int fileid_type, + int (*acceptable)(void *context, struct dentry *de), + void *context) +{ + __u16 *fh16 = (__u16*)fh32; + __u32 child[3]; /* The child is what triggered all this. */ + __u32 parent[3]; /* The parent is just along for the ride. */ + + if (fh_len < 3 || fileid_type > 2) + return NULL; + + child[0] = fh32[0]; + child[1] = fh16[2]; /* fh16 [sic] */ + child[2] = fh32[2]; + + parent[0] = 0; + parent[1] = 0; + parent[2] = 0; + if (fileid_type == 2) { + if (fh_len > 2) parent[0] = fh32[3]; + parent[1] = fh16[3]; /* fh16 [sic] */ + if (fh_len > 4) parent[2] = fh32[4]; + } + + return sb->s_export_op->find_exported_dentry(sb, child, parent, + acceptable, context); +} + + +struct export_operations isofs_export_ops = { + .decode_fh = isofs_export_decode_fh, + .encode_fh = isofs_export_encode_fh, + .get_dentry = isofs_export_get_dentry, + .get_parent = isofs_export_get_parent, +}; diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index a1e2a5d12..4197d4766 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -73,6 +73,7 @@ EXPORT_SYMBOL(journal_ack_err); EXPORT_SYMBOL(journal_clear_err); EXPORT_SYMBOL(log_wait_commit); EXPORT_SYMBOL(journal_start_commit); +EXPORT_SYMBOL(journal_force_commit_nested); EXPORT_SYMBOL(journal_wipe); EXPORT_SYMBOL(journal_blocks_per_page); EXPORT_SYMBOL(journal_invalidatepage); @@ -464,6 +465,39 @@ int log_start_commit(journal_t *journal, tid_t tid) return ret; } +/* + * Force and wait upon a commit if the calling process is not within + * transaction. This is used for forcing out undo-protected data which contains + * bitmaps, when the fs is running out of space. + * + * We can only force the running transaction if we don't have an active handle; + * otherwise, we will deadlock. + * + * Returns true if a transaction was started. + */ +int journal_force_commit_nested(journal_t *journal) +{ + transaction_t *transaction = NULL; + tid_t tid; + + spin_lock(&journal->j_state_lock); + if (journal->j_running_transaction && !current->journal_info) { + transaction = journal->j_running_transaction; + __log_start_commit(journal, transaction->t_tid); + } else if (journal->j_committing_transaction) + transaction = journal->j_committing_transaction; + + if (!transaction) { + spin_unlock(&journal->j_state_lock); + return 0; /* Nothing to retry */ + } + + tid = transaction->t_tid; + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + return 1; +} + /* * Start a commit of the current running transaction (if any). Returns true * if a transaction was started, and fills its tid in at *ptid @@ -585,13 +619,9 @@ int journal_bmap(journal_t *journal, unsigned long blocknr, * We play buffer_head aliasing tricks to write data/metadata blocks to * the journal without copying their contents, but for journal * descriptor blocks we do need to generate bona fide buffers. - * - * After the caller of journal_get_descriptor_buffer() has finished modifying - * the buffer's contents they really should run flush_dcache_page(bh->b_page). - * But we don't bother doing that, so there will be coherency problems with - * mmaps of blockdevs which hold live JBD-controlled filesystems. */ -struct journal_head *journal_get_descriptor_buffer(journal_t *journal) + +struct journal_head * journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; unsigned long blocknr; @@ -603,10 +633,8 @@ struct journal_head *journal_get_descriptor_buffer(journal_t *journal) return NULL; bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - lock_buffer(bh); memset(bh->b_data, 0, journal->j_blocksize); - set_buffer_uptodate(bh); - unlock_buffer(bh); + bh->b_state |= (1 << BH_Dirty); BUFFER_TRACE(bh, "return this buffer"); return journal_add_journal_head(bh); } diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 46d306cf0..9382d9384 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -17,41 +17,28 @@ #include #include "nodelist.h" -int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen); -int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); +static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); +static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { - .readlink = jffs2_readlink, + .readlink = generic_readlink, .follow_link = jffs2_follow_link, + .put_link = jffs2_put_link, .setattr = jffs2_setattr }; -int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - unsigned char *kbuf; - int ret; - - kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - - ret = vfs_readlink(dentry, buffer, buflen, kbuf); - kfree(kbuf); - return ret; -} - -int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) +static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; - int ret; - buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); + nd_set_link(nd, buf); + return 0; +} - if (IS_ERR(buf)) - return PTR_ERR(buf); - - ret = vfs_follow_link(nd, buf); - kfree(buf); - return ret; +static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) +{ + char *s = nd_get_link(nd); + if (!IS_ERR(s)) + kfree(s); } diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 3c3140dd7..1b49bbca6 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1,5 +1,5 @@ /* - * Copyright (C) International Business Machines Corp., 2000-2004 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -378,8 +378,6 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) * It's time to move the inline table to an external * page and begin to build the xtree */ - if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) - goto clean_up; /* No space */ /* * Save the table, we're going to overwrite it with the @@ -396,8 +394,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) /* * Allocate the first block & add it to the xtree */ + xaddr = 0; if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) { - /* This really shouldn't fail */ jfs_warn("add_index: xtInsert failed!"); memcpy(&jfs_ip->i_dirtable, temp_table, sizeof (temp_table)); @@ -766,12 +764,11 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, */ getChild: /* update max. number of pages to split */ - if (BT_STACK_FULL(btstack)) { + if (btstack->nsplit >= 8) { /* Something's corrupted, mark filesytem dirty so * chkdsk will fix it. */ jfs_error(sb, "stack overrun in dtSearch!"); - BT_STACK_DUMP(btstack); rc = -EIO; goto out; } @@ -978,10 +975,8 @@ static int dtSplitUp(tid_t tid, n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */ if (n <= split->nslot) xlen++; - if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) { - DT_PUTPAGE(smp); + if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) goto freeKeyName; - } pxdlist.maxnpxd = 1; pxdlist.npxd = 0; @@ -3347,12 +3342,6 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack) /* * descend down to leftmost child page */ - if (BT_STACK_FULL(btstack)) { - DT_PUTPAGE(mp); - jfs_error(ip->i_sb, "dtReadFirst: btstack overrun"); - BT_STACK_DUMP(btstack); - return -EIO; - } /* push (bn, index) of the parent page/entry */ BT_PUSH(btstack, bn, 0); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 865334f6c..848fbc8ba 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" @@ -3098,14 +3099,21 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno, static int copy_from_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + uid_t uid; + gid_t gid; jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff; ip->i_nlink = le32_to_cpu(dip->di_nlink); - ip->i_uid = le32_to_cpu(dip->di_uid); - ip->i_gid = le32_to_cpu(dip->di_gid); + + uid = le32_to_cpu(dip->di_uid); + gid = le32_to_cpu(dip->di_gid); + ip->i_uid = INOXID_UID(uid, gid); + ip->i_gid = INOXID_GID(uid, gid); + ip->i_xid = INOXID_XID(uid, gid, 0); + ip->i_size = le64_to_cpu(dip->di_size); ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec); ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec); @@ -3156,6 +3164,8 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) static void copy_to_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + uid_t uid; + gid_t gid; dip->di_fileset = cpu_to_le32(jfs_ip->fileset); dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp); @@ -3164,8 +3174,11 @@ static void copy_to_dinode(struct dinode * dip, struct inode *ip) dip->di_size = cpu_to_le64(ip->i_size); dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); dip->di_nlink = cpu_to_le32(ip->i_nlink); - dip->di_uid = cpu_to_le32(ip->i_uid); - dip->di_gid = cpu_to_le32(ip->i_gid); + + uid = XIDINO_UID(ip->i_uid, ip->i_xid); + gid = XIDINO_GID(ip->i_gid, ip->i_xid); + dip->di_uid = cpu_to_le32(uid); + dip->di_gid = cpu_to_le32(gid); /* * mode2 is only needed for storing the higher order bits. * Trust i_mode for the lower order ones diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 8c94bb015..1f3dfbc27 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -239,7 +239,6 @@ again: spin_unlock(&meta_lock); if (test_bit(META_stale, &mp->flag)) { release_metapage(mp); - yield(); /* Let other waiters release it, too */ goto again; } if (test_bit(META_discard, &mp->flag)) { diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index f48fdeae5..34b9b80f0 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1747,10 +1747,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, if (lwm == next) goto out; - if (lwm > next) { - jfs_err("xtLog: lwm > next\n"); - goto out; - } + assert(lwm < next); tlck->flag |= tlckUPDATEMAP; xadlock->flag = mlckALLOCXADLIST; xadlock->count = next - lwm; @@ -1916,18 +1913,25 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, /* * write log records */ - /* log after-image for logredo(): - * - * logredo() will update bmap for alloc of new/extended - * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from - * after-image of XADlist; - * logredo() resets (XAD_NEW|XAD_EXTEND) flag when - * applying the after-image to the meta-data page. + /* + * allocate entries XAD[lwm:next]: */ - lrd->type = cpu_to_le16(LOG_REDOPAGE); - PXDaddress(pxd, mp->index); - PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits); - lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + if (lwm < next) { + /* log after-image for logredo(): + * logredo() will update bmap for alloc of new/extended + * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from + * after-image of XADlist; + * logredo() resets (XAD_NEW|XAD_EXTEND) flag when + * applying the after-image to the meta-data page. + */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb-> + s_blocksize_bits); + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + } /* * truncate entry XAD[twm == next - 1]: @@ -2620,7 +2624,6 @@ void txAbort(tid_t tid, int dirty) lid_t lid, next; struct metapage *mp; struct tblock *tblk = tid_to_tblock(tid); - struct tlock *tlck; jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty); @@ -2628,10 +2631,9 @@ void txAbort(tid_t tid, int dirty) * free tlocks of the transaction */ for (lid = tblk->next; lid; lid = next) { - tlck = lid_to_tlock(lid); - next = tlck->next; - mp = tlck->mp; - JFS_IP(tlck->ip)->xtlid = 0; + next = lid_to_tlock(lid)->next; + + mp = lid_to_tlock(lid)->mp; if (mp) { mp->lid = 0; diff --git a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h index 3fefbf063..87ecbab5d 100644 --- a/fs/jfs/jfs_types.h +++ b/fs/jfs/jfs_types.h @@ -113,12 +113,11 @@ typedef struct { #define addressPXD(pxd)\ ( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2)) -#define MAXTREEHEIGHT 8 /* pxd list */ struct pxdlist { s16 maxnpxd; s16 npxd; - pxd_t pxd[MAXTREEHEIGHT]; + pxd_t pxd[8]; }; diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 998410ccc..c5b789e9e 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -858,7 +858,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, unchar *i_fastsymlink; s64 xlen = 0; int bmask = 0, xsize; - s64 extent = 0, xaddr; + s64 xaddr; struct metapage *mp; struct super_block *sb; struct tblock *tblk; @@ -892,11 +892,29 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) + goto out3; + tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; + /* + * create entry for symbolic link in parent directory + */ + + ino = ip->i_ino; + + + + if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { + jfs_err("jfs_symlink: dtInsert returned %d", rc); + /* discard ne inode */ + goto out3; + + } + /* fix symlink access permission * (dir_create() ANDs in the u.u_cmask, * but symlinks really need to be 777 access) @@ -904,7 +922,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ip->i_mode |= 0777; /* - * write symbolic link target path name + * write symbolic link target path name */ xtInitRoot(tid, ip); @@ -948,48 +966,37 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, xsize = (ssize + bmask) & ~bmask; xaddr = 0; xlen = xsize >> JFS_SBI(sb)->l2bsize; - if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) { - txAbort(tid, 0); + if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) { + ip->i_size = ssize - 1; + while (ssize) { + int copy_size = min(ssize, PSIZE); + + mp = get_metapage(ip, xaddr, PSIZE, 1); + + if (mp == NULL) { + dtDelete(tid, dip, &dname, &ino, + JFS_REMOVE); + rc = -EIO; + goto out3; + } + memcpy(mp->data, name, copy_size); + flush_metapage(mp); +#if 0 + set_buffer_uptodate(bp); + mark_buffer_dirty(bp, 1); + if (IS_SYNC(dip)) + sync_dirty_buffer(bp); + brelse(bp); +#endif /* 0 */ + ssize -= copy_size; + xaddr += JFS_SBI(sb)->nbperpage; + } + ip->i_blocks = LBLK2PBLK(sb, xlen); + } else { + dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); rc = -ENOSPC; goto out3; } - extent = xaddr; - ip->i_size = ssize - 1; - while (ssize) { - /* This is kind of silly since PATH_MAX == 4K */ - int copy_size = min(ssize, PSIZE); - - mp = get_metapage(ip, xaddr, PSIZE, 1); - - if (mp == NULL) { - dbFree(ip, extent, xlen); - rc = -EIO; - txAbort(tid, 0); - goto out3; - } - memcpy(mp->data, name, copy_size); - flush_metapage(mp); - ssize -= copy_size; - name += copy_size; - xaddr += JFS_SBI(sb)->nbperpage; - } - ip->i_blocks = LBLK2PBLK(sb, xlen); - } - - /* - * create entry for symbolic link in parent directory - */ - rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE); - if (rc == 0) { - ino = ip->i_ino; - rc = dtInsert(tid, dip, &dname, &ino, &btstack); - } - if (rc) { - if (xlen) - dbFree(ip, extent, xlen); - txAbort(tid, 0); - /* discard new inode */ - goto out3; } insert_inode_hash(ip); @@ -997,11 +1004,23 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, /* * commit update of parent directory and link object + * + * if extent allocation failed (ENOSPC), + * the parent inode is committed regardless to avoid + * backing out parent directory update (by dtInsert()) + * and subsequent dtDelete() which is harmless wrt + * integrity concern. + * the symlink inode will be freed by iput() at exit + * as it has a zero link count (by dtDelete()) and + * no permanant resources. */ iplist[0] = dip; - iplist[1] = ip; - rc = txCommit(tid, 2, &iplist[0], 0); + if (rc == 0) { + iplist[1] = ip; + rc = txCommit(tid, 2, &iplist[0], 0); + } else + rc = txCommit(tid, 1, &iplist[0], 0); out3: txEnd(tid); @@ -1204,7 +1223,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* Linelock header of dtree */ tlck = txLock(tid, old_ip, (struct metapage *) &JFS_IP(old_ip)->bxflag, - tlckDTREE | tlckBTROOT | tlckRELINK); + tlckDTREE | tlckBTROOT); dtlck = (struct dt_lock *) & tlck->lock; ASSERT(dtlck->index == 0); lv = & dtlck->lv[0]; diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index 6e028d912..280161a92 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -23,17 +23,12 @@ static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s = JFS_IP(dentry->d_inode)->i_inline; - return vfs_follow_link(nd, s); -} - -static int jfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - char *s = JFS_IP(dentry->d_inode)->i_inline; - return vfs_readlink(dentry, buffer, buflen, s); + nd_set_link(nd, s); + return 0; } struct inode_operations jfs_symlink_inode_operations = { - .readlink = jfs_readlink, + .readlink = generic_readlink, .follow_link = jfs_follow_link, .setxattr = jfs_setxattr, .getxattr = jfs_getxattr, diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index c786348cd..ad7498117 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -688,26 +688,17 @@ static int can_set_system_xattr(struct inode *inode, const char *name, } inode->i_mode = mode; mark_inode_dirty(inode); + if (rc == 0) + value = NULL; } /* * We're changing the ACL. Get rid of the cached one */ acl =JFS_IP(inode)->i_acl; - if (acl != JFS_ACL_NOT_CACHED) + if (acl && (acl != JFS_ACL_NOT_CACHED)) posix_acl_release(acl); JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; - - return 0; } else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) { - acl = posix_acl_from_xattr(value, value_len); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - printk(KERN_ERR "posix_acl_from_xattr returned %d\n", - rc); - return rc; - } - posix_acl_release(acl); - /* * We're changing the default ACL. Get rid of the cached one */ @@ -715,11 +706,13 @@ static int can_set_system_xattr(struct inode *inode, const char *name, if (acl && (acl != JFS_ACL_NOT_CACHED)) posix_acl_release(acl); JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED; - - return 0; - } -#endif /* CONFIG_JFS_POSIX_ACL */ + } else + /* Invalid xattr name */ + return -EINVAL; + return 0; +#else /* CONFIG_JFS_POSIX_ACL */ return -EOPNOTSUPP; +#endif /* CONFIG_JFS_POSIX_ACL */ } static int can_set_xattr(struct inode *inode, const char *name, diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 59c6c49fe..f16c78417 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -70,6 +70,7 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) * nlmclnt_lock for an explanation. */ sleep_on_timeout(&block.b_wait, 30*HZ); + #warning race for (head = &nlm_blocked; *head; head = &(*head)->b_next) { if (*head == &block) { diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 11dab7f1a..4b52a2ee4 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -343,8 +343,9 @@ static struct address_space_operations minix_aops = { }; static struct inode_operations minix_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .getattr = minix_getattr, }; diff --git a/fs/namei.c b/fs/namei.c index 9828b94fe..c2d43bbdf 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -163,6 +163,9 @@ int vfs_permission(struct inode * inode, int mask) { umode_t mode = inode->i_mode; + if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN|VX_WATCH)) + return -EACCES; + if (mask & MAY_WRITE) { /* * Nobody gets write access to a read-only fs. @@ -208,6 +211,15 @@ int vfs_permission(struct inode * inode, int mask) return -EACCES; } +static inline int xid_permission(struct inode *inode) +{ + if (inode->i_xid == 0) + return 0; + if (vx_check(inode->i_xid, VX_ADMIN|VX_WATCH|VX_IDENT)) + return 0; + return -EACCES; +} + int permission(struct inode * inode,int mask, struct nameidata *nd) { int retval; @@ -216,6 +228,8 @@ int permission(struct inode * inode,int mask, struct nameidata *nd) /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; + if ((retval = xid_permission(inode))) + return retval; if (inode->i_op && inode->i_op->permission) retval = inode->i_op->permission(inode, submask, nd); else @@ -395,6 +409,21 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s return result; } +inline void nd_set_link(struct nameidata *nd, char *path) +{ + nd->saved_names[current->link_count] = path; +} + +inline char *nd_get_link(struct nameidata *nd) +{ + return nd->saved_names[current->link_count]; +} + +EXPORT_SYMBOL(nd_set_link); +EXPORT_SYMBOL(nd_get_link); + +static inline int __vfs_follow_link(struct nameidata *, const char *); + /* * This limits recursive symlink follows to 8, while * limiting consecutive symlinks to 40. @@ -405,7 +434,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) { int err = -ELOOP; - if (current->link_count >= 5) + if (current->link_count >= MAX_NESTED_LINKS) goto loop; if (current->total_link_count >= 40) goto loop; @@ -416,7 +445,15 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) current->link_count++; current->total_link_count++; touch_atime(nd->mnt, dentry); + nd_set_link(nd, NULL); err = dentry->d_inode->i_op->follow_link(dentry, nd); + if (!err) { + char *s = nd_get_link(nd); + if (s) + err = __vfs_follow_link(nd, s); + if (dentry->d_inode->i_op->put_link) + dentry->d_inode->i_op->put_link(dentry, nd); + } current->link_count--; return err; loop: @@ -578,9 +615,11 @@ int fastcall link_path_walk(const char * name, struct nameidata *nd) { struct path next; struct inode *inode; - int err; + int err, atomic; unsigned int lookup_flags = nd->flags; - + + atomic = (lookup_flags & LOOKUP_ATOMIC); + while (*name=='/') name++; if (!*name) @@ -648,6 +687,9 @@ int fastcall link_path_walk(const char * name, struct nameidata *nd) if (err < 0) break; } + err = -EWOULDBLOCKIO; + if (atomic) + break; nd->flags |= LOOKUP_CONTINUE; /* This does the actual lookups.. */ err = do_lookup(nd, &this, &next); @@ -712,6 +754,9 @@ last_component: if (err < 0) break; } + err = -EWOULDBLOCKIO; + if (atomic) + break; err = do_lookup(nd, &this, &next); if (err) break; @@ -1031,15 +1076,18 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) 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) + if (!victim->d_inode) return -ENOENT; + if (victim->d_parent->d_inode != dir) + BUG(); + error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); if (error) return error; if (IS_APPEND(dir)) return -EPERM; if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| - IS_IMMUTABLE(victim->d_inode)) + IS_IXORUNLINK(victim->d_inode)) return -EPERM; if (isdir) { if (!S_ISDIR(victim->d_inode->i_mode)) @@ -1091,6 +1139,8 @@ static inline int lookup_flags(unsigned int f) if (f & O_DIRECTORY) retval |= LOOKUP_DIRECTORY; + if (f & O_ATOMICLOOKUP) + retval |= LOOKUP_ATOMIC; return retval; } @@ -1380,7 +1430,15 @@ do_link: if (error) goto exit_dput; touch_atime(nd->mnt, dentry); + nd_set_link(nd, NULL); error = dentry->d_inode->i_op->follow_link(dentry, nd); + if (!error) { + char *s = nd_get_link(nd); + if (s) + error = __vfs_follow_link(nd, s); + if (dentry->d_inode->i_op->put_link) + dentry->d_inode->i_op->put_link(dentry, nd); + } dput(dentry); if (error) return error; @@ -1833,7 +1891,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de /* * A link to an append-only or immutable file cannot be created. */ - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) return -EPERM; if (!dir->i_op || !dir->i_op->link) return -EPERM; @@ -2161,6 +2219,23 @@ out: return len; } +/* + * A helper for ->readlink(). This should be used *ONLY* for symlinks that + * have ->follow_link() touching nd only in nd_set_link(). Using (or not + * using) it for any given inode is up to filesystem. + */ +int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) +{ + struct nameidata nd; + int res = dentry->d_inode->i_op->follow_link(dentry, &nd); + if (!res) { + res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); + if (dentry->d_inode->i_op->put_link) + dentry->d_inode->i_op->put_link(dentry, &nd); + } + return res; +} + static inline int __vfs_follow_link(struct nameidata *nd, const char *link) { @@ -2237,6 +2312,30 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) return res; } +int page_follow_link_light(struct dentry *dentry, struct nameidata *nd) +{ + struct page *page; + char *s = page_getlink(dentry, &page); + if (!IS_ERR(s)) { + nd_set_link(nd, s); + s = NULL; + } + return PTR_ERR(s); +} + +void page_put_link(struct dentry *dentry, struct nameidata *nd) +{ + if (!IS_ERR(nd_get_link(nd))) { + struct page *page; + page = find_get_page(dentry->d_inode->i_mapping, 0); + if (!page) + BUG(); + kunmap(page); + page_cache_release(page); + page_cache_release(page); + } +} + int page_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page = NULL; @@ -2291,8 +2390,9 @@ fail: } struct inode_operations page_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, }; EXPORT_SYMBOL(__user_walk); @@ -2305,6 +2405,8 @@ EXPORT_SYMBOL(lookup_create); EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link); +EXPORT_SYMBOL(page_follow_link_light); +EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); @@ -2324,3 +2426,4 @@ EXPORT_SYMBOL(vfs_rename); EXPORT_SYMBOL(vfs_rmdir); EXPORT_SYMBOL(vfs_symlink); EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL(generic_readlink); diff --git a/fs/namespace.c b/fs/namespace.c index 2adae4289..4b66831ec 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -234,6 +234,9 @@ static int show_vfsmnt(struct seq_file *m, void *v) }; struct proc_fs_info *fs_infop; + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return 0; + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_putc(m, ' '); seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); @@ -333,18 +336,10 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); -void umount_tree(struct vfsmount *mnt) +static inline void __umount_tree(struct vfsmount *mnt, struct list_head *kill) { - struct vfsmount *p; - LIST_HEAD(kill); - - for (p = mnt; p; p = next_mnt(p, mnt)) { - list_del(&p->mnt_list); - list_add(&p->mnt_list, &kill); - } - - while (!list_empty(&kill)) { - mnt = list_entry(kill.next, struct vfsmount, mnt_list); + while (!list_empty(kill)) { + mnt = list_entry(kill->next, struct vfsmount, mnt_list); list_del_init(&mnt->mnt_list); if (mnt->mnt_parent == mnt) { spin_unlock(&vfsmount_lock); @@ -359,6 +354,32 @@ void umount_tree(struct vfsmount *mnt) } } +void umount_tree(struct vfsmount *mnt) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + } + __umount_tree(mnt, &kill); +} + +void umount_unused(struct vfsmount *mnt, struct fs_struct *fs) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + if (p == fs->rootmnt || p == fs->pwdmnt) + continue; + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + } + __umount_tree(mnt, &kill); +} + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block * sb = mnt->mnt_sb; @@ -456,7 +477,7 @@ asmlinkage long sys_umount(char __user * name, int flags) goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) goto dput_and_out; retval = do_umount(nd.mnt, flags); @@ -483,6 +504,8 @@ static int mount_is_safe(struct nameidata *nd) { if (capable(CAP_SYS_ADMIN)) return 0; + if (vx_ccaps(VXC_SECURE_MOUNT)) + return 0; return -EPERM; #ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) @@ -732,7 +755,7 @@ static int do_add_mount(struct nameidata *nd, char *type, int flags, return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); @@ -843,6 +866,9 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, mnt_flags |= MNT_NOEXEC; flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); + if (vx_ccaps(VXC_SECURE_MOUNT)) + mnt_flags |= MNT_NODEV; + /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); if (retval) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 77f051eef..b8018d5ae 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -466,7 +466,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, * cache. */ ssize_t -nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) +nfs_file_direct_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos) { ssize_t retval = -EINVAL; loff_t *ppos = &iocb->ki_pos; @@ -475,7 +475,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; struct iovec iov = { - .iov_base = (char *)buf, + .iov_base = buf, .iov_len = count, }; @@ -546,7 +546,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; struct iovec iov = { - .iov_base = (char __user *)buf, + .iov_base = buf, .iov_len = count, }; diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 864615916..a561819b6 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -306,7 +306,7 @@ static int __init root_nfs_name(char *name) /* Override them by options set on kernel command-line */ root_nfs_parse(name, buf); - cp = system_utsname.nodename; + cp = vx_new_uts(nodename); if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); return -1; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a01a2fa0a..483e8311b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -314,7 +314,7 @@ do_it: if (err >= 0) { err = 0; if (wbc->for_reclaim) - nfs_flush_inode(inode, 0, 0, FLUSH_STABLE); + err = WRITEPAGE_ACTIVATE; } } else { err = nfs_writepage_sync(NULL, inode, page, 0, @@ -327,7 +327,8 @@ do_it: } unlock_kernel(); out: - unlock_page(page); + if (err != WRITEPAGE_ACTIVATE) + unlock_page(page); if (inode_referenced) iput(inode); return err; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index f5df8304f..1e3af06b7 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -847,18 +847,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int elen; /* estimated entry length in words */ int num_entry_words = 0; /* actual number of words */ - if (cd->offset) { - u64 offset64 = offset; - - if (unlikely(cd->offset1)) { - /* we ended up with offset on a page boundary */ - *cd->offset = htonl(offset64 >> 32); - *cd->offset1 = htonl(offset64 & 0xffffffff); - cd->offset1 = NULL; - } else { - xdr_encode_hyper(cd->offset, (u64) offset); - } - } + if (cd->offset) + xdr_encode_hyper(cd->offset, (u64) offset); /* dprintk("encode_entry(%.*s @%ld%s)\n", @@ -939,32 +929,17 @@ encode_entry(struct readdir_cd *ccd, const char *name, /* update offset */ cd->offset = cd->buffer + (cd->offset - tmp); } else { - unsigned int offset_r = (cd->offset - tmp) << 2; - - /* update pointer to offset location. - * This is a 64bit quantity, so we need to - * deal with 3 cases: - * - entirely in first page - * - entirely in second page - * - 4 bytes in each page - */ - if (offset_r + 8 <= len1) { - cd->offset = p + (cd->offset - tmp); - } else if (offset_r >= len1) { - cd->offset -= len1 >> 2; - } else { - /* sitting on the fence */ - BUG_ON(offset_r != len1 - 4); - cd->offset = p + (cd->offset - tmp); - cd->offset1 = tmp; - } - len2 = (num_entry_words << 2) - len1; /* move from temp page to current and next pages */ memmove(p, tmp, len1); memmove(tmp, (caddr_t)tmp+len1, len2); + /* update offset */ + if (((cd->offset - tmp) << 2) < len1) + cd->offset = p + (cd->offset - tmp); + else + cd->offset -= len1 >> 2; p = tmp + (len2 >> 2); } } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2fc81bcbb..bb0c72fc7 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -538,8 +538,9 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create case NF4SOCK: case NF4FIFO: case NF4DIR: - default: break; + default: + goto xdr_error; } READ_BUF(4); @@ -1288,49 +1289,6 @@ static u32 nfs4_ftypes[16] = { NF4SOCK, NF4BAD, NF4LNK, NF4BAD, }; -static inline int -xdr_padding(int l) -{ - return 3 - ((l - 1) & 3); /* smallest i>=0 such that (l+i)%4 = 0 */ -} - -static int -nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id, - u32 **p, int *buflen) -{ - int status; - u32 len; - - if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4) - return nfserr_resource; - if (group) - status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); - else - status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); - if (status < 0) - return nfserrno(status); - len = (unsigned)status; - *(*p)++ = htonl(len); - memset((u8 *)*p + len, 0, xdr_padding(len)); - *p += XDR_QUADLEN(len); - *buflen -= (XDR_QUADLEN(len) << 2) + 4; - BUG_ON(*buflen < 0); - return 0; -} - -static inline int -nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen) -{ - return nfsd4_encode_name(rqstp, uid, 0, p, buflen); -} - -static inline int -nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen) -{ - return nfsd4_encode_name(rqstp, gid, 1, p, buflen); -} - - /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -1346,6 +1304,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, u32 bmval0 = bmval[0]; u32 bmval1 = bmval[1]; struct kstat stat; + char owner[IDMAP_NAMESZ]; + u32 ownerlen = 0; + char group[IDMAP_NAMESZ]; + u32 grouplen = 0; struct svc_fh tempfh; struct kstatfs statfs; int buflen = *countp << 2; @@ -1376,6 +1338,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out; fhp = &tempfh; } + if (bmval1 & FATTR4_WORD1_OWNER) { + int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner); + if (temp < 0) { + status = temp; + goto out_nfserr; + } + ownerlen = (unsigned) temp; + } + if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { + int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group); + if (temp < 0) { + status = temp; + goto out_nfserr; + } + grouplen = (unsigned) temp; + } + if ((buflen -= 16) < 0) goto out_resource; @@ -1557,18 +1536,18 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, WRITE32(stat.nlink); } if (bmval1 & FATTR4_WORD1_OWNER) { - status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen); - if (status == nfserr_resource) + buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4; + if (buflen < 0) goto out_resource; - if (status) - goto out; + WRITE32(ownerlen); + WRITEMEM(owner, ownerlen); } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen); - if (status == nfserr_resource) + buflen -= (XDR_QUADLEN(grouplen) << 2) + 4; + if (buflen < 0) goto out_resource; - if (status) - goto out; + WRITE32(grouplen); + WRITEMEM(group, grouplen); } if (bmval1 & FATTR4_WORD1_RAWDEV) { if ((buflen -= 8) < 0) diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 8e8c2342b..aaa367feb 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -56,7 +56,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry) /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); - err = permission(parent->d_inode, MAY_EXEC, NULL); + err = permission(parent->d_inode, S_IXOTH, NULL); if (err < 0) { dput(parent); break; diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 57e8c7ec7..097555ba1 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -1,4 +1,4 @@ -ToDo/Notes: +ToDo: - Find and fix bugs. - Either invalidate quotas or update the quota charges on NTFS 3.x volumes with quota tracking enabled ($Quota). @@ -11,10 +11,8 @@ ToDo/Notes: pages as nothing can dirty a page other than ourselves. Should this change, we will really need to roll our own ->set_page_dirty(). - Implement sops->dirty_inode() to implement {a,m,c}time updates and - such things. This should probably just flag the ntfs inode such that - sops->write_inode(), i.e. ntfs_write_inode(), will copy the times - when it is invoked rather than having to update the mft record - every time. + such things. + - Implement sops->write_inode(). - In between ntfs_prepare/commit_write, need exclusion between simultaneous file extensions. Need perhaps an NInoResizeUnderway() flag which we can set in ntfs_prepare_write() and clear again in @@ -26,71 +24,6 @@ ToDo/Notes: OTOH, perhaps i_sem, which is held accross generic_file_write is sufficient for synchronisation here. We then just need to make sure ntfs_readpage/writepage/truncate interoperate properly with us. - - Implement mft.c::sync_mft_mirror_umount(). We currently will just - leave the volume dirty on umount if the final iput(vol->mft_ino) - causes a write of any mirrored mft records due to the mft mirror - inode having been discarded already. Whether this can actually ever - happen is unclear however so it is worth waiting until someone hits - the problem. - - Enable the code for setting the NT4 compatibility flag when we start - making NTFS 1.2 specific modifications. - -2.1.14 - Fix an NFSd caused deadlock reported by several users. - - - Modify fs/ntfs/ntfs_readdir() to copy the index root attribute value - to a buffer so that we can put the search context and unmap the mft - record before calling the filldir() callback. We need to do this - because of NFSd which calls ->lookup() from its filldir callback() - and this causes NTFS to deadlock as ntfs_lookup() maps the mft record - of the directory and since ntfs_readdir() has got it mapped already - ntfs_lookup() deadlocks. - -2.1.13 - Enable overwriting of resident files and housekeeping of system files. - - - Implement writing of mft records (fs/ntfs/mft.[hc]), which includes - keeping the mft mirror in sync with the mft when mirrored mft records - are written. The functions are write_mft_record{,_nolock}(). The - implementation is quite rudimentary for now with lots of things not - implemented yet but I am not sure any of them can actually occur so - I will wait for people to hit each one and only then implement it. - - Commit open system inodes at umount time. This should make it - virtually impossible for sync_mft_mirror_umount() to ever be needed. - - Implement ->write_inode (fs/ntfs/inode.c::ntfs_write_inode()) for the - ntfs super operations. This gives us inode writing via the VFS inode - dirty code paths. Note: Access time updates are not implemented yet. - - Implement fs/ntfs/mft.[hc]::{,__}mark_mft_record_dirty() and make - fs/ntfs/aops.c::ntfs_writepage() and ntfs_commit_write() use it, thus - finally enabling resident file overwrite! (-8 This also includes a - placeholder for ->writepage (ntfs_mft_writepage()), which for now - just redirties the page and returns. Also, at umount time, we for - now throw away all mft data page cache pages after the last call to - ntfs_commit_inode() in the hope that all inodes will have been - written out by then and hence no dirty (meta)data will be lost. We - also check for this case and emit an error message telling the user - to run chkdsk. - - Use set_page_writeback() and end_page_writeback() in the resident - attribute code path of fs/ntfs/aops.c::ntfs_writepage() otherwise - the radix-tree tag PAGECACHE_TAG_DIRTY remains set even though the - page is clean. - - Implement ntfs_mft_writepage() so it now checks if any of the mft - records in the page are dirty and if so redirties the page and - returns. Otherwise it just returns (after doing set_page_writeback(), - unlock_page(), end_page_writeback() or the radix-tree tag - PAGECACHE_TAG_DIRTY remains set even though the page is clean), thus - alowing the VM to do with the page as it pleases. Also, at umount - time, now only throw away dirty mft (meta)data pages if dirty inodes - are present and ask the user to email us if they see this happening. - - Add functions ntfs_{clear,set}_volume_flags(), to modify the volume - information flags (fs/ntfs/super.c). - - Mark the volume dirty when (re)mounting read-write and mark it clean - when unmounting or remounting read-only. If any volume errors are - found, the volume is left marked dirty to force chkdsk to run. - - Add code to set the NT4 compatibility flag when (re)mounting - read-write for newer NTFS versions but leave it commented out for now - since we do not make any modifications that are NTFS 1.2 specific yet - and since setting this flag breaks Captive-NTFS which is not nice. - This code must be enabled once we start writing NTFS 1.2 specific - changes otherwise Windows NTFS driver might crash / cause corruption. 2.1.12 - Fix the second fix to the decompression engine and some cleanups. diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 3665464f4..715dc2c85 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ mst.o namei.o super.o sysctl.o unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.14\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.12\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 08aa85b44..f7f561a1a 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -478,8 +478,8 @@ static int ntfs_write_block(struct writeback_control *wbc, struct page *page) ni = NTFS_I(vi); vol = ni->vol; - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " - "0x%lx.", vi->i_ino, ni->type, page->index); + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " + "0x%lx.\n", vi->i_ino, ni->type, page->index); BUG_ON(!NInoNonResident(ni)); BUG_ON(NInoMstProtected(ni)); @@ -778,8 +778,9 @@ lock_retry_remap: * * For resident attributes, OTOH, ntfs_writepage() writes the @page by copying * the data to the mft record (which at this stage is most likely in memory). - * The mft record is then marked dirty and written out asynchronously via the - * vfs inode dirty code path. + * Thus, in this case, I/O is synchronous, as even if the mft record is not + * cached at this point in time, we need to wait for it to be read in before we + * can do the copy. * * Note the caller clears the page dirty flag before calling ntfs_writepage(). * @@ -874,6 +875,16 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) BUG_ON(page_has_buffers(page)); BUG_ON(!PageUptodate(page)); + // TODO: Consider using PageWriteback() + unlock_page() in 2.5 once the + // "VM fiddling has ended". Note, don't forget to replace all the + // unlock_page() calls further below with end_page_writeback() ones. + // FIXME: Make sure it is ok to SetPageError() on unlocked page under + // writeback before doing the change! +#if 0 + set_page_writeback(page); + unlock_page(page); +#endif + if (!NInoAttr(ni)) base_ni = ni; else @@ -923,14 +934,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) if (unlikely(bytes > PAGE_CACHE_SIZE)) bytes = PAGE_CACHE_SIZE; - /* - * Keep the VM happy. This must be done otherwise the radix-tree tag - * PAGECACHE_TAG_DIRTY remains set even though the page is clean. - */ - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - unlock_page(page); - /* * Here, we don't need to zero the out of bounds area everytime because * the below memcpy() already takes care of the mmap-at-end-of-file @@ -945,10 +948,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) * expose data to userspace/disk which should never have been exposed. * * FIXME: Ensure that i_size increases do the zeroing/overwriting and - * if we cannot guarantee that, then enable the zeroing below. If the - * zeroing below is enabled, we MUST move the unlock_page() from above - * to after the kunmap_atomic(), i.e. just before the - * end_page_writeback(). + * if we cannot guarantee that, then enable the zeroing below. */ kaddr = kmap_atomic(page, KM_USER0); @@ -966,10 +966,11 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) #endif kunmap_atomic(kaddr, KM_USER0); - end_page_writeback(page); + unlock_page(page); - /* Mark the mft record dirty, so it gets written back. */ - mark_mft_record_dirty(ctx->ntfs_ino); + // TODO: Mark mft record dirty so it gets written back. + ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. " + "Wrote to memory only..."); put_attr_search_ctx(ctx); unmap_mft_record(base_ni); @@ -1021,7 +1022,7 @@ static int ntfs_prepare_nonresident_write(struct page *page, ni = NTFS_I(vi); vol = ni->vol; - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, page->index, from, to); @@ -1378,7 +1379,7 @@ static int ntfs_prepare_write(struct file *file, struct page *page, struct inode *vi = page->mapping->host; ntfs_inode *ni = NTFS_I(vi); - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, page->index, from, to); @@ -1486,7 +1487,7 @@ static int ntfs_commit_nonresident_write(struct page *page, vi = page->mapping->host; - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " "0x%lx, from = %u, to = %u.", vi->i_ino, NTFS_I(vi)->type, page->index, from, to); @@ -1582,7 +1583,7 @@ static int ntfs_commit_write(struct file *file, struct page *page, vi = page->mapping->host; ni = NTFS_I(vi); - ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " + ntfs_debug("Entering for inode %li, attribute type 0x%x, page index " "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, page->index, from, to); @@ -1733,8 +1734,9 @@ static int ntfs_commit_write(struct file *file, struct page *page, } kunmap_atomic(kaddr, KM_USER0); - /* Mark the mft record dirty, so it gets written back. */ - mark_mft_record_dirty(ctx->ntfs_ino); + // TODO: Mark mft record dirty so it gets written back. + ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. " + "Wrote to memory only..."); put_attr_search_ctx(ctx); unmap_mft_record(base_ni); diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 6c7fb2a2b..2231c210f 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -624,7 +624,7 @@ run_list_element *ntfs_merge_run_lists(run_list_element *drl, if (drl[ds].vcn == marker_vcn) { ntfs_debug("Old marker = 0x%llx, replacing " - "with LCN_ENOENT.", + "with LCN_ENOENT.\n", (unsigned long long) drl[ds].lcn); drl[ds].lcn = (LCN)LCN_ENOENT; @@ -1565,7 +1565,7 @@ do_next_attr: goto do_next_attr_loop; } ntfs_error(base_ni->vol->sb, "Inode contains corrupt attribute list " - "attribute."); + "attribute.\n"); if (ni != base_ni) { unmap_extent_mft_record(ni); ctx->ntfs_ino = base_ni; diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index f9aca53c7..5836232f2 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -433,7 +433,7 @@ do_next_tag: goto do_next_tag; return_overflow: - ntfs_error(NULL, "Failed. Returning -EOVERFLOW."); + ntfs_error(NULL, "Failed. Returning -EOVERFLOW.\n"); goto return_error; } @@ -851,7 +851,7 @@ lock_retry_remap: if (err) { ntfs_error(vol->sb, "ntfs_decompress() failed in inode " "0x%lx with error code %i. Skipping " - "this compression block.", + "this compression block.\n", ni->mft_no, -err); /* Release the unfinished pages. */ for (; prev_cur_page < cur_page; prev_cur_page++) { diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 153100bfc..470a1e9c0 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -1067,7 +1067,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ntfs_inode *ndir = NTFS_I(vdir); ntfs_volume *vol = NTFS_SB(sb); MFT_RECORD *m; - INDEX_ROOT *ir = NULL; + INDEX_ROOT *ir; INDEX_ENTRY *ie; INDEX_ALLOCATION *ia; u8 *name = NULL; @@ -1139,29 +1139,9 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) "inode 0x%lx.", vdir->i_ino); goto err_out; } - /* - * Copy the index root attribute value to a buffer so that we can put - * the search context and unmap the mft record before calling the - * filldir() callback. We need to do this because of NFSd which calls - * ->lookup() from its filldir callback() and this causes NTFS to - * deadlock as ntfs_lookup() maps the mft record of the directory and - * we have got it mapped here already. The only solution is for us to - * unmap the mft record here so that a call to ntfs_lookup() is able to - * map the mft record without deadlocking. - */ - rc = le32_to_cpu(ctx->attr->data.resident.value_length); - ir = (INDEX_ROOT*)kmalloc(rc, GFP_NOFS); - if (unlikely(!ir)) { - err = -ENOMEM; - goto err_out; - } - /* Copy the index root value (it has been verified in read_inode). */ - memcpy(ir, (u8*)ctx->attr + - le16_to_cpu(ctx->attr->data.resident.value_offset), rc); - put_attr_search_ctx(ctx); - unmap_mft_record(ndir); - ctx = NULL; - m = NULL; + /* Get to the index root value (it's been verified in read_inode). */ + ir = (INDEX_ROOT*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->data.resident.value_offset)); index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); /* The first index entry. */ ie = (INDEX_ENTRY*)((u8*)&ir->index + @@ -1174,7 +1154,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { ntfs_debug("In index root, offset 0x%x.", (u8*)ie - (u8*)ir); /* Bounds checks. */ - if (unlikely((u8*)ie < (u8*)ir || (u8*)ie + + if (unlikely((u8*)ie < (u8*)ctx->mrec || (u8*)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || (u8*)ie + le16_to_cpu(ie->key_length) > index_end)) @@ -1189,13 +1169,20 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) rc = ntfs_filldir(vol, &fpos, ndir, INDEX_TYPE_ROOT, ir, ie, name, dirent, filldir); if (rc) { - kfree(ir); + put_attr_search_ctx(ctx); + unmap_mft_record(ndir); goto abort; } } - /* We are done with the index root and can free the buffer. */ - kfree(ir); - ir = NULL; + /* + * We are done with the index root and the mft record for that matter. + * We need to release it, otherwise we deadlock on ntfs_attr_iget() + * and/or ntfs_read_page(). + */ + put_attr_search_ctx(ctx); + unmap_mft_record(ndir); + m = NULL; + ctx = NULL; /* If there is no index allocation attribute we are finished. */ if (!NInoIndexAllocPresent(ndir)) goto EOD; @@ -1392,8 +1379,6 @@ err_out: ntfs_unmap_page(bmp_page); if (ia_page) ntfs_unmap_page(ia_page); - if (ir) - kfree(ir); if (name) kfree(name); if (ctx) diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 1abe1b399..0bb39d87d 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1960,134 +1960,49 @@ trunc_err: return err; } -/** - * ntfs_write_inode - write out a dirty inode - * @vi: inode to write out - * @sync: if true, write out synchronously - * - * Write out a dirty inode to disk including any extent inodes if present. - * - * If @sync is true, commit the inode to disk and wait for io completion. This - * is done using write_mft_record(). - * - * If @sync is false, just schedule the write to happen but do not wait for i/o - * completion. In 2.6 kernels, scheduling usually happens just by virtue of - * marking the page (and in this case mft record) dirty but we do not implement - * this yet as write_mft_record() largely ignores the @sync parameter and - * always performs synchronous writes. - */ void ntfs_write_inode(struct inode *vi, int sync) { ntfs_inode *ni = NTFS_I(vi); -#if 0 - attr_search_context *ctx; -#endif - MFT_RECORD *m; - int err = 0; ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "", vi->i_ino); + /* * Dirty attribute inodes are written via their real inodes so just - * clean them here. TODO: Take care of access time updates. + * clean them here. */ if (NInoAttr(ni)) { NInoClearDirty(ni); return; } - /* Map, pin, and lock the mft record belonging to the inode. */ - m = map_mft_record(ni); - if (unlikely(IS_ERR(m))) { - err = PTR_ERR(m); - goto err_out; - } -#if 0 - /* Obtain the standard information attribute. */ - ctx = get_attr_search_ctx(ni, m); - if (unlikely(!ctx)) { - err = -ENOMEM; - goto unm_err_out; - } - if (unlikely(!lookup_attr(AT_STANDARD_INFORMATION, NULL, 0, - IGNORE_CASE, 0, NULL, 0, ctx))) { - put_attr_search_ctx(ctx); - err = -ENOENT; - goto unm_err_out; - } - // TODO: Update the access times in the standard information attribute - // which is now in ctx->attr. - // - Probably want to have use sops->dirty_inode() to set a flag that - // we need to update the times here rather than having to blindly do - // it every time. Or even don't do it here at all and do it in - // sops->dirty_inode() instead. Problem with this would be that - // sops->dirty_inode() must be atomic under certain circumstances - // and mapping mft records and such like is not atomic. - // - For atime updates also need to check whether they are enabled in - // the superblock flags. - ntfs_warning(vi->i_sb, "Access time updates not implement yet."); - /* - * We just modified the mft record containing the standard information - * attribute. So need to mark the mft record dirty, too, but we do it - * manually so that mark_inode_dirty() is not called again. - * TODO: Only do this if there was a change in any of the times! - */ - if (!NInoTestSetDirty(ctx->ntfs_ino)) - __set_page_dirty_nobuffers(ctx->ntfs_ino->page); - put_attr_search_ctx(ctx); -#endif + /* Write this base mft record. */ - if (NInoDirty(ni)) - err = write_mft_record(ni, m, sync); + if (NInoDirty(ni)) { + ntfs_warning(vi->i_sb, "Cleaning dirty inode 0x%lx without " + "writing to disk as this is not yet " + "implemented.", vi->i_ino); + NInoClearDirty(ni); + } + /* Write all attached extent mft records. */ down(&ni->extent_lock); if (ni->nr_extents > 0) { - ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos; int i; + ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos; - ntfs_debug("Writing %i extent inodes.", ni->nr_extents); for (i = 0; i < ni->nr_extents; i++) { ntfs_inode *tni = extent_nis[i]; if (NInoDirty(tni)) { - MFT_RECORD *tm = map_mft_record(tni); - int ret; - - if (unlikely(IS_ERR(tm))) { - if (!err || err == -ENOMEM) - err = PTR_ERR(tm); - continue; - } - ret = write_mft_record(tni, tm, sync); - unmap_mft_record(tni); - if (unlikely(ret)) { - if (!err || err == -ENOMEM) - err = ret; - } + ntfs_warning(vi->i_sb, "Cleaning dirty extent " + "inode 0x%lx without writing " + "to disk as this is not yet " + "implemented.", tni->mft_no); + NInoClearDirty(tni); } } } up(&ni->extent_lock); - unmap_mft_record(ni); - if (unlikely(err)) - goto err_out; - ntfs_debug("Done."); - return; -#if 0 -unm_err_out: - unmap_mft_record(ni); -#endif -err_out: - if (err == -ENOMEM) { - ntfs_warning(vi->i_sb, "Not enough memory to write inode. " - "Marking the inode dirty again, so the VFS " - "retries later."); - mark_inode_dirty(vi); - } else { - ntfs_error(vi->i_sb, "Failed (error code %i): Marking inode " - "as bad. You should run chkdsk.", -err); - make_bad_inode(vi); - } - return; } #endif /* NTFS_RW */ diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 8875af935..92cdcb83a 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -102,13 +102,6 @@ int format_mft_record(ntfs_inode *ni, MFT_RECORD *mft_rec) */ extern int ntfs_readpage(struct file *, struct page *); -#ifdef NTFS_RW -/** - * ntfs_mft_writepage - forward declaration, function is further below - */ -static int ntfs_mft_writepage(struct page *page, struct writeback_control *wbc); -#endif /* NTFS_RW */ - /** * ntfs_mft_aops - address space operations for access to $MFT * @@ -119,10 +112,6 @@ struct address_space_operations ntfs_mft_aops = { .readpage = ntfs_readpage, /* Fill page with data. */ .sync_page = block_sync_page, /* Currently, just unplugs the disk request queue. */ -#ifdef NTFS_RW - .writepage = ntfs_mft_writepage, /* Write out the dirty mft - records in a page. */ -#endif /* NTFS_RW */ }; /** @@ -440,654 +429,3 @@ unm_err_out: ntfs_clear_extent_inode(ni); return m; } - -#ifdef NTFS_RW - -/** - * __mark_mft_record_dirty - set the mft record and the page containing it dirty - * @ni: ntfs inode describing the mapped mft record - * - * Internal function. Users should call mark_mft_record_dirty() instead. - * - * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni, - * as well as the page containing the mft record, dirty. Also, mark the base - * vfs inode dirty. This ensures that any changes to the mft record are - * written out to disk. - * - * NOTE: We only set I_DIRTY_SYNC and I_DIRTY_DATASYNC (and not I_DIRTY_PAGES) - * on the base vfs inode, because even though file data may have been modified, - * it is dirty in the inode meta data rather than the data page cache of the - * inode, and thus there are no data pages that need writing out. Therefore, a - * full mark_inode_dirty() is overkill. A mark_inode_dirty_sync(), on the - * other hand, is not sufficient, because I_DIRTY_DATASYNC needs to be set to - * ensure ->write_inode is called from generic_osync_inode() and this needs to - * happen or the file data would not necessarily hit the device synchronously, - * even though the vfs inode has the O_SYNC flag set. Also, I_DIRTY_DATASYNC - * simply "feels" better than just I_DIRTY_SYNC, since the file data has not - * actually hit the block device yet, which is not what I_DIRTY_SYNC on its own - * would suggest. - */ -void __mark_mft_record_dirty(ntfs_inode *ni) -{ - struct page *page = ni->page; - ntfs_inode *base_ni; - - ntfs_debug("Entering for inode 0x%lx.", ni->mft_no); - BUG_ON(!page); - BUG_ON(NInoAttr(ni)); - - /* - * Set the page containing the mft record dirty. This also marks the - * $MFT inode dirty (I_DIRTY_PAGES). - */ - __set_page_dirty_nobuffers(page); - - /* Determine the base vfs inode and mark it dirty, too. */ - down(&ni->extent_lock); - if (likely(ni->nr_extents >= 0)) - base_ni = ni; - else - base_ni = ni->ext.base_ntfs_ino; - up(&ni->extent_lock); - __mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC); -} - -static const char *ntfs_please_email = "Please email " - "linux-ntfs-dev@lists.sourceforge.net and say that you saw " - "this message. Thank you."; - -/** - * sync_mft_mirror_umount - synchronise an mft record to the mft mirror - * @ni: ntfs inode whose mft record to synchronize - * @m: mapped, mst protected (extent) mft record to synchronize - * - * Write the mapped, mst protected (extent) mft record @m described by the - * (regular or extent) ntfs inode @ni to the mft mirror ($MFTMirr) bypassing - * the page cache and the $MFTMirr inode itself. - * - * This function is only for use at umount time when the mft mirror inode has - * already been disposed off. We BUG() if we are called while the mft mirror - * inode is still attached to the volume. - * - * On success return 0. On error return -errno. - * - * NOTE: This function is not implemented yet as I am not convinced it can - * actually be triggered considering the sequence of commits we do in super.c:: - * ntfs_put_super(). But just in case we provide this place holder as the - * alternative would be either to BUG() or to get a NULL pointer dereference - * and Oops. - */ -static int sync_mft_mirror_umount(ntfs_inode *ni, MFT_RECORD *m) -{ - ntfs_volume *vol = ni->vol; - - BUG_ON(vol->mftmirr_ino); - ntfs_error(vol->sb, "Umount time mft mirror syncing is not " - "implemented yet. %s", ntfs_please_email); - return -EOPNOTSUPP; -} - -/** - * sync_mft_mirror - synchronize an mft record to the mft mirror - * @ni: ntfs inode whose mft record to synchronize - * @m: mapped, mst protected (extent) mft record to synchronize - * @sync: if true, wait for i/o completion - * - * Write the mapped, mst protected (extent) mft record @m described by the - * (regular or extent) ntfs inode @ni to the mft mirror ($MFTMirr). - * - * On success return 0. On error return -errno and set the volume errors flag - * in the ntfs_volume to which @ni belongs. - * - * NOTE: We always perform synchronous i/o and ignore the @sync parameter. - * - * TODO: If @sync is false, want to do truly asynchronous i/o, i.e. just - * schedule i/o via ->writepage or do it via kntfsd or whatever. - */ -static int sync_mft_mirror(ntfs_inode *ni, MFT_RECORD *m, int sync) -{ - ntfs_volume *vol = ni->vol; - struct page *page; - unsigned int blocksize = vol->sb->s_blocksize; - int max_bhs = vol->mft_record_size / blocksize; - struct buffer_head *bhs[max_bhs]; - struct buffer_head *bh, *head; - u8 *kmirr; - unsigned int block_start, block_end, m_start, m_end; - int i_bhs, nr_bhs, err = 0; - - ntfs_debug("Entering for inode 0x%lx.", ni->mft_no); - BUG_ON(!max_bhs); - if (unlikely(!vol->mftmirr_ino)) { - /* This could happen during umount... */ - err = sync_mft_mirror_umount(ni, m); - if (likely(!err)) - return err; - goto err_out; - } - /* Get the page containing the mirror copy of the mft record @m. */ - page = ntfs_map_page(vol->mftmirr_ino->i_mapping, ni->mft_no >> - (PAGE_CACHE_SHIFT - vol->mft_record_size_bits)); - if (unlikely(IS_ERR(page))) { - ntfs_error(vol->sb, "Failed to map mft mirror page."); - err = PTR_ERR(page); - goto err_out; - } - /* - * Exclusion against other writers. This should never be a problem - * since the page in which the mft record @m resides is also locked and - * hence any other writers would be held up there but it is better to - * make sure no one is writing from elsewhere. - */ - lock_page(page); - /* The address in the page of the mirror copy of the mft record @m. */ - kmirr = page_address(page) + ((ni->mft_no << vol->mft_record_size_bits) - & ~PAGE_CACHE_MASK); - /* Copy the mst protected mft record to the mirror. */ - memcpy(kmirr, m, vol->mft_record_size); - /* Make sure we have mapped buffers. */ - if (!page_has_buffers(page)) { -no_buffers_err_out: - ntfs_error(vol->sb, "Writing mft mirror records without " - "existing buffers is not implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - goto unlock_err_out; - } - bh = head = page_buffers(page); - if (!bh) - goto no_buffers_err_out; - nr_bhs = 0; - block_start = 0; - m_start = kmirr - (u8*)page_address(page); - m_end = m_start + vol->mft_record_size; - do { - block_end = block_start + blocksize; - /* - * If the buffer is outside the mft record, just skip it, - * clearing it if it is dirty to make sure it is not written - * out. It should never be marked dirty but better be safe. - */ - if ((block_end <= m_start) || (block_start >= m_end)) { - if (buffer_dirty(bh)) { - ntfs_warning(vol->sb, "Clearing dirty mft " - "record page buffer. %s", - ntfs_please_email); - clear_buffer_dirty(bh); - } - continue; - } - if (!buffer_mapped(bh)) { - ntfs_error(vol->sb, "Writing mft mirror records " - "without existing mapped buffers is " - "not implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - continue; - } - if (!buffer_uptodate(bh)) { - ntfs_error(vol->sb, "Writing mft mirror records " - "without existing uptodate buffers is " - "not implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - continue; - } - BUG_ON(!nr_bhs && (m_start != block_start)); - BUG_ON(nr_bhs >= max_bhs); - bhs[nr_bhs++] = bh; - BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end)); - } while (block_start = block_end, (bh = bh->b_this_page) != head); - if (likely(!err)) { - /* Lock buffers and start synchronous write i/o on them. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { - struct buffer_head *tbh = bhs[i_bhs]; - - if (unlikely(test_set_buffer_locked(tbh))) - BUG(); - BUG_ON(!buffer_uptodate(tbh)); - if (buffer_dirty(tbh)) - clear_buffer_dirty(tbh); - get_bh(tbh); - tbh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, tbh); - } - /* Wait on i/o completion of buffers. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { - struct buffer_head *tbh = bhs[i_bhs]; - - wait_on_buffer(tbh); - if (unlikely(!buffer_uptodate(tbh))) { - err = -EIO; - /* - * Set the buffer uptodate so the page & buffer - * states don't become out of sync. - */ - if (PageUptodate(page)) - set_buffer_uptodate(tbh); - } - } - } else /* if (unlikely(err)) */ { - /* Clean the buffers. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) - clear_buffer_dirty(bhs[i_bhs]); - } -unlock_err_out: - /* Current state: all buffers are clean, unlocked, and uptodate. */ - /* Remove the mst protection fixups again. */ - post_write_mst_fixup((NTFS_RECORD*)kmirr); - flush_dcache_page(page); - unlock_page(page); - ntfs_unmap_page(page); - if (unlikely(err)) { - /* I/O error during writing. This is really bad! */ - ntfs_error(vol->sb, "I/O error while writing mft mirror " - "record 0x%lx! You should unmount the volume " - "and run chkdsk or ntfsfix.", ni->mft_no); - goto err_out; - } - ntfs_debug("Done."); - return 0; -err_out: - ntfs_error(vol->sb, "Failed to synchronize $MFTMirr (error code %i). " - "Volume will be left marked dirty on umount. Run " - "ntfsfix on the partition after umounting to correct " - "this.", -err); - /* We don't want to clear the dirty bit on umount. */ - NVolSetErrors(vol); - return err; -} - -/** - * write_mft_record_nolock - write out a mapped (extent) mft record - * @ni: ntfs inode describing the mapped (extent) mft record - * @m: mapped (extent) mft record to write - * @sync: if true, wait for i/o completion - * - * Write the mapped (extent) mft record @m described by the (regular or extent) - * ntfs inode @ni to backing store. If the mft record @m has a counterpart in - * the mft mirror, that is also updated. - * - * On success, clean the mft record and return 0. On error, leave the mft - * record dirty and return -errno. The caller should call make_bad_inode() on - * the base inode to ensure no more access happens to this inode. We do not do - * it here as the caller may want to finish writing other extent mft records - * first to minimize on-disk metadata inconsistencies. - * - * NOTE: We always perform synchronous i/o and ignore the @sync parameter. - * However, if the mft record has a counterpart in the mft mirror and @sync is - * true, we write the mft record, wait for i/o completion, and only then write - * the mft mirror copy. This ensures that if the system crashes either the mft - * or the mft mirror will contain a self-consistent mft record @m. If @sync is - * false on the other hand, we start i/o on both and then wait for completion - * on them. This provides a speedup but no longer guarantees that you will end - * up with a self-consistent mft record in the case of a crash but if you asked - * for asynchronous writing you probably do not care about that anyway. - * - * TODO: If @sync is false, want to do truly asynchronous i/o, i.e. just - * schedule i/o via ->writepage or do it via kntfsd or whatever. - */ -int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) -{ - ntfs_volume *vol = ni->vol; - struct page *page = ni->page; - unsigned int blocksize = vol->sb->s_blocksize; - int max_bhs = vol->mft_record_size / blocksize; - struct buffer_head *bhs[max_bhs]; - struct buffer_head *bh, *head; - unsigned int block_start, block_end, m_start, m_end; - int i_bhs, nr_bhs, err = 0; - - ntfs_debug("Entering for inode 0x%lx.", ni->mft_no); - BUG_ON(NInoAttr(ni)); - BUG_ON(!max_bhs); - BUG_ON(!page); - BUG_ON(!PageLocked(page)); - /* - * If the ntfs_inode is clean no need to do anything. If it is dirty, - * mark it as clean now so that it can be redirtied later on if needed. - * There is no danger of races as as long as the caller is holding the - * locks for the mft record @m and the page it is in. - */ - if (!NInoTestClearDirty(ni)) - goto done; - /* Make sure we have mapped buffers. */ - if (!page_has_buffers(page)) { -no_buffers_err_out: - ntfs_error(vol->sb, "Writing mft records without existing " - "buffers is not implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - goto err_out; - } - bh = head = page_buffers(page); - if (!bh) - goto no_buffers_err_out; - nr_bhs = 0; - block_start = 0; - m_start = ni->page_ofs; - m_end = m_start + vol->mft_record_size; - do { - block_end = block_start + blocksize; - /* - * If the buffer is outside the mft record, just skip it, - * clearing it if it is dirty to make sure it is not written - * out. It should never be marked dirty but better be safe. - */ - if ((block_end <= m_start) || (block_start >= m_end)) { - if (buffer_dirty(bh)) { - ntfs_warning(vol->sb, "Clearing dirty mft " - "record page buffer. %s", - ntfs_please_email); - clear_buffer_dirty(bh); - } - continue; - } - if (!buffer_mapped(bh)) { - ntfs_error(vol->sb, "Writing mft records without " - "existing mapped buffers is not " - "implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - continue; - } - if (!buffer_uptodate(bh)) { - ntfs_error(vol->sb, "Writing mft records without " - "existing uptodate buffers is not " - "implemented yet. %s", - ntfs_please_email); - err = -EOPNOTSUPP; - continue; - } - BUG_ON(!nr_bhs && (m_start != block_start)); - BUG_ON(nr_bhs >= max_bhs); - bhs[nr_bhs++] = bh; - BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end)); - } while (block_start = block_end, (bh = bh->b_this_page) != head); - if (unlikely(err)) - goto cleanup_out; - /* Apply the mst protection fixups. */ - err = pre_write_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size); - if (err) { - ntfs_error(vol->sb, "Failed to apply mst fixups!"); - goto cleanup_out; - } - flush_dcache_mft_record_page(ni); - /* Lock buffers and start synchronous write i/o on them. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { - struct buffer_head *tbh = bhs[i_bhs]; - - if (unlikely(test_set_buffer_locked(tbh))) - BUG(); - BUG_ON(!buffer_uptodate(tbh)); - if (buffer_dirty(tbh)) - clear_buffer_dirty(tbh); - get_bh(tbh); - tbh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, tbh); - } - /* Synchronize the mft mirror now if not @sync. */ - if (!sync && ni->mft_no < vol->mftmirr_size) - sync_mft_mirror(ni, m, sync); - /* Wait on i/o completion of buffers. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { - struct buffer_head *tbh = bhs[i_bhs]; - - wait_on_buffer(tbh); - if (unlikely(!buffer_uptodate(tbh))) { - err = -EIO; - /* - * Set the buffer uptodate so the page & buffer states - * don't become out of sync. - */ - if (PageUptodate(page)) - set_buffer_uptodate(tbh); - } - } - /* If @sync, now synchronize the mft mirror. */ - if (sync && ni->mft_no < vol->mftmirr_size) - sync_mft_mirror(ni, m, sync); - /* Remove the mst protection fixups again. */ - post_write_mst_fixup((NTFS_RECORD*)m); - flush_dcache_mft_record_page(ni); - if (unlikely(err)) { - /* I/O error during writing. This is really bad! */ - ntfs_error(vol->sb, "I/O error while writing mft record " - "0x%lx! Marking base inode as bad. You " - "should unmount the volume and run chkdsk.", - ni->mft_no); - goto err_out; - } -done: - ntfs_debug("Done."); - return 0; -cleanup_out: - /* Clean the buffers. */ - for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) - clear_buffer_dirty(bhs[i_bhs]); -err_out: - /* - * Current state: all buffers are clean, unlocked, and uptodate. - * The caller should mark the base inode as bad so that no more i/o - * happens. ->clear_inode() will still be invoked so all extent inodes - * and other allocated memory will be freed. - */ - if (err == -ENOMEM) { - ntfs_error(vol->sb, "Not enough memory to write mft record. " - "Redirtying so the write is retried later."); - mark_mft_record_dirty(ni); - err = 0; - } - return err; -} - -/** - * ntfs_mft_writepage - check if a metadata page contains dirty mft records - * @page: metadata page possibly containing dirty mft records - * @wbc: writeback control structure - * - * This is called from the VM when it wants to have a dirty $MFT/$DATA metadata - * page cache page cleaned. The VM has already locked the page and marked it - * clean. Instead of writing the page as a conventional ->writepage function - * would do, we check if the page still contains any dirty mft records (it must - * have done at some point in the past since the page was marked dirty) and if - * none are found, i.e. all mft records are clean, we unlock the page and - * return. The VM is then free to do with the page as it pleases. If on the - * other hand we do find any dirty mft records in the page, we redirty the page - * before unlocking it and returning so the VM knows that the page is still - * busy and cannot be thrown out. - * - * Note, we do not actually write any dirty mft records here because they are - * dirty inodes and hence will be written by the VFS inode dirty code paths. - * There is no need to write them from the VM page dirty code paths, too and in - * fact once we implement journalling it would be a complete nightmare having - * two code paths leading to mft record writeout. - */ -static int ntfs_mft_writepage(struct page *page, struct writeback_control *wbc) -{ - struct inode *mft_vi = page->mapping->host; - struct super_block *sb = mft_vi->i_sb; - ntfs_volume *vol = NTFS_SB(sb); - u8 *maddr; - MFT_RECORD *m; - ntfs_inode **extent_nis; - unsigned long mft_no; - int nr, i, j; - BOOL is_dirty = FALSE; - - BUG_ON(mft_vi != vol->mft_ino); - /* The first mft record number in the page. */ - mft_no = page->index << (PAGE_CACHE_SHIFT - vol->mft_record_size_bits); - /* Number of mft records in the page. */ - nr = PAGE_CACHE_SIZE >> vol->mft_record_size_bits; - BUG_ON(!nr); - ntfs_debug("Entering for %i inodes starting at 0x%lx.", nr, mft_no); - /* Iterate over the mft records in the page looking for a dirty one. */ - maddr = (u8*)kmap(page); - for (i = 0; i < nr; ++i, ++mft_no, maddr += vol->mft_record_size) { - struct inode *vi; - ntfs_inode *ni, *eni; - ntfs_attr na; - - na.mft_no = mft_no; - na.name = NULL; - na.name_len = 0; - na.type = AT_UNUSED; - /* - * Check if the inode corresponding to this mft record is in - * the VFS inode cache and obtain a reference to it if it is. - */ - ntfs_debug("Looking for inode 0x%lx in icache.", mft_no); - /* - * For inode 0, i.e. $MFT itself, we cannot use ilookup5() from - * here or we deadlock because the inode is already locked by - * the kernel (fs/fs-writeback.c::__sync_single_inode()) and - * ilookup5() waits until the inode is unlocked before - * returning it and it never gets unlocked because - * ntfs_mft_writepage() never returns. )-: Fortunately, we - * have inode 0 pinned in icache for the duration of the mount - * so we can access it directly. - */ - if (!mft_no) { - /* Balance the below iput(). */ - vi = igrab(mft_vi); - BUG_ON(vi != mft_vi); - } else - vi = ilookup5(sb, mft_no, (test_t)ntfs_test_inode, &na); - if (vi) { - ntfs_debug("Inode 0x%lx is in icache.", mft_no); - /* The inode is in icache. Check if it is dirty. */ - ni = NTFS_I(vi); - if (!NInoDirty(ni)) { - /* The inode is not dirty, skip this record. */ - ntfs_debug("Inode 0x%lx is not dirty, " - "continuing search.", mft_no); - iput(vi); - continue; - } - ntfs_debug("Inode 0x%lx is dirty, aborting search.", - mft_no); - /* The inode is dirty, no need to search further. */ - iput(vi); - is_dirty = TRUE; - break; - } - ntfs_debug("Inode 0x%lx is not in icache.", mft_no); - /* The inode is not in icache. */ - /* Skip the record if it is not a mft record (type "FILE"). */ - if (!ntfs_is_mft_recordp(maddr)) { - ntfs_debug("Mft record 0x%lx is not a FILE record, " - "continuing search.", mft_no); - continue; - } - m = (MFT_RECORD*)maddr; - /* - * Skip the mft record if it is not in use. FIXME: What about - * deleted/deallocated (extent) inodes? (AIA) - */ - if (!(m->flags & MFT_RECORD_IN_USE)) { - ntfs_debug("Mft record 0x%lx is not in use, " - "continuing search.", mft_no); - continue; - } - /* Skip the mft record if it is a base inode. */ - if (!m->base_mft_record) { - ntfs_debug("Mft record 0x%lx is a base record, " - "continuing search.", mft_no); - continue; - } - /* - * This is an extent mft record. Check if the inode - * corresponding to its base mft record is in icache. - */ - na.mft_no = MREF_LE(m->base_mft_record); - ntfs_debug("Mft record 0x%lx is an extent record. Looking " - "for base inode 0x%lx in icache.", mft_no, - na.mft_no); - vi = ilookup5(sb, na.mft_no, (test_t)ntfs_test_inode, - &na); - if (!vi) { - /* - * The base inode is not in icache. Skip this extent - * mft record. - */ - ntfs_debug("Base inode 0x%lx is not in icache, " - "continuing search.", na.mft_no); - continue; - } - ntfs_debug("Base inode 0x%lx is in icache.", na.mft_no); - /* - * The base inode is in icache. Check if it has the extent - * inode corresponding to this extent mft record attached. - */ - ni = NTFS_I(vi); - down(&ni->extent_lock); - if (ni->nr_extents <= 0) { - /* - * The base inode has no attached extent inodes. Skip - * this extent mft record. - */ - up(&ni->extent_lock); - iput(vi); - continue; - } - /* Iterate over the attached extent inodes. */ - extent_nis = ni->ext.extent_ntfs_inos; - for (eni = NULL, j = 0; j < ni->nr_extents; ++j) { - if (mft_no == extent_nis[j]->mft_no) { - /* - * Found the extent inode corresponding to this - * extent mft record. - */ - eni = extent_nis[j]; - break; - } - } - /* - * If the extent inode was not attached to the base inode, skip - * this extent mft record. - */ - if (!eni) { - up(&ni->extent_lock); - iput(vi); - continue; - } - /* - * Found the extent inode corrsponding to this extent mft - * record. If it is dirty, no need to search further. - */ - if (NInoDirty(eni)) { - up(&ni->extent_lock); - iput(vi); - is_dirty = TRUE; - break; - } - /* The extent inode is not dirty, so do the next record. */ - up(&ni->extent_lock); - iput(vi); - } - kunmap(page); - /* If a dirty mft record was found, redirty the page. */ - if (is_dirty) { - ntfs_debug("Inode 0x%lx is dirty. Redirtying the page " - "starting at inode 0x%lx.", mft_no, - page->index << (PAGE_CACHE_SHIFT - - vol->mft_record_size_bits)); - redirty_page_for_writepage(wbc, page); - unlock_page(page); - } else { - /* - * Keep the VM happy. This must be done otherwise the - * radix-tree tag PAGECACHE_TAG_DIRTY remains set even though - * the page is clean. - */ - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - unlock_page(page); - end_page_writeback(page); - } - ntfs_debug("Done."); - return 0; -} - -#endif /* NTFS_RW */ diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h index 4fd9b5ec6..d23724a09 100644 --- a/fs/ntfs/mft.h +++ b/fs/ntfs/mft.h @@ -57,60 +57,6 @@ static inline void flush_dcache_mft_record_page(ntfs_inode *ni) flush_dcache_page(ni->page); } -extern void __mark_mft_record_dirty(ntfs_inode *ni); - -/** - * mark_mft_record_dirty - set the mft record and the page containing it dirty - * @ni: ntfs inode describing the mapped mft record - * - * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni, - * as well as the page containing the mft record, dirty. Also, mark the base - * vfs inode dirty. This ensures that any changes to the mft record are - * written out to disk. - * - * NOTE: Do not do anything if the mft record is already marked dirty. - */ -static inline void mark_mft_record_dirty(ntfs_inode *ni) -{ - if (!NInoTestSetDirty(ni)) - __mark_mft_record_dirty(ni); -} - -extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync); - -/** - * write_mft_record - write out a mapped (extent) mft record - * @ni: ntfs inode describing the mapped (extent) mft record - * @m: mapped (extent) mft record to write - * @sync: if true, wait for i/o completion - * - * This is just a wrapper for write_mft_record_nolock() (see mft.c), which - * locks the page for the duration of the write. This ensures that there are - * no race conditions between writing the mft record via the dirty inode code - * paths and via the page cache write back code paths or between writing - * neighbouring mft records residing in the same page. - * - * Locking the page also serializes us against ->readpage() if the page is not - * uptodate. - * - * On success, clean the mft record and return 0. On error, leave the mft - * record dirty and return -errno. The caller should call make_bad_inode() on - * the base inode to ensure no more access happens to this inode. We do not do - * it here as the caller may want to finish writing other extent mft records - * first to minimize on-disk metadata inconsistencies. - */ -static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync) -{ - struct page *page = ni->page; - int err; - - BUG_ON(!page); - lock_page(page); - err = write_mft_record_nolock(ni, m, sync); - unlock_page(page); - return err; -} - #endif /* NTFS_RW */ #endif /* _LINUX_NTFS_MFT_H */ diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 4c3a32b74..22939a515 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -291,101 +291,6 @@ needs_val: return FALSE; } -#ifdef NTFS_RW - -/** - * ntfs_write_volume_flags - write new flags to the volume information flags - * @vol: ntfs volume on which to modify the flags - * @flags: new flags value for the volume information flags - * - * Internal function. You probably want to use ntfs_{set,clear}_volume_flags() - * instead (see below). - * - * Replace the volume information flags on the volume @vol with the value - * supplied in @flags. Note, this overwrites the volume information flags, so - * make sure to combine the flags you want to modify with the old flags and use - * the result when calling ntfs_write_volume_flags(). - * - * Return 0 on success and -errno on error. - */ -static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags) -{ - ntfs_inode *ni = NTFS_I(vol->vol_ino); - MFT_RECORD *m; - VOLUME_INFORMATION *vi; - attr_search_context *ctx; - int err; - - ntfs_debug("Entering, old flags = 0x%x, new flags = 0x%x.", - vol->vol_flags, flags); - if (vol->vol_flags == flags) - goto done; - BUG_ON(!ni); - m = map_mft_record(ni); - if (IS_ERR(m)) { - err = PTR_ERR(m); - goto err_out; - } - ctx = get_attr_search_ctx(ni, m); - if (!ctx) { - err = -ENOMEM; - goto put_unm_err_out; - } - if (!lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx)) { - err = -EIO; - goto put_unm_err_out; - } - vi = (VOLUME_INFORMATION*)((u8*)ctx->attr + - le16_to_cpu(ctx->attr->data.resident.value_offset)); - vol->vol_flags = vi->flags = flags; - flush_dcache_mft_record_page(ctx->ntfs_ino); - mark_mft_record_dirty(ctx->ntfs_ino); - put_attr_search_ctx(ctx); - unmap_mft_record(ni); -done: - ntfs_debug("Done."); - return 0; -put_unm_err_out: - if (ctx) - put_attr_search_ctx(ctx); - unmap_mft_record(ni); -err_out: - ntfs_error(vol->sb, "Failed with error code %i.", -err); - return err; -} - -/** - * ntfs_set_volume_flags - set bits in the volume information flags - * @vol: ntfs volume on which to modify the flags - * @flags: flags to set on the volume - * - * Set the bits in @flags in the volume information flags on the volume @vol. - * - * Return 0 on success and -errno on error. - */ -static inline int ntfs_set_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags) -{ - flags &= VOLUME_FLAGS_MASK; - return ntfs_write_volume_flags(vol, vol->vol_flags | flags); -} - -/** - * ntfs_clear_volume_flags - clear bits in the volume information flags - * @vol: ntfs volume on which to modify the flags - * @flags: flags to clear on the volume - * - * Clear the bits in @flags in the volume information flags on the volume @vol. - * - * Return 0 on success and -errno on error. - */ -static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags) -{ - flags &= VOLUME_FLAGS_MASK; - return ntfs_write_volume_flags(vol, vol->vol_flags & ~flags); -} - -#endif /* NTFS_RW */ - /** * ntfs_remount - change the mount options of a mounted ntfs filesystem * @sb: superblock of mounted ntfs filesystem @@ -411,72 +316,30 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) * For the read-write compiled driver, if we are remounting read-write, * make sure there are no volume errors and that no unsupported volume * flags are set. Also, empty the logfile journal as it would become - * stale as soon as something is written to the volume and mark the - * volume dirty so that chkdsk is run if the volume is not umounted - * cleanly. - * - * When remounting read-only, mark the volume clean if no volume errors - * have occured. + * stale as soon as something is written to the volume. */ if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { static const char *es = ". Cannot remount read-write."; - /* Remounting read-write. */ if (NVolErrors(vol)) { ntfs_error(sb, "Volume has errors and is read-only%s", es); return -EROFS; } - if (vol->vol_flags & VOLUME_IS_DIRTY) { - ntfs_error(sb, "Volume is dirty and read-only%s", es); - return -EROFS; - } if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { ntfs_error(sb, "Volume has unsupported flags set and " "is read-only%s", es); return -EROFS; } - if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { - ntfs_error(sb, "Failed to set dirty bit in volume " - "information flags%s", es); - return -EROFS; - } -#if 0 - // TODO: Enable this code once we start modifying anything that - // is different between NTFS 1.2 and 3.x... - /* Set NT4 compatibility flag on newer NTFS version volumes. */ - if ((vol->major_ver > 1)) { - if (ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) { - ntfs_error(sb, "Failed to set NT4 " - "compatibility flag%s", es); - NVolSetErrors(vol); - return -EROFS; - } - } -#endif if (!ntfs_empty_logfile(vol->logfile_ino)) { ntfs_error(sb, "Failed to empty journal $LogFile%s", es); NVolSetErrors(vol); return -EROFS; } - } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { - /* Remounting read-only. */ - if (!NVolErrors(vol)) { - if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY)) - ntfs_warning(sb, "Failed to clear dirty bit " - "in volume information " - "flags. Run chkdsk."); - } } // TODO: For now we enforce no atime and dir atime updates as they are // not implemented. - if ((sb->s_flags & MS_NOATIME) && !(*flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Leaving them disabled."); - else if ((sb->s_flags & MS_NODIRATIME) && !(*flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Leaving them disabled."); *flags |= MS_NOATIME | MS_NODIRATIME; #endif /* ! NTFS_RW */ @@ -1268,7 +1131,7 @@ get_ctx_vol_failed: le32_to_cpu(ctx->attr->data.resident.value_length) > (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) goto err_put_vol; - /* Copy the volume flags and version to the ntfs_volume structure. */ + /* Setup volume flags and version. */ vol->vol_flags = vi->flags; vol->major_ver = vi->major_ver; vol->minor_ver = vi->minor_ver; @@ -1279,12 +1142,9 @@ get_ctx_vol_failed: #ifdef NTFS_RW /* Make sure that no unsupported volume flags are set. */ if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { - static const char *es1a = "Volume is dirty"; - static const char *es1b = "Volume has unsupported flags set"; + static const char *es1 = "Volume has unsupported flags set"; static const char *es2 = ". Run chkdsk and mount in Windows."; - const char *es1; - - es1 = vol->vol_flags & VOLUME_IS_DIRTY ? es1a : es1b; + /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | @@ -1311,12 +1171,10 @@ get_ctx_vol_failed: */ if (!load_and_check_logfile(vol) || !ntfs_is_logfile_clean(vol->logfile_ino)) { - static const char *es1a = "Failed to load $LogFile"; - static const char *es1b = "$LogFile is not clean"; - static const char *es2 = ". Mount in Windows."; - const char *es1; + static const char *es1 = "Failed to load $LogFile"; + static const char *es2 = "$LogFile is not clean"; + static const char *es3 = ". Mount in Windows."; - es1 = !vol->logfile_ino ? es1a : es1b; /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | @@ -1324,66 +1182,21 @@ get_ctx_vol_failed: ntfs_error(sb, "%s and neither on_errors=" "continue nor on_errors=" "remount-ro was specified%s", - es1, es2); + !vol->logfile_ino ? es1 : es2, + es3); goto iput_logfile_err_out; } sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; - ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); + ntfs_error(sb, "%s. Mounting read-only%s", + !vol->logfile_ino ? es1 : es2, es3); } else ntfs_warning(sb, "%s. Will not be able to remount " - "read-write%s", es1, es2); + "read-write%s", + !vol->logfile_ino ? es1 : es2, es3); /* This will prevent a read-write remount. */ NVolSetErrors(vol); - } - /* If (still) a read-write mount, mark the volume dirty. */ - if (!(sb->s_flags & MS_RDONLY) && - ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { - static const char *es1 = "Failed to set dirty bit in volume " - "information flags"; - static const char *es2 = ". Run chkdsk."; - - /* Convert to a read-only mount. */ - if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | - ON_ERRORS_CONTINUE))) { - ntfs_error(sb, "%s and neither on_errors=continue nor " - "on_errors=remount-ro was specified%s", - es1, es2); - goto iput_logfile_err_out; - } - ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); - sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; - /* - * Do not set NVolErrors() because ntfs_remount() might manage - * to set the dirty flag in which case all would be well. - */ - } -#if 0 - // TODO: Enable this code once we start modifying anything that is - // different between NTFS 1.2 and 3.x... - /* - * If (still) a read-write mount, set the NT4 compatibility flag on - * newer NTFS version volumes. - */ - if (!(sb->s_flags & MS_RDONLY) && (vol->major_ver > 1) && - ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) { - static const char *es1 = "Failed to set NT4 compatibility flag"; - static const char *es2 = ". Run chkdsk."; - - /* Convert to a read-only mount. */ - if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | - ON_ERRORS_CONTINUE))) { - ntfs_error(sb, "%s and neither on_errors=continue nor " - "on_errors=remount-ro was specified%s", - es1, es2); - goto iput_logfile_err_out; - } - ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); - sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; - NVolSetErrors(vol); - } -#endif - /* If (still) a read-write mount, empty the logfile. */ - if (!(sb->s_flags & MS_RDONLY) && + /* If a read-write mount, empty the logfile. */ + } else if (!(sb->s_flags & MS_RDONLY) && !ntfs_empty_logfile(vol->logfile_ino)) { static const char *es1 = "Failed to empty $LogFile"; static const char *es2 = ". Mount in Windows."; @@ -1396,11 +1209,12 @@ get_ctx_vol_failed: es1, es2); goto iput_logfile_err_out; } - ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; + ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); + /* This will prevent a read-write remount. */ NVolSetErrors(vol); } -#endif /* NTFS_RW */ +#endif /* * Get the inode for the attribute definitions file and parse the * attribute definitions. @@ -1475,69 +1289,18 @@ iput_mirr_err_out: /** * ntfs_put_super - called by the vfs to unmount a volume - * @sb: vfs superblock of volume to unmount + * @vfs_sb: vfs superblock of volume to unmount * * ntfs_put_super() is called by the VFS (from fs/super.c::do_umount()) when * the volume is being unmounted (umount system call has been invoked) and it * releases all inodes and memory belonging to the NTFS specific part of the * super block. */ -static void ntfs_put_super(struct super_block *sb) +static void ntfs_put_super(struct super_block *vfs_sb) { - ntfs_volume *vol = NTFS_SB(sb); + ntfs_volume *vol = NTFS_SB(vfs_sb); ntfs_debug("Entering."); -#ifdef NTFS_RW - /* - * Commit all inodes while they are still open in case some of them - * cause others to be dirtied. - */ - ntfs_commit_inode(vol->vol_ino); - - /* NTFS 3.0+ specific. */ - if (vol->major_ver >= 3) { - if (vol->secure_ino) - ntfs_commit_inode(vol->secure_ino); - } - - ntfs_commit_inode(vol->root_ino); - - down_write(&vol->lcnbmp_lock); - ntfs_commit_inode(vol->lcnbmp_ino); - up_write(&vol->lcnbmp_lock); - - down_write(&vol->mftbmp_lock); - ntfs_commit_inode(vol->mftbmp_ino); - up_write(&vol->mftbmp_lock); - - if (vol->logfile_ino) - ntfs_commit_inode(vol->logfile_ino); - - if (vol->mftmirr_ino) - ntfs_commit_inode(vol->mftmirr_ino); - ntfs_commit_inode(vol->mft_ino); - - /* - * If a read-write mount and no volume errors have occured, mark the - * volume clean. Also, re-commit all affected inodes. - */ - if (!(sb->s_flags & MS_RDONLY)) { - if (!NVolErrors(vol)) { - if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY)) - ntfs_warning(sb, "Failed to clear dirty bit " - "in volume information " - "flags. Run chkdsk."); - ntfs_commit_inode(vol->vol_ino); - ntfs_commit_inode(vol->root_ino); - if (vol->mftmirr_ino) - ntfs_commit_inode(vol->mftmirr_ino); - ntfs_commit_inode(vol->mft_ino); - } else { - ntfs_warning(sb, "Volume has errors. Leaving volume " - "marked dirty. Run chkdsk."); - } - } -#endif /* NTFS_RW */ iput(vol->vol_ino); vol->vol_ino = NULL; @@ -1568,47 +1331,11 @@ static void ntfs_put_super(struct super_block *sb) iput(vol->logfile_ino); vol->logfile_ino = NULL; } + if (vol->mftmirr_ino) { - /* Re-commit the mft mirror and mft just in case. */ - ntfs_commit_inode(vol->mftmirr_ino); - ntfs_commit_inode(vol->mft_ino); iput(vol->mftmirr_ino); vol->mftmirr_ino = NULL; } - /* - * If any dirty inodes are left, throw away all mft data page cache - * pages to allow a clean umount. This should never happen any more - * due to mft.c::ntfs_mft_writepage() cleaning all the dirty pages as - * the underlying mft records are written out and cleaned. If it does, - * happen anyway, we want to know... - */ - ntfs_commit_inode(vol->mft_ino); - write_inode_now(vol->mft_ino, 1); - if (!list_empty(&sb->s_dirty)) { - const char *s1, *s2; - - down(&vol->mft_ino->i_sem); - truncate_inode_pages(vol->mft_ino->i_mapping, 0); - up(&vol->mft_ino->i_sem); - write_inode_now(vol->mft_ino, 1); - if (!list_empty(&sb->s_dirty)) { - static const char *_s1 = "inodes"; - static const char *_s2 = ""; - s1 = _s1; - s2 = _s2; - } else { - static const char *_s1 = "mft pages"; - static const char *_s2 = "They have been thrown " - "away. "; - s1 = _s1; - s2 = _s2; - } - ntfs_error(sb, "Dirty %s found at umount time. %sYou should " - "run chkdsk. Please email " - "linux-ntfs-dev@lists.sourceforge.net and say " - "that you saw this message. Thank you.", s1, - s2); - } #endif /* NTFS_RW */ iput(vol->mft_ino); @@ -1617,7 +1344,7 @@ static void ntfs_put_super(struct super_block *sb) vol->upcase_len = 0; /* * Decrease the number of mounts and destroy the global default upcase - * table if necessary. Also decrease the number of upcase users if we + * table if necessary. Also decrease the number of upcase users if we * are a user. */ down(&ntfs_lock); @@ -1641,7 +1368,7 @@ static void ntfs_put_super(struct super_block *sb) unload_nls(vol->nls_map); vol->nls_map = NULL; } - sb->s_fs_info = NULL; + vfs_sb->s_fs_info = NULL; kfree(vol); return; } @@ -1902,8 +1629,8 @@ struct super_operations ntfs_sops = { #ifdef NTFS_RW //.dirty_inode = NULL, /* VFS: Called from // __mark_inode_dirty(). */ - .write_inode = ntfs_write_inode, /* VFS: Write dirty inode to - disk. */ + //.write_inode = NULL, /* VFS: Write dirty inode to + // disk. */ //.drop_inode = NULL, /* VFS: Called just after the // inode reference count has // been decreased to zero. @@ -1992,12 +1719,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) #ifndef NTFS_RW sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; #else - if (!(sb->s_flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Disabling them."); - else if (!(sb->s_flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Disabling them."); + // TODO: For now we enforce no atime and dir atime updates as they are + // not implemented. sb->s_flags |= MS_NOATIME | MS_NODIRATIME; #endif /* Allocate a new ntfs_volume and place it in sb->s_fs_info. */ diff --git a/fs/open.c b/fs/open.c index 854c5de74..a2566c942 100644 --- a/fs/open.c +++ b/fs/open.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -607,6 +608,9 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) dentry = file->f_dentry; inode = dentry->d_inode; + err = -EPERM; + if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN)) + goto out_putf; err = -EROFS; if (IS_RDONLY(inode)) goto out_putf; @@ -639,6 +643,10 @@ asmlinkage long sys_chmod(const char __user * filename, mode_t mode) goto out; inode = nd.dentry->d_inode; + error = -EPERM; + if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN)) + goto dput_and_out; + error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; @@ -678,14 +686,15 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; + newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { newattrs.ia_valid |= ATTR_UID; - newattrs.ia_uid = user; + newattrs.ia_uid = vx_map_uid(user); } if (group != (gid_t) -1) { newattrs.ia_valid |= ATTR_GID; - newattrs.ia_gid = group; + newattrs.ia_gid = vx_map_gid(group); } if (!S_ISDIR(inode->i_mode)) newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; @@ -880,6 +889,7 @@ repeat: FD_SET(fd, files->open_fds); FD_CLR(fd, files->close_on_exec); files->next_fd = fd + 1; + vx_openfd_inc(fd); #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { @@ -967,7 +977,6 @@ out_error: fd = error; goto out; } -EXPORT_SYMBOL_GPL(sys_open); #ifndef __alpha__ @@ -1034,6 +1043,7 @@ asmlinkage long sys_close(unsigned int fd) FD_CLR(fd, files->close_on_exec); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); + vx_openfd_dec(fd); return filp_close(filp, files); out_unlock: @@ -1041,7 +1051,6 @@ out_unlock: return -EBADF; } -EXPORT_SYMBOL(sys_close); /* * This routine simulates a hangup on the tty, to arrange that users diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index e98505bf8..1a673749e 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -389,23 +389,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) put_dev_sector(sect); return 0; } - - /* - * Now that the 55aa signature is present, this is probably - * either the boot sector of a FAT filesystem or a DOS-type - * partition table. Reject this in case the boot indicator - * is not 0 or 0x80. - */ p = (struct partition *) (data + 0x1be); - for (slot = 1; slot <= 4; slot++, p++) { - if (p->boot_ind != 0 && p->boot_ind != 0x80) { - put_dev_sector(sect); - return 0; - } - } - #ifdef CONFIG_EFI_PARTITION - p = (struct partition *) (data + 0x1be); for (slot = 1 ; slot <= 4 ; slot++, p++) { /* If this is an EFI GPT disk, msdos should ignore it. */ if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { @@ -413,8 +398,8 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) return 0; } } -#endif p = (struct partition *) (data + 0x1be); +#endif /* * Look for partitions in two passes: diff --git a/fs/pipe.c b/fs/pipe.c index 737271c0c..9ae8d8322 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -688,6 +688,8 @@ no_files: return error; } +EXPORT_SYMBOL_GPL(do_pipe); + /* * pipefs should _never_ be mounted by userland - too much of security hassle, * no real gain from having the whole whorehouse mounted. So we don't need diff --git a/fs/proc/array.c b/fs/proc/array.c index fbcf8bea0..278f30e96 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -128,7 +129,8 @@ static const char *task_state_array[] = { "D (disk sleep)", /* 2 */ "T (stopped)", /* 4 */ "Z (zombie)", /* 8 */ - "X (dead)" /* 16 */ + "X (dead)", /* 16 */ + "H (on hold)" /* 32 */ }; static inline const char * get_task_state(struct task_struct *tsk) @@ -137,7 +139,8 @@ static inline const char * get_task_state(struct task_struct *tsk) TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE | TASK_ZOMBIE | - TASK_STOPPED); + TASK_STOPPED | + TASK_ONHOLD); const char **p = &task_state_array[0]; while (state) { @@ -151,8 +154,10 @@ static inline char * task_state(struct task_struct *p, char *buffer) { struct group_info *group_info; int g; + pid_t ppid; read_lock(&tasklist_lock); + ppid = vx_map_tgid(current->vx_info, p->real_parent->pid); buffer += sprintf(buffer, "State:\t%s\n" "SleepAVG:\t%lu%%\n" @@ -165,7 +170,7 @@ static inline char * task_state(struct task_struct *p, char *buffer) get_task_state(p), (p->sleep_avg/1024)*100/(1020000000/1024), p->tgid, - p->pid, p->pid ? p->real_parent->pid : 0, + p->pid, p->pid ? ppid : 0, p->pid && p->ptrace ? p->parent->pid : 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); @@ -278,6 +283,10 @@ extern char *task_mem(struct mm_struct *, char *); int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; +#ifdef CONFIG_VSERVER_LEGACY + struct vx_info *vxi; + struct nx_info *nxi; +#endif struct mm_struct *mm = get_task_mm(task); buffer = task_name(task, buffer); @@ -289,6 +298,39 @@ int proc_pid_status(struct task_struct *task, char * buffer) } buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); + +#ifdef CONFIG_VSERVER_LEGACY + buffer += sprintf (buffer,"s_context: %d\n", vx_task_xid(task)); + vxi = task_get_vx_info(task); + if (vxi) { + buffer += sprintf (buffer,"ctxflags: %08llx\n" + ,(unsigned long long)vxi->vx_flags); + buffer += sprintf (buffer,"initpid: %d\n" + ,vxi->vx_initpid); + } else { + buffer += sprintf (buffer,"ctxflags: none\n"); + buffer += sprintf (buffer,"initpid: none\n"); + } + put_vx_info(vxi); + nxi = task_get_nx_info(task); + if (nxi) { + int i; + + buffer += sprintf (buffer,"ipv4root:"); + for (i=0; inbipv4; i++){ + buffer += sprintf (buffer," %08x/%08x" + ,nxi->ipv4[i] + ,nxi->mask[i]); + } + *buffer++ = '\n'; + buffer += sprintf (buffer,"ipv4root_bcast: %08x\n" + ,nxi->v4_bcast); + } else { + buffer += sprintf (buffer,"ipv4root: 0\n"); + buffer += sprintf (buffer,"ipv4root_bcast: 0\n"); + } + put_nx_info(nxi); +#endif #if defined(CONFIG_ARCH_S390) buffer = task_show_regs(task, buffer); #endif @@ -300,6 +342,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) { unsigned long vsize, eip, esp, wchan; long priority, nice; + unsigned long long bias_jiffies; int tty_pgrp = -1, tty_nr = 0; sigset_t sigign, sigcatch; char state; @@ -311,7 +354,16 @@ int proc_pid_stat(struct task_struct *task, char * buffer) state = *get_task_state(task); vsize = eip = esp = 0; + bias_jiffies = INITIAL_JIFFIES; + task_lock(task); + if (__vx_task_flags(task, VXF_VIRT_UPTIME, 0)) { + bias_jiffies = task->vx_info->cvirt.bias_jiffies; + /* hmm, do we need that? */ + if (bias_jiffies > task->start_time) + bias_jiffies = task->start_time; + } + mm = task->mm; if(mm) mm = mmgrab(mm); @@ -324,7 +376,10 @@ int proc_pid_stat(struct task_struct *task, char * buffer) up_read(&mm->mmap_sem); } - wchan = get_wchan(task); + wchan = 0; + if (current->uid == task->uid || current->euid == task->uid || + capable(CAP_SYS_NICE)) + wchan = get_wchan(task); sigemptyset(&sigign); sigemptyset(&sigcatch); @@ -355,7 +410,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) read_unlock(&tasklist_lock); /* Temporary variable needed for gcc-2.96 */ - start_time = jiffies_64_to_clock_t(task->start_time - INITIAL_JIFFIES); + start_time = jiffies_64_to_clock_t(task->start_time - bias_jiffies); res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ @@ -427,3 +482,22 @@ int proc_pid_statm(struct task_struct *task, char *buffer) return sprintf(buffer,"%d %d %d %d %d %d %d\n", size, resident, shared, text, lib, data, 0); } + + +int proc_pid_delay(struct task_struct *task, char * buffer) +{ + int res; + + res = sprintf(buffer,"%lu %lu %lu %lu %lu %lu %lu\n", + get_delay(task,runs), + get_delay(task,runcpu_total), + get_delay(task,waitcpu_total), + get_delay(task,iowait_total), + get_delay(task,num_iowaits), + get_delay(task,mem_iowait_total), + get_delay(task,num_memwaits) + + ); + return res; +} + diff --git a/fs/proc/base.c b/fs/proc/base.c index 5d6223272..c2324bd4d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -32,6 +32,7 @@ #include #include #include +#include /* * For hysterical raisins we keep the same inumbers as in the old procfs. @@ -67,6 +68,8 @@ enum pid_directory_inos { PROC_TGID_ATTR_EXEC, PROC_TGID_ATTR_FSCREATE, #endif + PROC_TGID_VX_INFO, + PROC_TGID_IP_INFO, PROC_TGID_FD_DIR, PROC_TID_INO, PROC_TID_STATUS, @@ -89,6 +92,12 @@ enum pid_directory_inos { PROC_TID_ATTR_PREV, PROC_TID_ATTR_EXEC, PROC_TID_ATTR_FSCREATE, +#endif + PROC_TID_VX_INFO, + PROC_TID_IP_INFO, +#ifdef CONFIG_DELAY_ACCT + PROC_TID_DELAY_ACCT, + PROC_TGID_DELAY_ACCT, #endif PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -111,7 +120,7 @@ static struct pid_entry tgid_base_stuff[] = { E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), - E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), + E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUSR), E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO), E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), @@ -120,9 +129,14 @@ static struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_SECURITY E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), #endif +#ifdef CONFIG_DELAY_ACCT + E(PROC_TGID_DELAY_ACCT,"delay", S_IFREG|S_IRUGO), +#endif #ifdef CONFIG_KALLSYMS E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO), #endif + E(PROC_TGID_VX_INFO, "vinfo", S_IFREG|S_IRUGO), + E(PROC_TGID_IP_INFO, "ninfo", S_IFREG|S_IRUGO), {0,0,NULL,0} }; static struct pid_entry tid_base_stuff[] = { @@ -133,7 +147,7 @@ static struct pid_entry tid_base_stuff[] = { E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), - E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), + E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUSR), E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO), E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), @@ -142,9 +156,14 @@ static struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_SECURITY E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), #endif +#ifdef CONFIG_DELAY_ACCT + E(PROC_TGID_DELAY_ACCT,"delay", S_IFREG|S_IRUGO), +#endif #ifdef CONFIG_KALLSYMS E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO), #endif + E(PROC_TID_VX_INFO, "vinfo", S_IFREG|S_IRUGO), + E(PROC_TID_IP_INFO, "ninfo", S_IFREG|S_IRUGO), {0,0,NULL,0} }; @@ -181,6 +200,7 @@ int proc_pid_stat(struct task_struct*,char*); int proc_pid_status(struct task_struct*,char*); int proc_pid_statm(struct task_struct*,char*); int proc_pid_cpu(struct task_struct*,char*); +int proc_pid_delay(struct task_struct*,char*); static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) { @@ -954,6 +974,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st inode->i_uid = task->euid; inode->i_gid = task->egid; } + inode->i_xid = vx_task_xid(task); security_task_to_inode(task, inode); out: @@ -979,6 +1000,11 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; struct task_struct *task = proc_task(inode); + + if (!vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + goto out_drop; + /* discard wrong fakeinit */ + if (pid_alive(task)) { if (proc_type(inode) == PROC_TGID_INO || proc_type(inode) == PROC_TID_INO || task_dumpable(task)) { inode->i_uid = task->euid; @@ -990,6 +1016,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) security_task_to_inode(task, inode); return 1; } +out_drop: d_drop(dentry); return 0; } @@ -1162,7 +1189,7 @@ static struct inode_operations proc_task_inode_operations = { }; #ifdef CONFIG_SECURITY -static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, +static ssize_t proc_pid_attr_read(struct file * file, char * buf, size_t count, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; @@ -1199,7 +1226,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, return count; } -static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, +static ssize_t proc_pid_attr_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; @@ -1374,6 +1401,23 @@ static struct dentry *proc_pident_lookup(struct inode *dir, inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_wchan; break; +#endif + case PROC_TID_VX_INFO: + case PROC_TGID_VX_INFO: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_vx_info; + break; + case PROC_TID_IP_INFO: + case PROC_TGID_IP_INFO: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_nx_info; + break; +#ifdef CONFIG_DELAY_ACCT + case PROC_TID_DELAY_ACCT: + case PROC_TGID_DELAY_ACCT: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_delay; + break; #endif default: printk("procfs: impossible type (%d)",p->type); @@ -1555,7 +1599,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct d_add(dentry, inode); return NULL; } - tgid = name_to_int(dentry); + tgid = vx_rmap_tgid(current->vx_info, name_to_int(dentry)); if (tgid == ~0U) goto out; @@ -1567,8 +1611,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct if (!task) goto out; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); - + inode = NULL; + if (vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); if (!inode) { put_task_struct(task); @@ -1610,10 +1655,12 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry struct inode *inode; unsigned tid; - tid = name_to_int(dentry); + tid = vx_rmap_tgid(current->vx_info, name_to_int(dentry)); if (tid == ~0U) goto out; +/* handle fakeinit */ + read_lock(&tasklist_lock); task = find_task_by_pid(tid); if (task) @@ -1624,8 +1671,9 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry if (leader->tgid != task->tgid) goto out_drop_task; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); - + inode = NULL; + if (vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); if (!inode) goto out_drop_task; @@ -1676,11 +1724,14 @@ static int get_tgid_list(int index, unsigned long version, unsigned int *tgids) for ( ; p != &init_task; p = next_task(p)) { int tgid = p->pid; + if (!pid_alive(p)) continue; + if (!vx_check(vx_task_xid(p), VX_WATCH|VX_IDENT)) + continue; if (--index >= 0) continue; - tgids[nr_tgids] = tgid; + tgids[nr_tgids] = vx_map_tgid(current->vx_info, tgid); nr_tgids++; if (nr_tgids >= PROC_MAXPIDS) break; @@ -1710,9 +1761,11 @@ static int get_tid_list(int index, unsigned int *tids, struct inode *dir) if (pid_alive(task)) do { int tid = task->pid; + if (!vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + continue; if (--index >= 0) continue; - tids[nr_tids] = tid; + tids[nr_tids] = vx_map_tgid(current->vx_info, tid); nr_tids++; if (nr_tids >= PROC_MAXPIDS) break; @@ -1766,11 +1819,14 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi unsigned int nr_tids, i; struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; + struct task_struct *task = proc_task(inode); int retval = -ENOENT; ino_t ino; unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ - if (!pid_alive(proc_task(inode))) + if (!vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + goto out; + if (!pid_alive(task)) goto out; retval = 0; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index d2c88ebb1..32a3f8798 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -319,21 +321,14 @@ static void release_inode_number(unsigned int inum) spin_unlock(&proc_inum_lock); } -static int -proc_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - char *s = PDE(dentry->d_inode)->data; - return vfs_readlink(dentry, buffer, buflen, s); -} - static int proc_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *s = PDE(dentry->d_inode)->data; - return vfs_follow_link(nd, s); + nd_set_link(nd, PDE(dentry->d_inode)->data); + return 0; } static struct inode_operations proc_link_inode_operations = { - .readlink = proc_readlink, + .readlink = generic_readlink, .follow_link = proc_follow_link, }; @@ -348,8 +343,15 @@ static int proc_delete_dentry(struct dentry * dentry) return 1; } +static int proc_revalidate_dentry(struct dentry *de, struct nameidata *nd) +{ + /* maybe add a check if it's really necessary? */ + return 0; +} + static struct dentry_operations proc_dentry_operations = { + .d_revalidate = proc_revalidate_dentry, .d_delete = proc_delete_dentry, }; @@ -369,6 +371,8 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam for (de = de->subdir; de ; de = de->next) { if (de->namelen != dentry->d_name.len) continue; + if (!vx_hide_check(0, de->vx_flags)) + continue; if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { unsigned int ino = de->low_ino; @@ -445,9 +449,12 @@ int proc_readdir(struct file * filp, } do { + if (!vx_hide_check(0, de->vx_flags)) + goto skip; if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino, de->mode >> 12) < 0) goto out; + skip: filp->f_pos++; de = de->next; } while (de); @@ -559,6 +566,7 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent, ent->namelen = len; ent->mode = mode; ent->nlink = nlink; + ent->vx_flags = IATTR_PROC_DEFAULT; out: return ent; } @@ -579,7 +587,8 @@ struct proc_dir_entry *proc_symlink(const char *name, kfree(ent->data); kfree(ent); ent = NULL; - } + } else + ent->vx_flags = IATTR_PROC_SYMLINK; } else { kfree(ent); ent = NULL; @@ -682,7 +691,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) parent->nlink--; proc_kill_inodes(de); de->nlink = 0; - WARN_ON(de->subdir); + BUG_ON(de->subdir); if (!atomic_read(&de->count)) free_proc_entry(de); else { diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 2d38f02c9..bf090daaf 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -211,6 +211,8 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, inode->i_uid = de->uid; inode->i_gid = de->gid; } + if (de->vx_flags) + PROC_I(inode)->vx_flags = de->vx_flags; if (de->size) inode->i_size = de->size; if (de->nlink) diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 1f55db799..7f6d1d330 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -24,7 +24,7 @@ static int open_kcore(struct inode * inode, struct file * filp) { - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; + return -EPERM; } static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 60e38c796..f96582d28 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,9 @@ static int uptime_read_proc(char *page, char **start, off_t off, do_posix_clock_monotonic_gettime(&uptime); jiffies_to_timespec(idle_jiffies, &idle); + if (vx_flags(VXF_VIRT_UPTIME, 0)) + vx_vsi_uptime(&uptime, &idle); + len = sprintf(page,"%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), diff --git a/fs/proc/root.c b/fs/proc/root.c index bf4b5d299..c84e88fe0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -23,6 +23,9 @@ struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL struct proc_dir_entry *proc_sys_root; #endif +struct proc_dir_entry *proc_virtual; + +extern void proc_vx_init(void); static struct super_block *proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) @@ -75,6 +78,7 @@ void __init proc_root_init(void) proc_device_tree_init(); #endif proc_bus = proc_mkdir("bus", 0); + proc_vx_init(); } static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index bbdfc9431..43301d869 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -34,12 +34,23 @@ char *task_mem(struct mm_struct *mm, char *buffer) "VmData:\t%8lu kB\n" "VmStk:\t%8lu kB\n" "VmExe:\t%8lu kB\n" - "VmLib:\t%8lu kB\n", + "VmLib:\t%8lu kB\n" + "StaBrk:\t%08lx kB\n" + "Brk:\t%08lx kB\n" + "StaStk:\t%08lx kB\n" +#if __i386__ + "ExecLim:\t%08lx\n" +#endif + , mm->total_vm << (PAGE_SHIFT-10), mm->locked_vm << (PAGE_SHIFT-10), mm->rss << (PAGE_SHIFT-10), data - stack, stack, - exec - lib, lib); + exec - lib, lib, mm->start_brk, mm->brk, mm->start_stack +#if __i386__ + , mm->context.exec_limit +#endif + ); up_read(&mm->mmap_sem); return buffer; } diff --git a/fs/rcfs/Makefile b/fs/rcfs/Makefile new file mode 100644 index 000000000..29575223e --- /dev/null +++ b/fs/rcfs/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for rcfs routines. +# + +obj-$(CONFIG_RCFS_FS) += rcfs.o + +rcfs-objs := super.o inode.o dir.o rootdir.o magic.o tc_magic.o socket_fs.o + +rcfs-objs-$(CONFIG_CKRM_TYPE_TASKCLASS) += tc_magic.o +rcfs-objs-$(CONFIG_CKRM_TYPE_SOCKETCLASS) += socket_fs.o diff --git a/fs/rcfs/dir.c b/fs/rcfs/dir.c new file mode 100644 index 000000000..048fe09bd --- /dev/null +++ b/fs/rcfs/dir.c @@ -0,0 +1,336 @@ +/* + * fs/rcfs/dir.c + * + * Copyright (C) Shailabh Nagar, IBM Corp. 2004 + * Vivek Kashyap, IBM Corp. 2004 + * + * + * Directory operations for rcfs + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 08 Mar 2004 + * Created. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + + +#define rcfs_positive(dentry) ((dentry)->d_inode && !d_unhashed((dentry))) + +int rcfs_empty(struct dentry *dentry) +{ + struct dentry *child; + int ret = 0; + + spin_lock(&dcache_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_child) + if (!rcfs_is_magic(child) && rcfs_positive(child)) + goto out; + ret = 1; +out: + spin_unlock(&dcache_lock); + return ret; +} + + + + +/* Directory inode operations */ + + +int +rcfs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + return rcfs_mknod(dir, dentry, mode | S_IFREG, 0); +} +EXPORT_SYMBOL(rcfs_create); + + +/* Symlinks permitted ?? */ +int +rcfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = rcfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + if (dir->i_mode & S_ISGID) + inode->i_gid = dir->i_gid; + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} +EXPORT_SYMBOL(rcfs_symlink); + +int +rcfs_create_coredir(struct inode *dir, struct dentry *dentry) +{ + + struct rcfs_inode_info *ripar, *ridir; + int sz; + + ripar = RCFS_I(dir); + ridir = RCFS_I(dentry->d_inode); + + // Inform RC's - do Core operations + if (ckrm_is_core_valid(ripar->core)) { + sz = strlen(ripar->name) + strlen(dentry->d_name.name) + 2 ; + ridir->name = kmalloc(sz, GFP_KERNEL); + if (!ridir->name) { + return -ENOMEM; + } + snprintf(ridir->name, sz,"%s/%s", ripar->name, + dentry->d_name.name); + ridir->core = (*(ripar->core->classtype->alloc)) + (ripar->core,ridir->name); + } + else { + printk(KERN_ERR "rcfs_mkdir: Invalid parent core %p\n", + ripar->core); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(rcfs_create_coredir); + + +int +rcfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + + int retval = 0; + ckrm_classtype_t *clstype; + +#if 0 + struct dentry *pd = list_entry(dir->i_dentry.next, struct dentry, + d_alias); + if ((!strcmp(pd->d_name.name, "/") && + !strcmp(dentry->d_name.name, "ce"))) { + // Call CE's mkdir if it has registered, else fail. + if (rcfs_eng_callbacks.mkdir) { + return (*rcfs_eng_callbacks.mkdir)(dir, dentry, mode); + } else { + return -EINVAL; + } + } +#endif + + if (_rcfs_mknod(dir, dentry, mode | S_IFDIR, 0)) { + printk(KERN_ERR "rcfs_mkdir: error in _rcfs_mknod\n"); + return retval; + } + + dir->i_nlink++; + + // Inherit parent's ops since _rcfs_mknod assigns noperm ops + dentry->d_inode->i_op = dir->i_op; + dentry->d_inode->i_fop = dir->i_fop; + + + retval = rcfs_create_coredir(dir, dentry); + if (retval) { + simple_rmdir(dir,dentry); + return retval; + // goto mkdir_err; + } + + // create the default set of magic files + clstype = (RCFS_I(dentry->d_inode))->core->classtype; + rcfs_create_magic(dentry, &(((struct rcfs_magf*)clstype->mfdesc)[1]), + clstype->mfcount-1); + + return retval; + +//mkdir_err: + dir->i_nlink--; + return retval; +} +EXPORT_SYMBOL(rcfs_mkdir); + + +int +rcfs_rmdir(struct inode * dir, struct dentry * dentry) +{ + struct rcfs_inode_info *ri = RCFS_I(dentry->d_inode); + +#if 0 + struct dentry *pd = list_entry(dir->i_dentry.next, + struct dentry, d_alias); + if ((!strcmp(pd->d_name.name, "/") && + !strcmp(dentry->d_name.name, "ce"))) { + // Call CE's mkdir if it has registered, else fail. + if (rcfs_eng_callbacks.rmdir) { + return (*rcfs_eng_callbacks.rmdir)(dir, dentry); + } else { + return simple_rmdir(dir, dentry); + } + } + else if ((!strcmp(pd->d_name.name, "/") && + !strcmp(dentry->d_name.name, "network"))) { + return -EPERM; + } +#endif + + if (!rcfs_empty(dentry)) { + printk(KERN_ERR "rcfs_rmdir: directory not empty\n"); + goto out; + } + + // Core class removal + + if (ri->core == NULL) { + printk(KERN_ERR "rcfs_rmdir: core==NULL\n"); + // likely a race condition + return 0; + } + + if ((*(ri->core->classtype->free))(ri->core)) { + printk(KERN_ERR "rcfs_rmdir: ckrm_free_core_class failed\n"); + goto out; + } + ri->core = NULL ; // just to be safe + + // Clear magic files only after core successfully removed + rcfs_clear_magic(dentry); + + return simple_rmdir(dir, dentry); + +out: + return -EBUSY; +} +EXPORT_SYMBOL(rcfs_rmdir); + + +int +rcfs_unlink(struct inode *dir, struct dentry *dentry) +{ + // -ENOENT and not -ENOPERM to allow rm -rf to work despite + // magic files being present + return -ENOENT; +} +EXPORT_SYMBOL(rcfs_unlink); + +// rename is allowed on directories only +int +rcfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + if (S_ISDIR(old_dentry->d_inode->i_mode)) + return simple_rename(old_dir, old_dentry, new_dir, new_dentry); + else + return -EINVAL; +} +EXPORT_SYMBOL(rcfs_rename); + + +struct inode_operations rcfs_dir_inode_operations = { + .create = rcfs_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = rcfs_unlink, + .symlink = rcfs_symlink, + .mkdir = rcfs_mkdir, + .rmdir = rcfs_rmdir, + .mknod = rcfs_mknod, + .rename = rcfs_rename, +}; + + + + + +int +rcfs_root_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + return -EPERM; +} + + +int +rcfs_root_symlink(struct inode * dir, struct dentry *dentry, + const char * symname) +{ + return -EPERM; +} + +int +rcfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + return -EPERM; +} + +int +rcfs_root_rmdir(struct inode * dir, struct dentry * dentry) +{ + return -EPERM; +} + +int +rcfs_root_unlink(struct inode *dir, struct dentry *dentry) +{ + return -EPERM; +} + +int +rcfs_root_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + return -EPERM; +} + +int +rcfs_root_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + return -EPERM; +} + +struct inode_operations rcfs_rootdir_inode_operations = { + .create = rcfs_root_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = rcfs_root_unlink, + .symlink = rcfs_root_symlink, + .mkdir = rcfs_root_mkdir, + .rmdir = rcfs_root_rmdir, + .mknod = rcfs_root_mknod, + .rename = rcfs_root_rename, +}; diff --git a/fs/rcfs/inode.c b/fs/rcfs/inode.c new file mode 100644 index 000000000..d9be67394 --- /dev/null +++ b/fs/rcfs/inode.c @@ -0,0 +1,204 @@ +/* + * fs/rcfs/inode.c + * + * Copyright (C) Shailabh Nagar, IBM Corp. 2004 + * Vivek Kashyap, IBM Corp. 2004 + * + * + * Resource class filesystem (rcfs) forming the + * user interface to Class-based Kernel Resource Management (CKRM). + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 05 Mar 2004 + * Created. + * 06 Mar 2004 + * Parsing for shares added + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +// Address of variable used as flag to indicate a magic file, +// ; value unimportant +int RCFS_IS_MAGIC; + + +struct inode *rcfs_get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode * inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + // Treat as default assignment */ + inode->i_op = &rcfs_file_inode_operations; + // inode->i_fop = &rcfs_file_operations; + break; + case S_IFDIR: + // inode->i_op = &rcfs_dir_inode_operations; + inode->i_op = &rcfs_rootdir_inode_operations; + inode->i_fop = &simple_dir_operations; + + // directory inodes start off with i_nlink == 2 + // (for "." entry) + + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + + + +int +_rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode *inode; + int error = -EPERM; + + if (dentry->d_inode) + return -EEXIST; + + inode = rcfs_get_inode(dir->i_sb, mode, dev); + if (inode) { + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + inode->i_mode |= S_ISGID; + } + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + + return error; +} +EXPORT_SYMBOL(_rcfs_mknod); + + +int +rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + // User can only create directories, not files + if ((mode & S_IFMT) != S_IFDIR) + return -EINVAL; + + return dir->i_op->mkdir(dir, dentry, mode); +} +EXPORT_SYMBOL(rcfs_mknod); + + +struct dentry * +rcfs_create_internal(struct dentry *parent, struct rcfs_magf *magf, int magic) +{ + struct qstr qstr; + struct dentry *mfdentry ; + + // Get new dentry for name + qstr.name = magf->name; + qstr.len = strlen(magf->name); + qstr.hash = full_name_hash(magf->name,qstr.len); + mfdentry = lookup_hash(&qstr,parent); + + if (!IS_ERR(mfdentry)) { + int err; + + down(&parent->d_inode->i_sem); + if (magic && (magf->mode & S_IFDIR)) + err = parent->d_inode->i_op->mkdir(parent->d_inode, + mfdentry, magf->mode); + else { + err =_rcfs_mknod(parent->d_inode,mfdentry, + magf->mode,0); + // _rcfs_mknod doesn't increment parent's link count, + // i_op->mkdir does. + parent->d_inode->i_nlink++; + } + up(&parent->d_inode->i_sem); + + if (err) { + dput(mfdentry); + return mfdentry; + } + } + return mfdentry ; +} +EXPORT_SYMBOL(rcfs_create_internal); + +int +rcfs_delete_internal(struct dentry *mfdentry) +{ + struct dentry *parent ; + + if (!mfdentry || !mfdentry->d_parent) + return -EINVAL; + + parent = mfdentry->d_parent; + + if (!mfdentry->d_inode) { + return 0; + } + down(&mfdentry->d_inode->i_sem); + if (S_ISDIR(mfdentry->d_inode->i_mode)) + simple_rmdir(parent->d_inode, mfdentry); + else + simple_unlink(parent->d_inode, mfdentry); + up(&mfdentry->d_inode->i_sem); + + d_delete(mfdentry); + + return 0; +} +EXPORT_SYMBOL(rcfs_delete_internal); + +struct inode_operations rcfs_file_inode_operations = { + .getattr = simple_getattr, +}; + + + + + + diff --git a/fs/rcfs/magic.c b/fs/rcfs/magic.c new file mode 100644 index 000000000..ad92a07a8 --- /dev/null +++ b/fs/rcfs/magic.c @@ -0,0 +1,546 @@ +/* + * fs/rcfs/magic.c + * + * Copyright (C) Shailabh Nagar, IBM Corp. 2004 + * (C) Vivek Kashyap, IBM Corp. 2004 + * (C) Chandra Seetharaman, IBM Corp. 2004 + * (C) Hubertus Franke, IBM Corp. 2004 + * + * File operations for common magic files in rcfs, + * the user interface for CKRM. + * + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 23 Apr 2004 + * Created from code kept earlier in fs/rcfs/magic_*.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + + +/****************************************************** + * Macros + * + * generic macros to assist in writing magic fileops + * + *****************************************************/ + + +#define MAGIC_SHOW(FUNC) \ +static int \ +FUNC ## _show(struct seq_file *s, void *v) \ +{ \ + int rc=0; \ + ckrm_core_class_t *core ; \ + \ + core = (ckrm_core_class_t *) \ + (((struct rcfs_inode_info *)s->private)->core); \ + \ + if (!ckrm_is_core_valid(core)) { \ + return -EINVAL; \ + } \ + \ + if (core->classtype->show_ ## FUNC) \ + rc = (* core->classtype->show_ ## FUNC)(core, s); \ + \ + return rc; \ +}; + + +#define MAGIC_OPEN(FUNC) \ +static int \ +FUNC ## _open(struct inode *inode, struct file *file) \ +{ \ + struct rcfs_inode_info *ri; \ + int ret=-EINVAL; \ + \ + if (file->f_dentry && file->f_dentry->d_parent) { \ + \ + ri = RCFS_I(file->f_dentry->d_parent->d_inode); \ + ret = single_open(file,FUNC ## _show, (void *)ri); \ + } \ + return ret; \ +} + +#define MAGIC_CLOSE(FUNC) \ +static int \ +FUNC ## _close(struct inode *inode, struct file *file) \ +{ \ + return single_release(inode,file); \ +} + + + +#define MAGIC_PARSE(FUNC) \ +static int \ +FUNC ## _parse(char *options, char **resstr, char **otherstr) \ +{ \ + char *p; \ + \ + if (!options) \ + return 1; \ + \ + while ((p = strsep(&options, ",")) != NULL) { \ + substring_t args[MAX_OPT_ARGS]; \ + int token; \ + \ + if (!*p) \ + continue; \ + \ + token = match_token(p, FUNC##_tokens, args); \ + switch (token) { \ + case FUNC ## _res_type: \ + *resstr = match_strdup(args); \ + break; \ + case FUNC ## _str: \ + *otherstr = match_strdup(args); \ + break; \ + default: \ + return 0; \ + } \ + } \ + return 1; \ +} + +#define MAGIC_WRITE(FUNC,CLSTYPEFUN) \ +static ssize_t \ +FUNC ## _write(struct file *file, const char __user *buf, \ + size_t count, loff_t *ppos) \ +{ \ + struct rcfs_inode_info *ri = \ + RCFS_I(file->f_dentry->d_parent->d_inode); \ + char *optbuf, *otherstr=NULL, *resname=NULL; \ + int done, rc = 0; \ + ckrm_core_class_t *core ; \ + \ + core = ri->core; \ + if (!ckrm_is_core_valid(core)) \ + return -EINVAL; \ + \ + if ((ssize_t) count < 0 \ + || (ssize_t) count > FUNC ## _max_input_size) \ + return -EINVAL; \ + \ + if (!access_ok(VERIFY_READ, buf, count)) \ + return -EFAULT; \ + \ + down(&(ri->vfs_inode.i_sem)); \ + \ + optbuf = kmalloc(FUNC ## _max_input_size, GFP_KERNEL); \ + __copy_from_user(optbuf, buf, count); \ + if (optbuf[count-1] == '\n') \ + optbuf[count-1]='\0'; \ + \ + done = FUNC ## _parse(optbuf, &resname, &otherstr); \ + \ + if (!done) { \ + printk(KERN_ERR "Error parsing FUNC \n"); \ + goto FUNC ## _write_out; \ + } \ + \ + if (core->classtype-> CLSTYPEFUN) { \ + rc = (*core->classtype->CLSTYPEFUN) \ + (core, resname, otherstr); \ + if (rc) { \ + printk(KERN_ERR "FUNC_write: CLSTYPEFUN error\n"); \ + goto FUNC ## _write_out; \ + } \ + } \ + \ +FUNC ## _write_out: \ + up(&(ri->vfs_inode.i_sem)); \ + kfree(optbuf); \ + kfree(otherstr); \ + kfree(resname); \ + return rc ? rc : count; \ +} + + +#define MAGIC_RD_FILEOPS(FUNC) \ +struct file_operations FUNC ## _fileops = { \ + .open = FUNC ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = FUNC ## _close, \ +}; \ +EXPORT_SYMBOL(FUNC ## _fileops); + + +#define MAGIC_RDWR_FILEOPS(FUNC) \ +struct file_operations FUNC ## _fileops = { \ + .open = FUNC ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = FUNC ## _close, \ + .write = FUNC ## _write, \ +}; \ +EXPORT_SYMBOL(FUNC ## _fileops); + + +/******************************************************************************** + * Target + * + * pseudo file for manually reclassifying members to a class + * + *******************************************************************************/ + +#define TARGET_MAX_INPUT_SIZE 100 + +static ssize_t +target_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct rcfs_inode_info *ri= RCFS_I(file->f_dentry->d_inode); + char *optbuf; + int rc = -EINVAL; + ckrm_classtype_t *clstype; + + + if ((ssize_t) count < 0 || (ssize_t) count > TARGET_MAX_INPUT_SIZE) + return -EINVAL; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + down(&(ri->vfs_inode.i_sem)); + + optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL); + __copy_from_user(optbuf, buf, count); + if (optbuf[count-1] == '\n') + optbuf[count-1]='\0'; + + clstype = ri->core->classtype; + if (clstype->forced_reclassify) + rc = (* clstype->forced_reclassify)(ri->core,optbuf); + + up(&(ri->vfs_inode.i_sem)); + kfree(optbuf); + return !rc ? count : rc; + +} + +struct file_operations target_fileops = { + .write = target_write, +}; +EXPORT_SYMBOL(target_fileops); + + + +/******************************************************************************** + * Config + * + * Set/get configuration parameters of a class. + * + *******************************************************************************/ + +/* Currently there are no per-class config parameters defined. + * Use existing code as a template + */ + +#define config_max_input_size 300 + +enum config_token_t { + config_str, config_res_type, config_err +}; + +static match_table_t config_tokens = { + {config_res_type,"res=%s"}, + {config_str, "config=%s"}, + {config_err, NULL}, +}; + + +MAGIC_PARSE(config); +MAGIC_WRITE(config,set_config); +MAGIC_SHOW(config); +MAGIC_OPEN(config); +MAGIC_CLOSE(config); + +MAGIC_RDWR_FILEOPS(config); + + +/******************************************************************************** + * Members + * + * List members of a class + * + *******************************************************************************/ + +MAGIC_SHOW(members); +MAGIC_OPEN(members); +MAGIC_CLOSE(members); + +MAGIC_RD_FILEOPS(members); + + +/******************************************************************************** + * Stats + * + * Get/reset class statistics + * No standard set of stats defined. Each resource controller chooses + * its own set of statistics to maintain and export. + * + *******************************************************************************/ + +#define stats_max_input_size 50 + +enum stats_token_t { + stats_res_type, stats_str,stats_err +}; + +static match_table_t stats_tokens = { + {stats_res_type,"res=%s"}, + {stats_str, NULL}, + {stats_err, NULL}, +}; + + +MAGIC_PARSE(stats); +MAGIC_WRITE(stats,reset_stats); +MAGIC_SHOW(stats); +MAGIC_OPEN(stats); +MAGIC_CLOSE(stats); + +MAGIC_RDWR_FILEOPS(stats); + + +/******************************************************************************** + * Shares + * + * Set/get shares of a taskclass. + * Share types and semantics are defined by rcfs and ckrm core + * + *******************************************************************************/ + + +#define SHARES_MAX_INPUT_SIZE 300 + +/* The enums for the share types should match the indices expected by + array parameter to ckrm_set_resshare */ + +/* Note only the first NUM_SHAREVAL enums correspond to share types, + the remaining ones are for token matching purposes */ + +enum share_token_t { + MY_GUAR, MY_LIM, TOT_GUAR, MAX_LIM, SHARE_RES_TYPE, SHARE_ERR +}; + +/* Token matching for parsing input to this magic file */ +static match_table_t shares_tokens = { + {SHARE_RES_TYPE, "res=%s"}, + {MY_GUAR, "guarantee=%d"}, + {MY_LIM, "limit=%d"}, + {TOT_GUAR,"total_guarantee=%d"}, + {MAX_LIM, "max_limit=%d"}, + {SHARE_ERR, NULL} +}; + + +static int +shares_parse(char *options, char **resstr, struct ckrm_shares *shares) +{ + char *p; + int option; + + if (!options) + return 1; + + while ((p = strsep(&options, ",")) != NULL) { + + substring_t args[MAX_OPT_ARGS]; + int token; + + if (!*p) + continue; + + token = match_token(p, shares_tokens, args); + switch (token) { + case SHARE_RES_TYPE: + *resstr = match_strdup(args); + break; + case MY_GUAR: + if (match_int(args, &option)) + return 0; + shares->my_guarantee = option; + break; + case MY_LIM: + if (match_int(args, &option)) + return 0; + shares->my_limit = option; + break; + case TOT_GUAR: + if (match_int(args, &option)) + return 0; + shares->total_guarantee = option; + break; + case MAX_LIM: + if (match_int(args, &option)) + return 0; + shares->max_limit = option; + break; + default: + return 0; + } + + } + return 1; +} + + +static ssize_t +shares_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct rcfs_inode_info *ri; + char *optbuf; + int rc = 0; + struct ckrm_core_class *core; + int done; + char *resname; + + struct ckrm_shares newshares = { + CKRM_SHARE_UNCHANGED, + CKRM_SHARE_UNCHANGED, + CKRM_SHARE_UNCHANGED, + CKRM_SHARE_UNCHANGED, + CKRM_SHARE_UNCHANGED, + CKRM_SHARE_UNCHANGED + }; + + if ((ssize_t) count < 0 || (ssize_t) count > SHARES_MAX_INPUT_SIZE) + return -EINVAL; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + ri = RCFS_I(file->f_dentry->d_parent->d_inode); + + if (!ri || !ckrm_is_core_valid((ckrm_core_class_t *)(ri->core))) { + printk(KERN_ERR "shares_write: Error accessing core class\n"); + return -EFAULT; + } + + down(&inode->i_sem); + + core = ri->core; + optbuf = kmalloc(SHARES_MAX_INPUT_SIZE, GFP_KERNEL); + __copy_from_user(optbuf, buf, count); + if (optbuf[count-1] == '\n') + optbuf[count-1]='\0'; + + done = shares_parse(optbuf, &resname, &newshares); + if (!done) { + printk(KERN_ERR "Error parsing shares\n"); + rc = -EINVAL; + goto write_out; + } + + if (core->classtype->set_shares) { + rc = (*core->classtype->set_shares)(core,resname,&newshares); + if (rc) { + printk(KERN_ERR "shares_write: resctlr share set error\n"); + goto write_out; + } + } + + printk(KERN_ERR "Set %s shares to %d %d %d %d\n", + resname, + newshares.my_guarantee, + newshares.my_limit, + newshares.total_guarantee, + newshares.max_limit); + + rc = count ; + +write_out: + + up(&inode->i_sem); + kfree(optbuf); + kfree(resname); + return rc; +} + + +MAGIC_SHOW(shares); +MAGIC_OPEN(shares); +MAGIC_CLOSE(shares); + +MAGIC_RDWR_FILEOPS(shares); + + + +/* + * magic file creation/deletion + * + */ + + +int +rcfs_clear_magic(struct dentry *parent) +{ + struct dentry *mftmp, *mfdentry ; + + list_for_each_entry_safe(mfdentry, mftmp, &parent->d_subdirs, d_child) { + + if (!rcfs_is_magic(mfdentry)) + continue ; + + if (rcfs_delete_internal(mfdentry)) + printk(KERN_ERR "rcfs_clear_magic: error deleting one\n"); + } + + return 0; + +} +EXPORT_SYMBOL(rcfs_clear_magic); + + +int +rcfs_create_magic(struct dentry *parent, struct rcfs_magf magf[], int count) +{ + int i; + struct dentry *mfdentry; + + for (i=0; id_inode)->core = RCFS_I(parent->d_inode)->core; + mfdentry->d_fsdata = &RCFS_IS_MAGIC; + if (magf[i].i_fop) + mfdentry->d_inode->i_fop = magf[i].i_fop; + if (magf[i].i_op) + mfdentry->d_inode->i_op = magf[i].i_op; + } + return 0; +} +EXPORT_SYMBOL(rcfs_create_magic); diff --git a/fs/rcfs/rootdir.c b/fs/rcfs/rootdir.c new file mode 100644 index 000000000..fe3415d8d --- /dev/null +++ b/fs/rcfs/rootdir.c @@ -0,0 +1,244 @@ +/* + * fs/rcfs/rootdir.c + * + * Copyright (C) Vivek Kashyap, IBM Corp. 2004 + * + * + * Functions for creating root directories and magic files + * for classtypes and classification engines under rcfs + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 08 April 2004 + * Created. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + + +rbce_eng_callback_t rcfs_eng_callbacks = { + NULL, NULL +}; + +int +rcfs_register_engine(rbce_eng_callback_t *rcbs) +{ + if (!rcbs->mkdir || rcfs_eng_callbacks.mkdir) { + return -EINVAL; + } + rcfs_eng_callbacks = *rcbs; + return 0; +} +EXPORT_SYMBOL(rcfs_register_engine); + + + +int +rcfs_unregister_engine(rbce_eng_callback_t *rcbs) +{ + if (!rcbs->mkdir || !rcfs_eng_callbacks.mkdir || + (rcbs->mkdir != rcfs_eng_callbacks.mkdir)) { + return -EINVAL; + } + rcfs_eng_callbacks.mkdir = NULL; + rcfs_eng_callbacks.rmdir = NULL; + return 0; +} +EXPORT_SYMBOL(rcfs_unregister_engine); + + + + +/* rcfs_mkroot + * Create and return a "root" dentry under /rcfs. Also create associated magic files + * + * @mfdesc: array of rcfs_magf describing root dir and its magic files + * @count: number of entries in mfdesc + * @core: core class to be associated with root + * @rootde: output parameter to return the newly created root dentry + */ + +int +rcfs_mkroot(struct rcfs_magf *mfdesc, int mfcount, struct dentry **rootde) +{ + int sz; + struct rcfs_magf *rootdesc = &mfdesc[0]; + struct dentry *dentry ; + struct rcfs_inode_info *rootri; + + if ((mfcount < 0) || (!mfdesc)) + return -EINVAL; + + rootdesc = &mfdesc[0]; + printk("allocating classtype root <%s>\n",rootdesc->name); + dentry = rcfs_create_internal(rcfs_rootde, rootdesc,0); + + if (!dentry) { + printk(KERN_ERR "Could not create %s\n",rootdesc->name); + return -ENOMEM; + } + + rootri = RCFS_I(dentry->d_inode); + sz = strlen(rootdesc->name) + strlen(RCFS_ROOT) + 2; + rootri->name = kmalloc(sz, GFP_KERNEL); + if (!rootri->name) { + printk(KERN_ERR "Error allocating name for %s\n", + rootdesc->name); + rcfs_delete_internal(dentry); + return -ENOMEM; + } + snprintf(rootri->name,sz,"%s/%s",RCFS_ROOT,rootdesc->name); + + if (rootdesc->i_fop) + dentry->d_inode->i_fop = rootdesc->i_fop; + if (rootdesc->i_op) + dentry->d_inode->i_op = rootdesc->i_op; + + // set output parameters + *rootde = dentry; + + return 0; +} +EXPORT_SYMBOL(rcfs_mkroot); + + +int +rcfs_rmroot(struct dentry *rootde) +{ + if (!rootde) + return -EINVAL; + + rcfs_clear_magic(rootde); + kfree(RCFS_I(rootde->d_inode)->name); + rcfs_delete_internal(rootde); + return 0; +} +EXPORT_SYMBOL(rcfs_rmroot); + + +int +rcfs_register_classtype(ckrm_classtype_t *clstype) +{ + int rc ; + struct rcfs_inode_info *rootri; + struct rcfs_magf *mfdesc; + + // Initialize mfdesc, mfcount + clstype->mfdesc = (void *) genmfdesc[clstype->mfidx]->rootmf; + clstype->mfcount = genmfdesc[clstype->mfidx]->rootmflen; + + mfdesc = (struct rcfs_magf *)clstype->mfdesc; + + /* rcfs root entry has the same name as the classtype */ + strncpy(mfdesc[0].name,clstype->name,RCFS_MAGF_NAMELEN) ; + + rc = rcfs_mkroot(mfdesc,clstype->mfcount, + (struct dentry **)&(clstype->rootde)); + if (rc) + return rc; + + rootri = RCFS_I(((struct dentry *)(clstype->rootde))->d_inode); + rootri->core = clstype->default_class; + clstype->default_class->name = rootri->name; + ckrm_core_grab(clstype->default_class); + + // Create magic files under root + if ((rc = rcfs_create_magic(clstype->rootde, &mfdesc[1], + clstype->mfcount-1))) { + kfree(rootri->name); + rcfs_delete_internal(clstype->rootde); + return rc; + } + + return rc; +} +EXPORT_SYMBOL(rcfs_register_classtype); + + +int +rcfs_deregister_classtype(ckrm_classtype_t *clstype) +{ + int rc; + + rc = rcfs_rmroot((struct dentry *)clstype->rootde); + if (!rc) { + clstype->default_class->name = NULL ; + ckrm_core_drop(clstype->default_class); + } + return rc; +} +EXPORT_SYMBOL(rcfs_deregister_classtype); + + + +// Common root and magic file entries. +// root name, root permissions, magic file names and magic file permissions are needed by +// all entities (classtypes and classification engines) existing under the rcfs mount point + +// The common sets of these attributes are listed here as a table. Individual classtypes and +// classification engines can simple specify the index into the table to initialize their +// magf entries. +// + +#ifdef CONFIG_CKRM_TYPE_TASKCLASS +extern struct rcfs_mfdesc tc_mfdesc; +#endif + +#ifdef CONFIG_CKRM_TYPE_TASKCLASS +extern struct rcfs_mfdesc sock_mfdesc; +#endif + +// extern struct rcfs_magf rbce_mfdesc; + + +struct rcfs_mfdesc *genmfdesc[]={ +#ifdef CONFIG_CKRM_TYPE_TASKCLASS + &tc_mfdesc, +#else + NULL, +#endif +#ifdef CONFIG_CKRM_TYPE_SOCKETCLASS + &sock_mfdesc, +#else + NULL, +#endif +// Create similar entry for RBCE ? +//#ifdef CONFIG_CKRM_CE +// &rbce_mfdesc, +//#else +// NULL, +//#endif + +}; + + + + diff --git a/fs/rcfs/socket_fs.c b/fs/rcfs/socket_fs.c new file mode 100644 index 000000000..492fb092c --- /dev/null +++ b/fs/rcfs/socket_fs.c @@ -0,0 +1,338 @@ +/* ckrm_socketaq.c + * + * Copyright (C) Vivek Kashyap, IBM Corp. 2004 + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * Initial version + */ + +/******************************************************************************* + * Socket class type + * + * Defines the root structure for socket based classes. Currently only inbound + * connection control is supported based on prioritized accept queues. + ******************************************************************************/ + + +#include +#include + +extern int rcfs_create(struct inode *,struct dentry *, int, struct nameidata *); +extern int rcfs_unlink(struct inode *, struct dentry *); +extern int rcfs_symlink(struct inode *, struct dentry *, const char *); +extern int rcfs_mknod(struct inode *, struct dentry *, int mode, dev_t); +extern int rcfs_mkdir(struct inode *, struct dentry *, int); +extern int rcfs_rmdir(struct inode *, struct dentry *); +extern int rcfs_rename(struct inode *, struct dentry *, struct inode *, + struct dentry *); + +extern int rcfs_create_coredir(struct inode *, struct dentry *); +int sock_mkdir(struct inode *, struct dentry *, int mode); +int sock_rmdir(struct inode *, struct dentry *); + + +int sock_create_noperm(struct inode *, struct dentry *,int, struct nameidata *); +int sock_unlink_noperm(struct inode *,struct dentry *); +int sock_mkdir_noperm(struct inode *,struct dentry *,int); +int sock_rmdir_noperm(struct inode *,struct dentry *); +int sock_mknod_noperm(struct inode *,struct dentry *,int, dev_t); + +void sock_set_directory(void); + +extern struct file_operations config_fileops, + members_fileops, + shares_fileops, + stats_fileops, + target_fileops; + + +struct inode_operations my_iops = { + .create = rcfs_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = rcfs_unlink, + .symlink = rcfs_symlink, + .mkdir = sock_mkdir, + .rmdir = sock_rmdir, + .mknod = rcfs_mknod, + .rename = rcfs_rename, +}; + +struct inode_operations class_iops = { + .create = sock_create_noperm, + .lookup = simple_lookup, + .link = simple_link, + .unlink = sock_unlink_noperm, + .symlink = rcfs_symlink, + .mkdir = sock_mkdir_noperm, + .rmdir = sock_rmdir_noperm, + .mknod = sock_mknod_noperm, + .rename = rcfs_rename, +}; + +struct inode_operations sub_iops = { + .create = sock_create_noperm, + .lookup = simple_lookup, + .link = simple_link, + .unlink = sock_unlink_noperm, + .symlink = rcfs_symlink, + .mkdir = sock_mkdir_noperm, + .rmdir = sock_rmdir_noperm, + .mknod = sock_mknod_noperm, + .rename = rcfs_rename, +}; + +struct rcfs_magf def_magf = { + .mode = RCFS_DEFAULT_DIR_MODE, + .i_op = &sub_iops, + .i_fop = NULL, +}; + +struct rcfs_magf sock_rootdesc[] = { + { + // .name = should not be set, copy from classtype name, + .mode = RCFS_DEFAULT_DIR_MODE, + .i_op = &my_iops, + //.i_fop = &simple_dir_operations, + .i_fop = NULL, + }, + { + .name = "members", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &members_fileops, + }, + { + .name = "target", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &target_fileops, + }, +}; + +struct rcfs_magf sock_magf[] = { + { + .name = "config", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &config_fileops, + }, + { + .name = "members", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop =&members_fileops, + }, + { + .name = "shares", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &shares_fileops, + }, + { + .name = "stats", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &stats_fileops, + }, + { + .name = "target", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &target_fileops, + }, +}; + +struct rcfs_magf sub_magf[] = { + { + .name = "config", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &config_fileops, + }, + { + .name = "shares", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &shares_fileops, + }, + { + .name = "stats", + .mode = RCFS_DEFAULT_FILE_MODE, + .i_op = &my_iops, + .i_fop = &stats_fileops, + }, +}; + +struct rcfs_mfdesc sock_mfdesc = { + .rootmf = sock_rootdesc, + .rootmflen = (sizeof(sock_rootdesc)/sizeof(struct rcfs_magf)), +}; + + +#define SOCK_MAX_MAGF (sizeof(sock_magf)/sizeof(struct rcfs_magf)) +#define LAQ_MAX_SUBMAGF (sizeof(sub_magf)/sizeof(struct rcfs_magf)) + +int +sock_rmdir(struct inode *p, struct dentry *me) +{ + struct dentry *mftmp, *mfdentry ; + + // delete all magic sub directories + list_for_each_entry_safe(mfdentry, mftmp, &me->d_subdirs, d_child) { + if (S_ISDIR(mfdentry->d_inode->i_mode)) + rcfs_rmdir(me->d_inode, mfdentry); + } + // delete ourselves + rcfs_rmdir(p,me); + + return 0; +} + +#ifdef NUM_ACCEPT_QUEUES +#define LAQ_NUM_ACCEPT_QUEUES NUM_ACCEPT_QUEUES +#else +#define LAQ_NUM_ACCEPT_QUEUES 0 +#endif + +int +sock_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int retval = 0; + int i,j; + struct dentry *pentry, *mfdentry; + + if (_rcfs_mknod(dir, dentry, mode | S_IFDIR, 0)) { + printk(KERN_ERR "rcfs_mkdir: error reaching parent\n"); + return retval; + } + + // Needed if only _rcfs_mknod is used instead of i_op->mkdir + dir->i_nlink++; + + retval = rcfs_create_coredir(dir, dentry); + if (retval) + goto mkdir_err; + + /* create the default set of magic files */ + for (i =0; i < SOCK_MAX_MAGF; i++) { + mfdentry = rcfs_create_internal(dentry, &sock_magf[i],0); + mfdentry->d_fsdata = &RCFS_IS_MAGIC; + RCFS_I(mfdentry->d_inode)->core = + RCFS_I(dentry->d_inode)->core; + if (sock_magf[i].i_fop) + mfdentry->d_inode->i_fop = sock_magf[i].i_fop; + if (sock_magf[i].i_op) + mfdentry->d_inode->i_op = sock_magf[i].i_op; + } + + for (i=1; i < LAQ_NUM_ACCEPT_QUEUES; i++) { + j = sprintf(def_magf.name, "%d",i); + def_magf.name[j] = '\0'; + + pentry = rcfs_create_internal(dentry, &def_magf,0); + retval = rcfs_create_coredir(dentry->d_inode, pentry); + if (retval) + goto mkdir_err; + for (j=0; j < LAQ_MAX_SUBMAGF; j++) { + mfdentry = rcfs_create_internal(pentry, &sub_magf[j],0); + mfdentry->d_fsdata = &RCFS_IS_MAGIC; + RCFS_I(mfdentry->d_inode)->core = + RCFS_I(pentry->d_inode)->core; + if (sub_magf[j].i_fop) + mfdentry->d_inode->i_fop = sub_magf[j].i_fop; + if (sub_magf[j].i_op) + mfdentry->d_inode->i_op = sub_magf[j].i_op; + } + pentry->d_inode->i_op = &sub_iops; + } + dentry->d_inode->i_op = &class_iops; + return 0; + +mkdir_err: + // Needed + dir->i_nlink--; + return retval; +} +#ifndef NUM_ACCEPT_QUEUES +#define NUM_ACCEPT_QUEUES 0 +#endif + +char * +sock_get_name(struct ckrm_core_class *c) +{ + char *p = (char *)c->name; + + while(*p) + p++; + while( *p != '/' && p != c->name) + p--; + + return ++p; +} + +int +sock_create_noperm(struct inode *dir,struct dentry *dentry,int mode, struct nameidata *nd) +{ + return -EPERM; +} + +int +sock_unlink_noperm(struct inode *dir,struct dentry *dentry) +{ + return -EPERM; +} + +int +sock_mkdir_noperm(struct inode *dir,struct dentry *dentry, int mode) +{ + return -EPERM; +} + +int +sock_rmdir_noperm(struct inode *dir,struct dentry *dentry) +{ + return -EPERM; +} + +int +sock_mknod_noperm(struct inode *dir,struct dentry *dentry,int mode, dev_t dev) +{ + return -EPERM; +} + +#if 0 +void +sock_set_directory() +{ + struct dentry *pentry, *dentry; + + pentry = rcfs_set_magf_byname("listen_aq", (void *)&my_dir_magf[0]); + if (pentry) { + dentry = rcfs_create_internal(pentry, &my_dir_magf[1],0); + if (my_dir_magf[1].i_fop) + dentry->d_inode->i_fop = my_dir_magf[1].i_fop; + RCFS_I(dentry->d_inode)->core = + RCFS_I(pentry->d_inode)->core; + dentry = rcfs_create_internal(pentry, &my_dir_magf[2],0); + if (my_dir_magf[2].i_fop) + dentry->d_inode->i_fop = my_dir_magf[2].i_fop; + RCFS_I(dentry->d_inode)->core = + RCFS_I(pentry->d_inode)->core; + } + else { + printk(KERN_ERR "Could not create /rcfs/listen_aq\n" + "Perhaps /rcfs needs to be mounted\n"); + } +} +#endif + diff --git a/fs/rcfs/super.c b/fs/rcfs/super.c new file mode 100644 index 000000000..d0e78c447 --- /dev/null +++ b/fs/rcfs/super.c @@ -0,0 +1,288 @@ +/* + * fs/rcfs/super.c + * + * Copyright (C) Shailabh Nagar, IBM Corp. 2004 + * Vivek Kashyap, IBM Corp. 2004 + * + * Super block operations for rcfs + * + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 08 Mar 2004 + * Created. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +static kmem_cache_t *rcfs_inode_cachep; + + +inline struct rcfs_inode_info *RCFS_I(struct inode *inode) +{ + return container_of(inode, struct rcfs_inode_info, vfs_inode); +} +EXPORT_SYMBOL(RCFS_I); + + + +static struct inode * +rcfs_alloc_inode(struct super_block *sb) +{ + struct rcfs_inode_info *ri; + ri = (struct rcfs_inode_info *) kmem_cache_alloc(rcfs_inode_cachep, + SLAB_KERNEL); + if (!ri) + return NULL; + ri->name = NULL; + return &ri->vfs_inode; +} + +static void +rcfs_destroy_inode(struct inode *inode) +{ + struct rcfs_inode_info *ri = RCFS_I(inode); + + kfree(ri->name); + kmem_cache_free(rcfs_inode_cachep, RCFS_I(inode)); +} + +static void +rcfs_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +{ + struct rcfs_inode_info *ri = (struct rcfs_inode_info *) foo; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(&ri->vfs_inode); +} + +int +rcfs_init_inodecache(void) +{ + rcfs_inode_cachep = kmem_cache_create("rcfs_inode_cache", + sizeof(struct rcfs_inode_info), + 0, SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT, + rcfs_init_once, NULL); + if (rcfs_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +void rcfs_destroy_inodecache(void) +{ + printk(KERN_WARNING "destroy inodecache was called\n"); + if (kmem_cache_destroy(rcfs_inode_cachep)) + printk(KERN_INFO "rcfs_inode_cache: not all structures were freed\n"); +} + +struct super_operations rcfs_super_ops = +{ + .alloc_inode = rcfs_alloc_inode, + .destroy_inode = rcfs_destroy_inode, + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + + +struct dentry *rcfs_rootde; /* redundant since one can also get it from sb */ +static struct inode *rcfs_root; +static struct rcfs_inode_info *rcfs_rootri; + +static int rcfs_mounted; + +static int rcfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + struct rcfs_inode_info *rootri; + struct ckrm_classtype *clstype; + int i,rc; + + sb->s_fs_info = NULL; + if (rcfs_mounted) { + return -EPERM; + } + rcfs_mounted++; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = RCFS_MAGIC; + sb->s_op = &rcfs_super_ops; + inode = rcfs_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + inode->i_op = &rcfs_rootdir_inode_operations; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + + + // Link inode and core class + rootri = RCFS_I(inode); + rootri->name = kmalloc(strlen(RCFS_ROOT) + 1, GFP_KERNEL); + if (!rootri->name) { + d_delete(root); + iput(inode); + return -ENOMEM; + } + strcpy(rootri->name, RCFS_ROOT); + rootri->core = NULL; + + rcfs_root = inode; + sb->s_fs_info = rcfs_root = inode; + rcfs_rootde = root ; + rcfs_rootri = rootri ; + + // register metatypes + for ( i=0; is_fs_info != rcfs_root) { + generic_shutdown_super(sb); + return; + } + rcfs_mounted--; + + for ( i=0; i < CKRM_MAX_CLASSTYPES; i++) { + + clstype = ckrm_classtypes[i]; + if (clstype == NULL || clstype->rootde == NULL) + continue; + + if ((rc = rcfs_deregister_classtype(clstype))) { + printk(KERN_ERR "Error removing classtype %s\n", + clstype->name); + // return ; // can also choose to stop here + } + } + + // do not remove comment block until ce directory issue resolved + // deregister CE with rcfs + // Check if loaded + // if ce is in one directory /rcfs/ce, + // rcfs_deregister_engine for all classtypes within above + // codebase + // followed by + // rcfs_rmroot here + // if ce in multiple (per-classtype) directories + // call rbce_deregister_engine within ckrm_deregister_classtype + + // following will automatically clear rcfs root entry including its + // rcfs_inode_info + + generic_shutdown_super(sb); + + // printk(KERN_ERR "Removed all entries\n"); +} + + +static struct file_system_type rcfs_fs_type = { + .name = "rcfs", + .get_sb = rcfs_get_sb, + .kill_sb = rcfs_kill_sb, +}; + +struct rcfs_functions my_rcfs_fn = { + .mkroot = rcfs_mkroot, + .rmroot = rcfs_rmroot, + .register_classtype = rcfs_register_classtype, + .deregister_classtype = rcfs_deregister_classtype, +}; + +extern struct rcfs_functions rcfs_fn ; + +static int __init init_rcfs_fs(void) +{ + int ret; + + ret = register_filesystem(&rcfs_fs_type); + if (ret) + goto init_register_err; + + ret = rcfs_init_inodecache(); + if (ret) + goto init_cache_err; + + rcfs_fn = my_rcfs_fn ; + + return ret; + +init_cache_err: + unregister_filesystem(&rcfs_fs_type); +init_register_err: + return ret; +} + +static void __exit exit_rcfs_fs(void) +{ + rcfs_destroy_inodecache(); + unregister_filesystem(&rcfs_fs_type); +} + +module_init(init_rcfs_fs) +module_exit(exit_rcfs_fs) + +MODULE_LICENSE("GPL"); diff --git a/fs/rcfs/tc_magic.c b/fs/rcfs/tc_magic.c new file mode 100644 index 000000000..16864094c --- /dev/null +++ b/fs/rcfs/tc_magic.c @@ -0,0 +1,94 @@ +/* + * fs/rcfs/tc_magic.c + * + * Copyright (C) Shailabh Nagar, IBM Corp. 2004 + * (C) Vivek Kashyap, IBM Corp. 2004 + * (C) Chandra Seetharaman, IBM Corp. 2004 + * (C) Hubertus Franke, IBM Corp. 2004 + * + * + * define magic fileops for taskclass classtype + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 23 Apr 2004 + * Created. + * + */ + +#include +#include + + +/******************************************************************************* + * Taskclass general + * + * Define structures for taskclass root directory and its magic files + * In taskclasses, there is one set of magic files, created automatically under + * the taskclass root (upon classtype registration) and each directory (class) + * created subsequently. However, classtypes can also choose to have different + * sets of magic files created under their root and other directories under root + * using their mkdir function. RCFS only provides helper functions for creating + * the root directory and its magic files + * + *******************************************************************************/ + +#define TC_FILE_MODE (S_IFREG | S_IRUGO | S_IWUSR) + +#define NR_TCROOTMF 6 +struct rcfs_magf tc_rootdesc[NR_TCROOTMF] = { + /* First entry must be root */ + { +// .name = should not be set, copy from classtype name + .mode = RCFS_DEFAULT_DIR_MODE, + .i_op = &rcfs_dir_inode_operations, + .i_fop = &simple_dir_operations, + }, + /* Rest are root's magic files */ + { + .name = "target", + .mode = TC_FILE_MODE, + .i_fop = &target_fileops, + .i_op = &rcfs_file_inode_operations, + }, + { + .name = "config", + .mode = TC_FILE_MODE, + .i_fop = &config_fileops, + .i_op = &rcfs_file_inode_operations, + }, + { + .name = "members", + .mode = TC_FILE_MODE, + .i_fop = &members_fileops, + .i_op = &rcfs_file_inode_operations, + }, + { + .name = "stats", + .mode = TC_FILE_MODE, + .i_fop = &stats_fileops, + .i_op = &rcfs_file_inode_operations, + }, + { + .name = "shares", + .mode = TC_FILE_MODE, + .i_fop = &shares_fileops, + .i_op = &rcfs_file_inode_operations, + }, +}; + +struct rcfs_mfdesc tc_mfdesc = { + .rootmf = tc_rootdesc, + .rootmflen = NR_TCROOTMF, +}; + + diff --git a/fs/read_write.c b/fs/read_write.c index f765a22b4..0515f7bb2 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -144,7 +144,6 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) bad: return retval; } -EXPORT_SYMBOL_GPL(sys_lseek); #ifdef __ARCH_WANT_SYS_LLSEEK asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, @@ -283,7 +282,6 @@ asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) return ret; } -EXPORT_SYMBOL_GPL(sys_read); asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) { diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 68050af43..402ba643f 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -17,6 +17,7 @@ #include #include #include +#include extern int reiserfs_default_io_size; /* default io size devuned in super.c */ @@ -1010,6 +1011,8 @@ static void init_inode (struct inode * inode, struct path * path) struct buffer_head * bh; struct item_head * ih; __u32 rdev; + uid_t uid; + gid_t gid; //int version = ITEM_VERSION_1; bh = PATH_PLAST_BUFFER (path); @@ -1033,12 +1036,13 @@ static void init_inode (struct inode * inode, struct path * path) struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); unsigned long blocks; + uid = sd_v1_uid(sd); + gid = sd_v1_gid(sd); + set_inode_item_key_version (inode, KEY_FORMAT_3_5); set_inode_sd_version (inode, STAT_DATA_V1); inode->i_mode = sd_v1_mode(sd); inode->i_nlink = sd_v1_nlink(sd); - inode->i_uid = sd_v1_uid(sd); - inode->i_gid = sd_v1_gid(sd); inode->i_size = sd_v1_size(sd); inode->i_atime.tv_sec = sd_v1_atime(sd); inode->i_mtime.tv_sec = sd_v1_mtime(sd); @@ -1078,11 +1082,12 @@ static void init_inode (struct inode * inode, struct path * path) // (directories and symlinks) struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih); + uid = sd_v2_uid(sd); + gid = sd_v2_gid(sd); + inode->i_mode = sd_v2_mode(sd); inode->i_nlink = sd_v2_nlink(sd); - inode->i_uid = sd_v2_uid(sd); inode->i_size = sd_v2_size(sd); - inode->i_gid = sd_v2_gid(sd); inode->i_mtime.tv_sec = sd_v2_mtime(sd); inode->i_atime.tv_sec = sd_v2_atime(sd); inode->i_ctime.tv_sec = sd_v2_ctime(sd); @@ -1109,6 +1114,9 @@ static void init_inode (struct inode * inode, struct path * path) REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd ); sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode ); } + inode->i_uid = INOXID_UID(uid, gid); + inode->i_gid = INOXID_GID(uid, gid); + inode->i_xid = INOXID_XID(uid, gid, 0); pathrelse (path); if (S_ISREG (inode->i_mode)) { @@ -1133,13 +1141,15 @@ static void init_inode (struct inode * inode, struct path * path) static void inode2sd (void * sd, struct inode * inode, loff_t size) { struct stat_data * sd_v2 = (struct stat_data *)sd; + uid_t uid = XIDINO_UID(inode->i_uid, inode->i_xid); + gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid); __u16 flags; + set_sd_v2_uid(sd_v2, uid ); + set_sd_v2_gid(sd_v2, gid ); set_sd_v2_mode(sd_v2, inode->i_mode ); set_sd_v2_nlink(sd_v2, inode->i_nlink ); - set_sd_v2_uid(sd_v2, inode->i_uid ); set_sd_v2_size(sd_v2, size ); - set_sd_v2_gid(sd_v2, inode->i_gid ); set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec ); set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec ); set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec ); @@ -2429,6 +2439,14 @@ void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode ) inode -> i_flags |= S_IMMUTABLE; else inode -> i_flags &= ~S_IMMUTABLE; + if( sd_attrs & REISERFS_IUNLINK_FL ) + inode -> i_flags |= S_IUNLINK; + else + inode -> i_flags &= ~S_IUNLINK; + if( sd_attrs & REISERFS_BARRIER_FL ) + inode -> i_flags |= S_BARRIER; + else + inode -> i_flags &= ~S_BARRIER; if( sd_attrs & REISERFS_APPEND_FL ) inode -> i_flags |= S_APPEND; else @@ -2451,6 +2469,14 @@ void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ) *sd_attrs |= REISERFS_IMMUTABLE_FL; else *sd_attrs &= ~REISERFS_IMMUTABLE_FL; + if( inode -> i_flags & S_IUNLINK ) + *sd_attrs |= REISERFS_IUNLINK_FL; + else + *sd_attrs &= ~REISERFS_IUNLINK_FL; + if( inode -> i_flags & S_BARRIER ) + *sd_attrs |= REISERFS_BARRIER_FL; + else + *sd_attrs &= ~REISERFS_BARRIER_FL; if( inode -> i_flags & S_SYNC ) *sd_attrs |= REISERFS_SYNC_FL; else @@ -2611,11 +2637,36 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); } +int reiserfs_setattr_flags(struct inode *inode, unsigned int flags) +{ + unsigned int oldflags, newflags; + + oldflags = REISERFS_I(inode)->i_flags; + newflags = oldflags & ~(REISERFS_IMMUTABLE_FL | + REISERFS_IUNLINK_FL | REISERFS_BARRIER_FL); + if (flags & ATTR_FLAG_IMMUTABLE) + newflags |= REISERFS_IMMUTABLE_FL; + if (flags & ATTR_FLAG_IUNLINK) + newflags |= REISERFS_IUNLINK_FL; + if (flags & ATTR_FLAG_BARRIER) + newflags |= REISERFS_BARRIER_FL; + + if (oldflags ^ newflags) { + REISERFS_I(inode)->i_flags = newflags; + inode->i_ctime = CURRENT_TIME; + } + return 0; +} + int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode ; int error ; unsigned int ia_valid = attr->ia_valid; + reiserfs_write_lock(inode->i_sb); + if (S_ISDIR(inode->i_mode)) + goto is_dir; + if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate @@ -2648,7 +2699,12 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { goto out; } + is_dir: error = inode_change_ok(inode, attr) ; + + if (!error && attr->ia_valid & ATTR_ATTR_FLAG) + reiserfs_setattr_flags(inode, attr->ia_attr_flags); + if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 7f2fba5e1..21d7c8310 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -20,7 +20,7 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { - unsigned int flags; + unsigned int flags, oldflags; switch (cmd) { case REISERFS_IOC_UNPACK: @@ -36,6 +36,7 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case REISERFS_IOC_GETFLAGS: flags = REISERFS_I(inode) -> i_attrs; i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags ); + flags &= REISERFS_FL_USER_VISIBLE; return put_user(flags, (int __user *) arg); case REISERFS_IOC_SETFLAGS: { if (IS_RDONLY(inode)) @@ -47,8 +48,10 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if (get_user(flags, (int __user *) arg)) return -EFAULT; - if ( ( ( flags ^ REISERFS_I(inode) -> i_attrs) & ( REISERFS_IMMUTABLE_FL | REISERFS_APPEND_FL)) && - !capable( CAP_LINUX_IMMUTABLE ) ) + oldflags = REISERFS_I(inode) -> i_attrs; + if ( (oldflags & REISERFS_IMMUTABLE_FL) || ( ( (flags ^ oldflags) & + (REISERFS_IMMUTABLE_FL | REISERFS_IUNLINK_FL | REISERFS_APPEND_FL)) && + !capable( CAP_LINUX_IMMUTABLE ) ) ) return -EPERM; if( ( flags & REISERFS_NOTAIL_FL ) && @@ -59,6 +62,9 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if( result ) return result; } + + flags = flags & REISERFS_FL_USER_MODIFYABLE; + flags |= oldflags & ~REISERFS_FL_USER_MODIFYABLE; sd_attrs_to_i_attrs( flags, inode ); REISERFS_I(inode) -> i_attrs = flags; inode->i_ctime = CURRENT_TIME; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 52d88ae28..48eb79861 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1389,8 +1389,9 @@ struct inode_operations reiserfs_dir_inode_operations = { * stuff added */ struct inode_operations reiserfs_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setattr = reiserfs_setattr, .setxattr = reiserfs_setxattr, .getxattr = reiserfs_getxattr, diff --git a/fs/relayfs/Makefile b/fs/relayfs/Makefile new file mode 100644 index 000000000..09f098a10 --- /dev/null +++ b/fs/relayfs/Makefile @@ -0,0 +1,8 @@ +# +# relayfs Makefile +# + +obj-$(CONFIG_RELAYFS_FS) += relayfs.o + +relayfs-y := relay.o relay_lockless.o relay_locking.o inode.o resize.o +relayfs-$(CONFIG_KLOG_CHANNEL) += klog.o diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c new file mode 100644 index 000000000..6e8736015 --- /dev/null +++ b/fs/relayfs/inode.c @@ -0,0 +1,629 @@ +/* + * VFS-related code for RelayFS, a high-speed data relay filesystem. + * + * Copyright (C) 2003 - Tom Zanussi , IBM Corp + * Copyright (C) 2003 - Karim Yaghmour + * + * Based on ramfs, Copyright (C) 2002 - Linus Torvalds + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RELAYFS_MAGIC 0x26F82121 + +static struct super_operations relayfs_ops; +static struct address_space_operations relayfs_aops; +static struct inode_operations relayfs_file_inode_operations; +static struct file_operations relayfs_file_operations; +static struct inode_operations relayfs_dir_inode_operations; + +static struct vfsmount * relayfs_mount; +static int relayfs_mount_count; + +static struct backing_dev_info relayfs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; + +static struct inode * +relayfs_get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode * inode; + + inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_mapping->a_ops = &relayfs_aops; + inode->i_mapping->backing_dev_info = &relayfs_backing_dev_info; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_op = &relayfs_file_inode_operations; + inode->i_fop = &relayfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &relayfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +/* + * File creation. Allocate an inode, and we're done.. + */ +/* SMP-safe */ +static int +relayfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode * inode; + int error = -ENOSPC; + + inode = relayfs_get_inode(dir->i_sb, mode, dev); + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int +relayfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + int retval; + + retval = relayfs_mknod(dir, dentry, mode | S_IFDIR, 0); + + if (!retval) + dir->i_nlink++; + return retval; +} + +static int +relayfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +{ + return relayfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int +relayfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = relayfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} + +/** + * relayfs_create_entry - create a relayfs directory or file + * @name: the name of the file to create + * @parent: parent directory + * @dentry: result dentry + * @entry_type: type of file to create (S_IFREG, S_IFDIR) + * @mode: mode + * @data: data to associate with the file + * + * Creates a file or directory with the specifed permissions. + */ +static int +relayfs_create_entry(const char * name, struct dentry * parent, struct dentry **dentry, int entry_type, int mode, void * data) +{ + struct qstr qname; + struct dentry * d; + + int error = 0; + + error = simple_pin_fs("relayfs", &relayfs_mount, &relayfs_mount_count); + if (error) { + printk(KERN_ERR "Couldn't mount relayfs: errcode %d\n", error); + return error; + } + + qname.name = name; + qname.len = strlen(name); + qname.hash = full_name_hash(name, qname.len); + + if (parent == NULL) + if (relayfs_mount && relayfs_mount->mnt_sb) + parent = relayfs_mount->mnt_sb->s_root; + + if (parent == NULL) { + simple_release_fs(&relayfs_mount, &relayfs_mount_count); + return -EINVAL; + } + + parent = dget(parent); + down(&parent->d_inode->i_sem); + d = lookup_hash(&qname, parent); + if (IS_ERR(d)) { + error = PTR_ERR(d); + goto release_mount; + } + + if (d->d_inode) { + error = -EEXIST; + goto release_mount; + } + + if (entry_type == S_IFREG) + error = relayfs_create(parent->d_inode, d, entry_type | mode, NULL); + else + error = relayfs_mkdir(parent->d_inode, d, entry_type | mode); + if (error) + goto release_mount; + + if ((entry_type == S_IFREG) && data) { + d->d_inode->u.generic_ip = data; + goto exit; /* don't release mount for regular files */ + } + +release_mount: + simple_release_fs(&relayfs_mount, &relayfs_mount_count); +exit: + *dentry = d; + up(&parent->d_inode->i_sem); + dput(parent); + + return error; +} + +/** + * relayfs_create_file - create a file in the relay filesystem + * @name: the name of the file to create + * @parent: parent directory + * @dentry: result dentry + * @data: data to associate with the file + * @mode: mode, if not specied the default perms are used + * + * The file will be created user rw on behalf of current user. + */ +int +relayfs_create_file(const char * name, struct dentry * parent, struct dentry **dentry, void * data, int mode) +{ + if (!mode) + mode = S_IRUSR | S_IWUSR; + + return relayfs_create_entry(name, parent, dentry, S_IFREG, + mode, data); +} + +/** + * relayfs_create_dir - create a directory in the relay filesystem + * @name: the name of the directory to create + * @parent: parent directory + * @dentry: result dentry + * + * The directory will be created world rwx on behalf of current user. + */ +int +relayfs_create_dir(const char * name, struct dentry * parent, struct dentry **dentry) +{ + return relayfs_create_entry(name, parent, dentry, S_IFDIR, + S_IRWXU | S_IRUGO | S_IXUGO, NULL); +} + +/** + * relayfs_remove_file - remove a file in the relay filesystem + * @dentry: file dentry + * + * Remove a file previously created by relayfs_create_file. + */ +int +relayfs_remove_file(struct dentry *dentry) +{ + struct dentry *parent; + int is_reg; + + parent = dentry->d_parent; + if (parent == NULL) + return -EINVAL; + + is_reg = S_ISREG(dentry->d_inode->i_mode); + + parent = dget(parent); + down(&parent->d_inode->i_sem); + if (dentry->d_inode) { + simple_unlink(parent->d_inode, dentry); + d_delete(dentry); + } + dput(dentry); + up(&parent->d_inode->i_sem); + dput(parent); + + if(is_reg) + simple_release_fs(&relayfs_mount, &relayfs_mount_count); + + return 0; +} + +/** + * relayfs_open - open file op for relayfs files + * @inode: the inode + * @filp: the file + * + * Associates the channel with the file, and increments the + * channel refcount. Reads will be 'auto-consuming'. + */ +int +relayfs_open(struct inode *inode, struct file *filp) +{ + struct rchan *rchan; + struct rchan_reader *reader; + int retval = 0; + + if (inode->u.generic_ip) { + rchan = (struct rchan *)inode->u.generic_ip; + if (rchan == NULL) + return -EACCES; + reader = __add_rchan_reader(rchan, filp, 1, 0); + if (reader == NULL) + return -ENOMEM; + filp->private_data = reader; + retval = rchan->callbacks->fileop_notify(rchan->id, filp, + RELAY_FILE_OPEN); + if (retval == 0) + /* Inc relay channel refcount for file */ + rchan_get(rchan->id); + else { + __remove_rchan_reader(reader); + retval = -EPERM; + } + } + + return retval; +} + +/** + * relayfs_mmap - mmap file op for relayfs files + * @filp: the file + * @vma: the vma describing what to map + * + * Calls upon relay_mmap_buffer to map the file into user space. + */ +int +relayfs_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct rchan *rchan; + + rchan = ((struct rchan_reader *)filp->private_data)->rchan; + + return __relay_mmap_buffer(rchan, vma); +} + +/** + * relayfs_file_read - read file op for relayfs files + * @filp: the file + * @buf: user buf to read into + * @count: bytes requested + * @offset: offset into file + * + * Reads count bytes from the channel, or as much as is available within + * the sub-buffer currently being read. Reads are 'auto-consuming'. + * See relay_read() for details. + * + * Returns bytes read on success, 0 or -EAGAIN if nothing available, + * negative otherwise. + */ +ssize_t +relayfs_file_read(struct file *filp, char * buf, size_t count, loff_t *offset) +{ + size_t read_count; + struct rchan_reader *reader; + u32 dummy; /* all VFS readers are auto-consuming */ + + if (offset != &filp->f_pos) /* pread, seeking not supported */ + return -ESPIPE; + + if (count == 0) + return 0; + + reader = (struct rchan_reader *)filp->private_data; + read_count = relay_read(reader, buf, count, + filp->f_flags & (O_NDELAY | O_NONBLOCK) ? 0 : 1, &dummy); + + return read_count; +} + +/** + * relayfs_file_write - write file op for relayfs files + * @filp: the file + * @buf: user buf to write from + * @count: bytes to write + * @offset: offset into file + * + * Reserves a slot in the relay buffer and writes count bytes + * into it. The current limit for a single write is 2 pages + * worth. The user_deliver() channel callback will be invoked on + * + * Returns bytes written on success, 0 or -EAGAIN if nothing available, + * negative otherwise. + */ +ssize_t +relayfs_file_write(struct file *filp, const char *buf, size_t count, loff_t *offset) +{ + int write_count; + char * write_buf; + struct rchan *rchan; + int err = 0; + void *wrote_pos; + struct rchan_reader *reader; + + reader = (struct rchan_reader *)filp->private_data; + if (reader == NULL) + return -EPERM; + + rchan = reader->rchan; + if (rchan == NULL) + return -EPERM; + + if (count == 0) + return 0; + + /* Change this if need to write more than 2 pages at once */ + if (count > 2 * PAGE_SIZE) + return -EINVAL; + + write_buf = (char *)__get_free_pages(GFP_KERNEL, 1); + if (write_buf == NULL) + return -ENOMEM; + + if (copy_from_user(write_buf, buf, count)) + return -EFAULT; + + if (filp->f_flags & (O_NDELAY | O_NONBLOCK)) { + write_count = relay_write(rchan->id, write_buf, count, -1, &wrote_pos); + if (write_count == 0) + return -EAGAIN; + } else { + err = wait_event_interruptible(rchan->write_wait, + (write_count = relay_write(rchan->id, write_buf, count, -1, &wrote_pos))); + if (err) + return err; + } + + free_pages((unsigned long)write_buf, 1); + + rchan->callbacks->user_deliver(rchan->id, wrote_pos, write_count); + + return write_count; +} + +/** + * relayfs_ioctl - ioctl file op for relayfs files + * @inode: the inode + * @filp: the file + * @cmd: the command + * @arg: command arg + * + * Passes the specified cmd/arg to the kernel client. arg may be a + * pointer to user-space data, in which case the kernel client is + * responsible for copying the data to/from user space appropriately. + * The kernel client is also responsible for returning a meaningful + * return value for ioctl calls. + * + * Returns result of relay channel callback, -EPERM if unsuccessful. + */ +int +relayfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct rchan *rchan; + struct rchan_reader *reader; + + reader = (struct rchan_reader *)filp->private_data; + if (reader == NULL) + return -EPERM; + + rchan = reader->rchan; + if (rchan == NULL) + return -EPERM; + + return rchan->callbacks->ioctl(rchan->id, cmd, arg); +} + +/** + * relayfs_poll - poll file op for relayfs files + * @filp: the file + * @wait: poll table + * + * Poll implemention. + */ +static unsigned int +relayfs_poll(struct file *filp, poll_table *wait) +{ + struct rchan_reader *reader; + unsigned int mask = 0; + + reader = (struct rchan_reader *)filp->private_data; + + if (reader->rchan->finalized) + return POLLERR; + + if (filp->f_mode & FMODE_READ) { + poll_wait(filp, &reader->rchan->read_wait, wait); + if (!rchan_empty(reader)) + mask |= POLLIN | POLLRDNORM; + } + + if (filp->f_mode & FMODE_WRITE) { + poll_wait(filp, &reader->rchan->write_wait, wait); + if (!rchan_full(reader)) + mask |= POLLOUT | POLLWRNORM; + } + + return mask; +} + +/** + * relayfs_release - release file op for relayfs files + * @inode: the inode + * @filp: the file + * + * Decrements the channel refcount, as the filesystem is + * no longer using it. + */ +int +relayfs_release(struct inode *inode, struct file *filp) +{ + struct rchan_reader *reader; + struct rchan *rchan; + + reader = (struct rchan_reader *)filp->private_data; + if (reader == NULL || reader->rchan == NULL) + return 0; + rchan = reader->rchan; + + rchan->callbacks->fileop_notify(reader->rchan->id, filp, + RELAY_FILE_CLOSE); + __remove_rchan_reader(reader); + /* The channel is no longer in use as far as this file is concerned */ + rchan_put(rchan); + + return 0; +} + +static struct address_space_operations relayfs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, + .commit_write = simple_commit_write +}; + +static struct file_operations relayfs_file_operations = { + .open = relayfs_open, + .read = relayfs_file_read, + .write = relayfs_file_write, + .ioctl = relayfs_ioctl, + .poll = relayfs_poll, + .mmap = relayfs_mmap, + .fsync = simple_sync_file, + .release = relayfs_release, +}; + +static struct inode_operations relayfs_file_inode_operations = { + .getattr = simple_getattr, +}; + +static struct inode_operations relayfs_dir_inode_operations = { + .create = relayfs_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = simple_unlink, + .symlink = relayfs_symlink, + .mkdir = relayfs_mkdir, + .rmdir = simple_rmdir, + .mknod = relayfs_mknod, + .rename = simple_rename, +}; + +static struct super_operations relayfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static int +relayfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = RELAYFS_MAGIC; + sb->s_op = &relayfs_ops; + inode = relayfs_get_inode(sb, S_IFDIR | 0755, 0); + + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + + return 0; +} + +static struct super_block * +relayfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, relayfs_fill_super); +} + +static struct file_system_type relayfs_fs_type = { + .owner = THIS_MODULE, + .name = "relayfs", + .get_sb = relayfs_get_sb, + .kill_sb = kill_litter_super, +}; + +static int __init +init_relayfs_fs(void) +{ + int err = register_filesystem(&relayfs_fs_type); +#ifdef CONFIG_KLOG_CHANNEL + if (!err) + create_klog_channel(); +#endif + return err; +} + +static void __exit +exit_relayfs_fs(void) +{ +#ifdef CONFIG_KLOG_CHANNEL + remove_klog_channel(); +#endif + unregister_filesystem(&relayfs_fs_type); +} + +module_init(init_relayfs_fs) +module_exit(exit_relayfs_fs) + +MODULE_AUTHOR("Tom Zanussi and Karim Yaghmour "); +MODULE_DESCRIPTION("Relay Filesystem"); +MODULE_LICENSE("GPL"); + diff --git a/fs/relayfs/klog.c b/fs/relayfs/klog.c new file mode 100644 index 000000000..3f2d31da4 --- /dev/null +++ b/fs/relayfs/klog.c @@ -0,0 +1,206 @@ +/* + * KLOG Generic Logging facility built upon the relayfs infrastructure + * + * Authors: Hubertus Franke (frankeh@us.ibm.com) + * Tom Zanussi (zanussi@us.ibm.com) + * + * Please direct all questions/comments to zanussi@us.ibm.com + * + * Copyright (C) 2003, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* klog channel id */ +static int klog_channel = -1; + +/* maximum size of klog formatting buffer beyond which truncation will occur */ +#define KLOG_BUF_SIZE (512) +/* per-cpu klog formatting buffer */ +static char buf[NR_CPUS][KLOG_BUF_SIZE]; + +/* + * klog_enabled determines whether klog()/klog_raw() actually do write + * to the klog channel at any given time. If klog_enabled == 1 they do, + * otherwise they don't. Settable using sysctl fs.relayfs.klog_enabled. + */ +#ifdef CONFIG_KLOG_CHANNEL_AUTOENABLE +static int klog_enabled = 1; +#else +static int klog_enabled = 0; +#endif + +/** + * klog - write a formatted string into the klog channel + * @fmt: format string + * + * Returns number of bytes written, negative number on failure. + */ +int klog(const char *fmt, ...) +{ + va_list args; + int len, err; + char *cbuf; + unsigned long flags; + + if (!klog_enabled || klog_channel < 0) + return 0; + + local_irq_save(flags); + cbuf = buf[smp_processor_id()]; + + va_start(args, fmt); + len = vsnprintf(cbuf, KLOG_BUF_SIZE, fmt, args); + va_end(args); + + err = relay_write(klog_channel, cbuf, len, -1, NULL); + local_irq_restore(flags); + + return err; +} + +/** + * klog_raw - directly write into the klog channel + * @buf: buffer containing data to write + * @len: # bytes to write + * + * Returns number of bytes written, negative number on failure. + */ +int klog_raw(const char *buf,int len) +{ + int err = 0; + + if (klog_enabled && klog_channel >= 0) + err = relay_write(klog_channel, buf, len, -1, NULL); + + return err; +} + +/** + * relayfs sysctl data + * + * Only sys/fs/relayfs/klog_enabled for now. + */ +#define CTL_ENABLE_KLOG 100 +#define CTL_RELAYFS 100 + +static struct ctl_table_header *relayfs_ctl_table_header; + +static struct ctl_table relayfs_table[] = +{ + { + .ctl_name = CTL_ENABLE_KLOG, + .procname = "klog_enabled", + .data = &klog_enabled, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + 0 + } +}; + +static struct ctl_table relayfs_dir_table[] = +{ + { + .ctl_name = CTL_RELAYFS, + .procname = "relayfs", + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = relayfs_table, + }, + { + 0 + } +}; + +static struct ctl_table relayfs_root_table[] = +{ + { + .ctl_name = CTL_FS, + .procname = "fs", + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = relayfs_dir_table, + }, + { + 0 + } +}; + +/** + * create_klog_channel - creates channel /mnt/relay/klog + * + * Returns channel id on success, negative otherwise. + */ +int +create_klog_channel(void) +{ + u32 bufsize, nbufs; + u32 channel_flags; + + channel_flags = RELAY_DELIVERY_PACKET | RELAY_USAGE_GLOBAL; + channel_flags |= RELAY_SCHEME_ANY | RELAY_TIMESTAMP_ANY; + + bufsize = 1 << (CONFIG_KLOG_CHANNEL_SHIFT - 2); + nbufs = 4; + + klog_channel = relay_open("klog", + bufsize, + nbufs, + channel_flags, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + 0); + + if (klog_channel < 0) + printk("klog channel creation failed, errcode: %d\n", klog_channel); + else { + printk("klog channel created (%u bytes)\n", 1 << CONFIG_KLOG_CHANNEL_SHIFT); + relayfs_ctl_table_header = register_sysctl_table(relayfs_root_table, 1); + } + + return klog_channel; +} + +/** + * remove_klog_channel - destroys channel /mnt/relay/klog + * + * Returns 0, negative otherwise. + */ +int +remove_klog_channel(void) +{ + if (relayfs_ctl_table_header) + unregister_sysctl_table(relayfs_ctl_table_header); + + return relay_close(klog_channel); +} + +EXPORT_SYMBOL(klog); +EXPORT_SYMBOL(klog_raw); + diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c new file mode 100644 index 000000000..11f4636ce --- /dev/null +++ b/fs/relayfs/relay.c @@ -0,0 +1,1911 @@ +/* + * Public API and common code for RelayFS. + * + * Please see Documentation/filesystems/relayfs.txt for API description. + * + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "relay_lockless.h" +#include "relay_locking.h" +#include "resize.h" + +/* Relay channel table, indexed by channel id */ +static struct rchan * rchan_table[RELAY_MAX_CHANNELS]; +static rwlock_t rchan_table_lock = RW_LOCK_UNLOCKED; + +/* Relay operation structs, one per scheme */ +static struct relay_ops lockless_ops = { + .reserve = lockless_reserve, + .commit = lockless_commit, + .get_offset = lockless_get_offset, + .finalize = lockless_finalize, + .reset = lockless_reset, + .reset_index = lockless_reset_index +}; + +static struct relay_ops locking_ops = { + .reserve = locking_reserve, + .commit = locking_commit, + .get_offset = locking_get_offset, + .finalize = locking_finalize, + .reset = locking_reset, + .reset_index = locking_reset_index +}; + +/* + * Low-level relayfs kernel API. These functions should not normally be + * used by clients. See high-level kernel API below. + */ + +/** + * rchan_get - get channel associated with id, incrementing refcount + * @rchan_id: the channel id + * + * Returns channel if successful, NULL otherwise. + */ +struct rchan * +rchan_get(int rchan_id) +{ + struct rchan *rchan; + + if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS)) + return NULL; + + read_lock(&rchan_table_lock); + rchan = rchan_table[rchan_id]; + if (rchan) + atomic_inc(&rchan->refcount); + read_unlock(&rchan_table_lock); + + return rchan; +} + +/** + * clear_readers - clear non-VFS readers + * @rchan: the channel + * + * Clear the channel pointers of all non-VFS readers open on the channel. + */ +static inline void +clear_readers(struct rchan *rchan) +{ + struct list_head *p; + struct rchan_reader *reader; + + read_lock(&rchan->open_readers_lock); + list_for_each(p, &rchan->open_readers) { + reader = list_entry(p, struct rchan_reader, list); + if (!reader->vfs_reader) + reader->rchan = NULL; + } + read_unlock(&rchan->open_readers_lock); +} + +/** + * rchan_alloc_id - reserve a channel id and store associated channel + * @rchan: the channel + * + * Returns channel id if successful, -1 otherwise. + */ +static inline int +rchan_alloc_id(struct rchan *rchan) +{ + int i; + int rchan_id = -1; + + if (rchan == NULL) + return -1; + + write_lock(&rchan_table_lock); + for (i = 0; i < RELAY_MAX_CHANNELS; i++) { + if (rchan_table[i] == NULL) { + rchan_table[i] = rchan; + rchan_id = rchan->id = i; + break; + } + } + if (rchan_id != -1) + atomic_inc(&rchan->refcount); + write_unlock(&rchan_table_lock); + + return rchan_id; +} + +/** + * rchan_free_id - revoke a channel id and remove associated channel + * @rchan_id: the channel id + */ +static inline void +rchan_free_id(int rchan_id) +{ + struct rchan *rchan; + + if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS)) + return; + + write_lock(&rchan_table_lock); + rchan = rchan_table[rchan_id]; + rchan_table[rchan_id] = NULL; + write_unlock(&rchan_table_lock); +} + +/** + * rchan_destroy_buf - destroy the current channel buffer + * @rchan: the channel + */ +static inline void +rchan_destroy_buf(struct rchan *rchan) +{ + if (rchan->buf && !rchan->init_buf) + free_rchan_buf(rchan->buf, + rchan->buf_page_array, + rchan->buf_page_count); +} + +/** + * relay_release - perform end-of-buffer processing for last buffer + * @rchan: the channel + * + * Returns 0 if successful, negative otherwise. + * + * Releases the channel buffer, destroys the channel, and removes the + * relay file from the relayfs filesystem. Should only be called from + * rchan_put(). If we're here, it means by definition refcount is 0. + */ +static int +relay_release(struct rchan *rchan) +{ + if (rchan == NULL) + return -EBADF; + + rchan_destroy_buf(rchan); + rchan_free_id(rchan->id); + relayfs_remove_file(rchan->dentry); + clear_readers(rchan); + kfree(rchan); + + return 0; +} + +/** + * rchan_get - decrement channel refcount, releasing it if 0 + * @rchan: the channel + * + * If the refcount reaches 0, the channel will be destroyed. + */ +void +rchan_put(struct rchan *rchan) +{ + if (atomic_dec_and_test(&rchan->refcount)) + relay_release(rchan); +} + +/** + * relay_reserve - reserve a slot in the channel buffer + * @rchan: the channel + * @len: the length of the slot to reserve + * @td: the time delta between buffer start and current write, or TSC + * @err: receives the result flags + * @interrupting: 1 if interrupting previous, used only in locking scheme + * + * Returns pointer to the beginning of the reserved slot, NULL if error. + * + * The errcode value contains the result flags and is an ORed combination + * of the following: + * + * RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred + * RELAY_EVENT_DISCARD_NONE - event should not be discarded + * RELAY_BUFFER_SWITCH - buffer switch occurred + * RELAY_EVENT_DISCARD - event should be discarded (all buffers are full) + * RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer + * + * buffer_start and buffer_end callbacks are triggered at this point + * if applicable. + */ +char * +relay_reserve(struct rchan *rchan, + u32 len, + struct timeval *ts, + u32 *td, + int *err, + int *interrupting) +{ + if (rchan == NULL) + return NULL; + + *interrupting = 0; + + return rchan->relay_ops->reserve(rchan, len, ts, td, err, interrupting); +} + + +/** + * wakeup_readers - wake up VFS readers waiting on a channel + * @private: the channel + * + * This is the work function used to defer reader waking. The + * reason waking is deferred is that calling directly from commit + * causes problems if you're writing from say the scheduler. + */ +static void +wakeup_readers(void *private) +{ + struct rchan *rchan = (struct rchan *)private; + + wake_up_interruptible(&rchan->read_wait); +} + + +/** + * relay_commit - commit a reserved slot in the buffer + * @rchan: the channel + * @from: commit the length starting here + * @len: length committed + * @interrupting: 1 if interrupting previous, used only in locking scheme + * + * After the write into the reserved buffer has been complted, this + * function must be called in order for the relay to determine whether + * buffers are complete and to wake up VFS readers. + * + * delivery callback is triggered at this point if applicable. + */ +void +relay_commit(struct rchan *rchan, + char *from, + u32 len, + int reserve_code, + int interrupting) +{ + int deliver; + + if (rchan == NULL) + return; + + deliver = packet_delivery(rchan) || + (reserve_code & RELAY_BUFFER_SWITCH); + + rchan->relay_ops->commit(rchan, from, len, deliver, interrupting); + + /* The params are always the same, so no worry about re-queuing */ + if (deliver && waitqueue_active(&rchan->read_wait)) { + PREPARE_WORK(&rchan->wake_readers, wakeup_readers, rchan); + schedule_delayed_work(&rchan->wake_readers, 1); + } +} + +/** + * relay_get_offset - get current and max channel buffer offsets + * @rchan: the channel + * @max_offset: maximum channel offset + * + * Returns the current and maximum channel buffer offsets. + */ +u32 +relay_get_offset(struct rchan *rchan, u32 *max_offset) +{ + return rchan->relay_ops->get_offset(rchan, max_offset); +} + +/** + * reset_index - try once to reset the current channel index + * @rchan: the channel + * @old_index: the index read before reset + * + * Attempts to reset the channel index to 0. It tries once, and + * if it fails, returns negative, 0 otherwise. + */ +int +reset_index(struct rchan *rchan, u32 old_index) +{ + return rchan->relay_ops->reset_index(rchan, old_index); +} + +/* + * close() vm_op implementation for relayfs file mapping. + */ +static void +relay_file_mmap_close(struct vm_area_struct *vma) +{ + struct file *filp = vma->vm_file; + struct rchan_reader *reader; + struct rchan *rchan; + + reader = (struct rchan_reader *)filp->private_data; + rchan = reader->rchan; + + atomic_dec(&rchan->mapped); + + rchan->callbacks->fileop_notify(reader->rchan->id, filp, + RELAY_FILE_UNMAP); +} + +/* + * vm_ops for relay file mappings. + */ +static struct vm_operations_struct relay_file_mmap_ops = { + .close = relay_file_mmap_close +}; + +/* \begin{Code inspired from BTTV driver} */ +static inline unsigned long +kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *) adr)); + kva |= adr & (PAGE_SIZE - 1); + ret = __pa(kva); + return ret; +} + +static int +relay_mmap_region(struct vm_area_struct *vma, + const char *adr, + const char *start_pos, + unsigned long size) +{ + unsigned long start = (unsigned long) adr; + unsigned long page, pos; + + pos = (unsigned long) start_pos; + + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return 0; +} +/* \end{Code inspired from BTTV driver} */ + +/** + * relay_mmap_buffer: - mmap buffer to process address space + * @rchan_id: relay channel id + * @vma: vm_area_struct describing memory to be mapped + * + * Returns: + * 0 if ok + * -EAGAIN, when remap failed + * -EINVAL, invalid requested length + * + * Caller should already have grabbed mmap_sem. + */ +int +__relay_mmap_buffer(struct rchan *rchan, + struct vm_area_struct *vma) +{ + int err = 0; + unsigned long length = vma->vm_end - vma->vm_start; + struct file *filp = vma->vm_file; + + if (rchan == NULL) { + err = -EBADF; + goto exit; + } + + if (rchan->init_buf) { + err = -EPERM; + goto exit; + } + + if (length != (unsigned long)rchan->alloc_size) { + err = -EINVAL; + goto exit; + } + + err = relay_mmap_region(vma, + (char *)vma->vm_start, + rchan->buf, + rchan->alloc_size); + + if (err == 0) { + vma->vm_ops = &relay_file_mmap_ops; + err = rchan->callbacks->fileop_notify(rchan->id, filp, + RELAY_FILE_MAP); + if (err == 0) + atomic_inc(&rchan->mapped); + } +exit: + return err; +} + +/* + * High-level relayfs kernel API. See Documentation/filesystems/relafys.txt. + */ + +/* + * rchan_callback implementations defining default channel behavior. Used + * in place of corresponding NULL values in client callback struct. + */ + +/* + * buffer_end() default callback. Does nothing. + */ +static int +buffer_end_default_callback(int rchan_id, + char *current_write_pos, + char *end_of_buffer, + struct timeval end_time, + u32 end_tsc, + int using_tsc) +{ + return 0; +} + +/* + * buffer_start() default callback. Does nothing. + */ +static int +buffer_start_default_callback(int rchan_id, + char *current_write_pos, + u32 buffer_id, + struct timeval start_time, + u32 start_tsc, + int using_tsc) +{ + return 0; +} + +/* + * deliver() default callback. Does nothing. + */ +static void +deliver_default_callback(int rchan_id, char *from, u32 len) +{ +} + +/* + * user_deliver() default callback. Does nothing. + */ +static void +user_deliver_default_callback(int rchan_id, char *from, u32 len) +{ +} + +/* + * needs_resize() default callback. Does nothing. + */ +static void +needs_resize_default_callback(int rchan_id, + int resize_type, + u32 suggested_buf_size, + u32 suggested_n_bufs) +{ +} + +/* + * fileop_notify() default callback. Does nothing. + */ +static int +fileop_notify_default_callback(int rchan_id, + struct file *filp, + enum relay_fileop fileop) +{ + return 0; +} + +/* + * ioctl() default callback. Does nothing. + */ +static int +ioctl_default_callback(int rchan_id, + unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +/* relay channel default callbacks */ +static struct rchan_callbacks default_channel_callbacks = { + .buffer_start = buffer_start_default_callback, + .buffer_end = buffer_end_default_callback, + .deliver = deliver_default_callback, + .user_deliver = user_deliver_default_callback, + .needs_resize = needs_resize_default_callback, + .fileop_notify = fileop_notify_default_callback, + .ioctl = ioctl_default_callback, +}; + +/** + * check_attribute_flags - check sanity of channel attributes + * @flags: channel attributes + * @resizeable: 1 if true + * + * Returns 0 if successful, negative otherwise. + */ +static int +check_attribute_flags(u32 *attribute_flags, int resizeable) +{ + u32 flags = *attribute_flags; + + if (!(flags & RELAY_DELIVERY_BULK) && !(flags & RELAY_DELIVERY_PACKET)) + return -EINVAL; /* Delivery mode must be specified */ + + if (!(flags & RELAY_USAGE_SMP) && !(flags & RELAY_USAGE_GLOBAL)) + return -EINVAL; /* Usage must be specified */ + + if (resizeable) { /* Resizeable can never be continuous */ + *attribute_flags &= ~RELAY_MODE_CONTINUOUS; + *attribute_flags |= RELAY_MODE_NO_OVERWRITE; + } + + if ((flags & RELAY_MODE_CONTINUOUS) && + (flags & RELAY_MODE_NO_OVERWRITE)) + return -EINVAL; /* Can't have it both ways */ + + if (!(flags & RELAY_MODE_CONTINUOUS) && + !(flags & RELAY_MODE_NO_OVERWRITE)) + *attribute_flags |= RELAY_MODE_CONTINUOUS; /* Default to continuous */ + + if (!(flags & RELAY_SCHEME_ANY)) + return -EINVAL; /* One or both must be specified */ + else if (flags & RELAY_SCHEME_LOCKLESS) { + if (have_cmpxchg()) + *attribute_flags &= ~RELAY_SCHEME_LOCKING; + else if (flags & RELAY_SCHEME_LOCKING) + *attribute_flags &= ~RELAY_SCHEME_LOCKLESS; + else + return -EINVAL; /* Locking scheme not an alternative */ + } + + if (!(flags & RELAY_TIMESTAMP_ANY)) + return -EINVAL; /* One or both must be specified */ + else if (flags & RELAY_TIMESTAMP_TSC) { + if (have_tsc()) + *attribute_flags &= ~RELAY_TIMESTAMP_GETTIMEOFDAY; + else if (flags & RELAY_TIMESTAMP_GETTIMEOFDAY) + *attribute_flags &= ~RELAY_TIMESTAMP_TSC; + else + return -EINVAL; /* gettimeofday not an alternative */ + } + + return 0; +} + +/* + * High-level API functions. + */ + +/** + * __relay_reset - internal reset function + * @rchan: the channel + * @init: 1 if this is a first-time channel initialization + * + * See relay_reset for description of effect. + */ +void +__relay_reset(struct rchan *rchan, int init) +{ + int i; + + if (init) { + rchan->version = RELAYFS_CHANNEL_VERSION; + init_MUTEX(&rchan->resize_sem); + init_waitqueue_head(&rchan->read_wait); + init_waitqueue_head(&rchan->write_wait); + atomic_set(&rchan->refcount, 0); + INIT_LIST_HEAD(&rchan->open_readers); + rchan->open_readers_lock = RW_LOCK_UNLOCKED; + } + + rchan->buf_id = rchan->buf_idx = 0; + atomic_set(&rchan->suspended, 0); + atomic_set(&rchan->mapped, 0); + rchan->half_switch = 0; + rchan->bufs_produced = 0; + rchan->bufs_consumed = 0; + rchan->bytes_consumed = 0; + rchan->initialized = 0; + rchan->finalized = 0; + rchan->resize_min = rchan->resize_max = 0; + rchan->resizing = 0; + rchan->replace_buffer = 0; + rchan->resize_buf = NULL; + rchan->resize_buf_size = 0; + rchan->resize_alloc_size = 0; + rchan->resize_n_bufs = 0; + rchan->resize_err = 0; + rchan->resize_failures = 0; + rchan->resize_order = 0; + + rchan->expand_page_array = NULL; + rchan->expand_page_count = 0; + rchan->shrink_page_array = NULL; + rchan->shrink_page_count = 0; + rchan->resize_page_array = NULL; + rchan->resize_page_count = 0; + rchan->old_buf_page_array = NULL; + rchan->expand_buf_id = 0; + + INIT_WORK(&rchan->wake_readers, NULL, NULL); + INIT_WORK(&rchan->wake_writers, NULL, NULL); + + for (i = 0; i < RELAY_MAX_BUFS; i++) + rchan->unused_bytes[i] = 0; + + rchan->relay_ops->reset(rchan, init); +} + +/** + * relay_reset - reset the channel + * @rchan: the channel + * + * Returns 0 if successful, negative if not. + * + * This has the effect of erasing all data from the buffer and + * restarting the channel in its initial state. The buffer itself + * is not freed, so any mappings are still in effect. + * + * NOTE: Care should be taken that the channnel isn't actually + * being used by anything when this call is made. + */ +int +relay_reset(int rchan_id) +{ + struct rchan *rchan; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + __relay_reset(rchan, 0); + update_readers_consumed(rchan, 0, 0); + + rchan_put(rchan); + + return 0; +} + +/** + * check_init_buf - check the sanity of init_buf, if present + * @init_buf: the initbuf + * @init_buf_size: the total initbuf size + * @bufsize: the channel's sub-buffer size + * @nbufs: the number of sub-buffers in the channel + * + * Returns 0 if ok, negative otherwise. + */ +static int +check_init_buf(char *init_buf, u32 init_buf_size, u32 bufsize, u32 nbufs) +{ + int err = 0; + + if (init_buf && nbufs == 1) /* 1 sub-buffer makes no sense */ + err = -EINVAL; + + if (init_buf && (bufsize * nbufs != init_buf_size)) + err = -EINVAL; + + return err; +} + +/** + * rchan_create_buf - allocate the initial channel buffer + * @rchan: the channel + * @size_alloc: the total size of the channel buffer + * + * Returns 0 if successful, negative otherwise. + */ +static inline int +rchan_create_buf(struct rchan *rchan, int size_alloc) +{ + struct page **page_array; + int page_count; + + if ((rchan->buf = (char *)alloc_rchan_buf(size_alloc, &page_array, &page_count)) == NULL) { + rchan->buf_page_array = NULL; + rchan->buf_page_count = 0; + return -ENOMEM; + } + + rchan->buf_page_array = page_array; + rchan->buf_page_count = page_count; + + return 0; +} + +/** + * rchan_create - allocate and initialize a channel, including buffer + * @chanpath: path specifying the relayfs channel file to create + * @bufsize: the size of the sub-buffers within the channel buffer + * @nbufs: the number of sub-buffers within the channel buffer + * @rchan_flags: flags specifying buffer attributes + * @err: err code + * + * Returns channel if successful, NULL otherwise, err receives errcode. + * + * Allocates a struct rchan representing a relay channel, according + * to the attributes passed in via rchan_flags. Does some basic sanity + * checking but doesn't try to do anything smart. In particular, the + * number of buffers must be a power of 2, and if the lockless scheme + * is being used, the sub-buffer size must also be a power of 2. The + * locking scheme can use buffers of any size. + */ +static struct rchan * +rchan_create(const char *chanpath, + int bufsize, + int nbufs, + u32 rchan_flags, + char *init_buf, + u32 init_buf_size, + int *err) +{ + int size_alloc; + struct rchan *rchan = NULL; + + *err = 0; + + rchan = (struct rchan *)kmalloc(sizeof(struct rchan), GFP_KERNEL); + if (rchan == NULL) { + *err = -ENOMEM; + return NULL; + } + rchan->buf = rchan->init_buf = NULL; + + *err = check_init_buf(init_buf, init_buf_size, bufsize, nbufs); + if (*err) + goto exit; + + if (nbufs == 1 && bufsize) { + rchan->n_bufs = nbufs; + rchan->buf_size = bufsize; + size_alloc = bufsize; + goto alloc; + } + + if (bufsize <= 0 || + (rchan_flags & RELAY_SCHEME_LOCKLESS && hweight32(bufsize) != 1) || + hweight32(nbufs) != 1 || + nbufs < RELAY_MIN_BUFS || + nbufs > RELAY_MAX_BUFS) { + *err = -EINVAL; + goto exit; + } + + size_alloc = FIX_SIZE(bufsize * nbufs); + if (size_alloc > RELAY_MAX_BUF_SIZE) { + *err = -EINVAL; + goto exit; + } + rchan->n_bufs = nbufs; + rchan->buf_size = bufsize; + + if (rchan_flags & RELAY_SCHEME_LOCKLESS) { + offset_bits(rchan) = ffs(bufsize) - 1; + offset_mask(rchan) = RELAY_BUF_OFFSET_MASK(offset_bits(rchan)); + bufno_bits(rchan) = ffs(nbufs) - 1; + } +alloc: + if (rchan_alloc_id(rchan) == -1) { + *err = -ENOMEM; + goto exit; + } + + if (init_buf == NULL) { + *err = rchan_create_buf(rchan, size_alloc); + if (*err) { + rchan_free_id(rchan->id); + goto exit; + } + } else + rchan->buf = rchan->init_buf = init_buf; + + rchan->alloc_size = size_alloc; + + if (rchan_flags & RELAY_SCHEME_LOCKLESS) + rchan->relay_ops = &lockless_ops; + else + rchan->relay_ops = &locking_ops; + +exit: + if (*err) { + kfree(rchan); + rchan = NULL; + } + + return rchan; +} + + +static char tmpname[NAME_MAX]; + +/** + * rchan_create_dir - create directory for file + * @chanpath: path to file, including filename + * @residual: filename remaining after parse + * @topdir: the directory filename should be created in + * + * Returns 0 if successful, negative otherwise. + * + * Inspired by xlate_proc_name() in procfs. Given a file path which + * includes the filename, creates any and all directories necessary + * to create the file. + */ +static int +rchan_create_dir(const char * chanpath, + const char **residual, + struct dentry **topdir) +{ + const char *cp = chanpath, *next; + struct dentry *parent = NULL; + int len, err = 0; + + while (1) { + next = strchr(cp, '/'); + if (!next) + break; + + len = next - cp; + + strncpy(tmpname, cp, len); + tmpname[len] = '\0'; + err = relayfs_create_dir(tmpname, parent, &parent); + if (err && (err != -EEXIST)) + return err; + cp += len + 1; + } + + *residual = cp; + *topdir = parent; + + return err; +} + +/** + * rchan_create_file - create file, including parent directories + * @chanpath: path to file, including filename + * @dentry: result dentry + * @data: data to associate with the file + * + * Returns 0 if successful, negative otherwise. + */ +static int +rchan_create_file(const char * chanpath, + struct dentry **dentry, + struct rchan * data, + int mode) +{ + int err; + const char * fname; + struct dentry *topdir; + + err = rchan_create_dir(chanpath, &fname, &topdir); + if (err && (err != -EEXIST)) + return err; + + err = relayfs_create_file(fname, topdir, dentry, (void *)data, mode); + + return err; +} + +/** + * relay_open - create a new file/channel buffer in relayfs + * @chanpath: name of file to create, including path + * @bufsize: size of sub-buffers + * @nbufs: number of sub-buffers + * @flags: channel attributes + * @callbacks: client callback functions + * @start_reserve: number of bytes to reserve at start of each sub-buffer + * @end_reserve: number of bytes to reserve at end of each sub-buffer + * @rchan_start_reserve: additional reserve at start of first sub-buffer + * @resize_min: minimum total buffer size, if set + * @resize_max: maximum total buffer size, if set + * @mode: the perms to be given to the relayfs file, 0 to accept defaults + * @init_buf: initial memory buffer to start out with, NULL if N/A + * @init_buf_size: initial memory buffer size to start out with, 0 if N/A + * + * Returns channel id if successful, negative otherwise. + * + * Creates a relay channel using the sizes and attributes specified. + * The default permissions, used if mode == 0 are S_IRUSR | S_IWUSR. See + * Documentation/filesystems/relayfs.txt for details. + */ +int +relay_open(const char *chanpath, + int bufsize, + int nbufs, + u32 flags, + struct rchan_callbacks *channel_callbacks, + u32 start_reserve, + u32 end_reserve, + u32 rchan_start_reserve, + u32 resize_min, + u32 resize_max, + int mode, + char *init_buf, + u32 init_buf_size) +{ + int err; + struct rchan *rchan; + struct dentry *dentry; + struct rchan_callbacks *callbacks = NULL; + + if (chanpath == NULL) + return -EINVAL; + + if (nbufs != 1) { + err = check_attribute_flags(&flags, resize_min ? 1 : 0); + if (err) + return err; + } + + rchan = rchan_create(chanpath, bufsize, nbufs, flags, init_buf, init_buf_size, &err); + + if (err < 0) + return err; + + /* Create file in fs */ + if ((err = rchan_create_file(chanpath, &dentry, rchan, mode)) < 0) { + rchan_destroy_buf(rchan); + rchan_free_id(rchan->id); + kfree(rchan); + return err; + } + + rchan->dentry = dentry; + + if (channel_callbacks == NULL) + callbacks = &default_channel_callbacks; + else + callbacks = channel_callbacks; + + if (callbacks->buffer_end == NULL) + callbacks->buffer_end = buffer_end_default_callback; + if (callbacks->buffer_start == NULL) + callbacks->buffer_start = buffer_start_default_callback; + if (callbacks->deliver == NULL) + callbacks->deliver = deliver_default_callback; + if (callbacks->user_deliver == NULL) + callbacks->user_deliver = user_deliver_default_callback; + if (callbacks->needs_resize == NULL) + callbacks->needs_resize = needs_resize_default_callback; + if (callbacks->fileop_notify == NULL) + callbacks->fileop_notify = fileop_notify_default_callback; + if (callbacks->ioctl == NULL) + callbacks->ioctl = ioctl_default_callback; + rchan->callbacks = callbacks; + + /* Just to let the client know the sizes used */ + rchan->callbacks->needs_resize(rchan->id, + RELAY_RESIZE_REPLACED, + rchan->buf_size, + rchan->n_bufs); + + rchan->flags = flags; + rchan->start_reserve = start_reserve; + rchan->end_reserve = end_reserve; + rchan->rchan_start_reserve = rchan_start_reserve; + + __relay_reset(rchan, 1); + + if (resize_min > 0 && resize_max > 0 && + resize_max < RELAY_MAX_TOTAL_BUF_SIZE) { + rchan->resize_min = resize_min; + rchan->resize_max = resize_max; + init_shrink_timer(rchan); + } + + rchan_get(rchan->id); + + return rchan->id; +} + +/** + * relay_discard_init_buf - alloc channel buffer and copy init_buf into it + * @rchan_id: the channel id + * + * Returns 0 if successful, negative otherwise. + * + * NOTE: May sleep. Should also be called only when the channel isn't + * actively being written into. + */ +int +relay_discard_init_buf(int rchan_id) +{ + struct rchan *rchan; + int err = 0; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + if (rchan->init_buf == NULL) { + err = -EINVAL; + goto out; + } + + err = rchan_create_buf(rchan, rchan->alloc_size); + if (err) + goto out; + + memcpy(rchan->buf, rchan->init_buf, rchan->n_bufs * rchan->buf_size); + rchan->init_buf = NULL; +out: + rchan_put(rchan); + + return err; +} + +/** + * relay_finalize - perform end-of-buffer processing for last buffer + * @rchan_id: the channel id + * @releasing: true if called when releasing file + * + * Returns 0 if successful, negative otherwise. + */ +static int +relay_finalize(int rchan_id) +{ + struct rchan *rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + if (rchan->finalized == 0) { + rchan->relay_ops->finalize(rchan); + rchan->finalized = 1; + } + + if (waitqueue_active(&rchan->read_wait)) { + PREPARE_WORK(&rchan->wake_readers, wakeup_readers, rchan); + schedule_delayed_work(&rchan->wake_readers, 1); + } + + rchan_put(rchan); + + return 0; +} + +/** + * restore_callbacks - restore default channel callbacks + * @rchan: the channel + * + * Restore callbacks to the default versions. + */ +static inline void +restore_callbacks(struct rchan *rchan) +{ + if (rchan->callbacks != &default_channel_callbacks) + rchan->callbacks = &default_channel_callbacks; +} + +/** + * relay_close - close the channel + * @rchan_id: relay channel id + * + * Finalizes the last sub-buffer and marks the channel as finalized. + * The channel buffer and channel data structure are then freed + * automatically when the last reference to the channel is given up. + */ +int +relay_close(int rchan_id) +{ + int err; + struct rchan *rchan; + + if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS)) + return -EBADF; + + err = relay_finalize(rchan_id); + + if (!err) { + read_lock(&rchan_table_lock); + rchan = rchan_table[rchan_id]; + read_unlock(&rchan_table_lock); + + if (rchan) { + restore_callbacks(rchan); + if (rchan->resize_min) + del_timer(&rchan->shrink_timer); + rchan_put(rchan); + } + } + + return err; +} + +/** + * relay_write - reserve a slot in the channel and write data into it + * @rchan_id: relay channel id + * @data_ptr: data to be written into reserved slot + * @count: number of bytes to write + * @td_offset: optional offset where time delta should be written + * @wrote_pos: optional ptr returning buf pos written to, ignored if NULL + * + * Returns the number of bytes written, 0 or negative on failure. + * + * Reserves space in the channel and writes count bytes of data_ptr + * to it. Automatically performs any necessary locking, depending + * on the scheme and SMP usage in effect (no locking is done for the + * lockless scheme regardless of usage). + * + * If td_offset is >= 0, the internal time delta calculated when + * slot was reserved will be written at that offset. + * + * If wrote_pos is non-NULL, it will receive the location the data + * was written to, which may be needed for some applications but is not + * normally interesting. + */ +int +relay_write(int rchan_id, + const void *data_ptr, + size_t count, + int td_offset, + void **wrote_pos) +{ + unsigned long flags; + char *reserved, *write_pos; + int bytes_written = 0; + int reserve_code, interrupting; + struct timeval ts; + u32 td; + struct rchan *rchan; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + relay_lock_channel(rchan, flags); /* nop for lockless */ + + write_pos = reserved = relay_reserve(rchan, count, &ts, &td, + &reserve_code, &interrupting); + + if (reserved != NULL) { + relay_write_direct(write_pos, data_ptr, count); + if ((td_offset >= 0) && (td_offset < count - sizeof(td))) + *((u32 *)(reserved + td_offset)) = td; + bytes_written = count; + } else if (reserve_code == RELAY_WRITE_TOO_LONG) + bytes_written = -EINVAL; + + if (bytes_written > 0) + relay_commit(rchan, reserved, bytes_written, reserve_code, interrupting); + + relay_unlock_channel(rchan, flags); /* nop for lockless */ + + rchan_put(rchan); + + if (wrote_pos) + *wrote_pos = reserved; + + return bytes_written; +} + +/** + * wakeup_writers - wake up VFS writers waiting on a channel + * @private: the channel + * + * This is the work function used to defer writer waking. The + * reason waking is deferred is that calling directly from + * buffers_consumed causes problems if you're writing from say + * the scheduler. + */ +static void +wakeup_writers(void *private) +{ + struct rchan *rchan = (struct rchan *)private; + + wake_up_interruptible(&rchan->write_wait); +} + + +/** + * __relay_buffers_consumed - internal version of relay_buffers_consumed + * @rchan: the relay channel + * @bufs_consumed: number of buffers to add to current count for channel + * + * Internal - updates the channel's consumed buffer count. + */ +static void +__relay_buffers_consumed(struct rchan *rchan, u32 bufs_consumed) +{ + rchan->bufs_consumed += bufs_consumed; + + if (rchan->bufs_consumed > rchan->bufs_produced) + rchan->bufs_consumed = rchan->bufs_produced; + + atomic_set(&rchan->suspended, 0); + + PREPARE_WORK(&rchan->wake_writers, wakeup_writers, rchan); + schedule_delayed_work(&rchan->wake_writers, 1); +} + +/** + * __reader_buffers_consumed - update reader/channel consumed buffer count + * @reader: channel reader + * @bufs_consumed: number of buffers to add to current count for channel + * + * Internal - updates the reader's consumed buffer count. If the reader's + * resulting total is greater than the channel's, update the channel's. +*/ +static void +__reader_buffers_consumed(struct rchan_reader *reader, u32 bufs_consumed) +{ + reader->bufs_consumed += bufs_consumed; + + if (reader->bufs_consumed > reader->rchan->bufs_consumed) + __relay_buffers_consumed(reader->rchan, bufs_consumed); +} + +/** + * relay_buffers_consumed - add to the # buffers consumed for the channel + * @reader: channel reader + * @bufs_consumed: number of buffers to add to current count for channel + * + * Adds to the channel's consumed buffer count. buffers_consumed should + * be the number of buffers newly consumed, not the total number consumed. + * + * NOTE: kernel clients don't need to call this function if the reader + * is auto-consuming or the channel is MODE_CONTINUOUS. + */ +void +relay_buffers_consumed(struct rchan_reader *reader, u32 bufs_consumed) +{ + if (reader && reader->rchan) + __reader_buffers_consumed(reader, bufs_consumed); +} + +/** + * __relay_bytes_consumed - internal version of relay_bytes_consumed + * @rchan: the relay channel + * @bytes_consumed: number of bytes to add to current count for channel + * @read_offset: where the bytes were consumed from + * + * Internal - updates the channel's consumed count. +*/ +static void +__relay_bytes_consumed(struct rchan *rchan, u32 bytes_consumed, u32 read_offset) +{ + u32 consuming_idx; + u32 unused; + + consuming_idx = read_offset / rchan->buf_size; + + if (consuming_idx >= rchan->n_bufs) + consuming_idx = rchan->n_bufs - 1; + rchan->bytes_consumed += bytes_consumed; + + unused = rchan->unused_bytes[consuming_idx]; + + if (rchan->bytes_consumed + unused >= rchan->buf_size) { + __relay_buffers_consumed(rchan, 1); + rchan->bytes_consumed = 0; + } +} + +/** + * __reader_bytes_consumed - update reader/channel consumed count + * @reader: channel reader + * @bytes_consumed: number of bytes to add to current count for channel + * @read_offset: where the bytes were consumed from + * + * Internal - updates the reader's consumed count. If the reader's + * resulting total is greater than the channel's, update the channel's. +*/ +static void +__reader_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset) +{ + u32 consuming_idx; + u32 unused; + + consuming_idx = read_offset / reader->rchan->buf_size; + + if (consuming_idx >= reader->rchan->n_bufs) + consuming_idx = reader->rchan->n_bufs - 1; + + reader->bytes_consumed += bytes_consumed; + + unused = reader->rchan->unused_bytes[consuming_idx]; + + if (reader->bytes_consumed + unused >= reader->rchan->buf_size) { + reader->bufs_consumed++; + reader->bytes_consumed = 0; + } + + if ((reader->bufs_consumed > reader->rchan->bufs_consumed) || + ((reader->bufs_consumed == reader->rchan->bufs_consumed) && + (reader->bytes_consumed > reader->rchan->bytes_consumed))) + __relay_bytes_consumed(reader->rchan, bytes_consumed, read_offset); +} + +/** + * relay_bytes_consumed - add to the # bytes consumed for the channel + * @reader: channel reader + * @bytes_consumed: number of bytes to add to current count for channel + * @read_offset: where the bytes were consumed from + * + * Adds to the channel's consumed count. bytes_consumed should be the + * number of bytes actually read e.g. return value of relay_read() and + * the read_offset should be the actual offset the bytes were read from + * e.g. the actual_read_offset set by relay_read(). See + * Documentation/filesystems/relayfs.txt for more details. + * + * NOTE: kernel clients don't need to call this function if the reader + * is auto-consuming or the channel is MODE_CONTINUOUS. + */ +void +relay_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset) +{ + if (reader && reader->rchan) + __reader_bytes_consumed(reader, bytes_consumed, read_offset); +} + +/** + * update_readers_consumed - apply offset change to reader + * @rchan: the channel + * + * Apply the consumed counts to all readers open on the channel. + */ +void +update_readers_consumed(struct rchan *rchan, u32 bufs_consumed, u32 bytes_consumed) +{ + struct list_head *p; + struct rchan_reader *reader; + + read_lock(&rchan->open_readers_lock); + list_for_each(p, &rchan->open_readers) { + reader = list_entry(p, struct rchan_reader, list); + reader->bufs_consumed = bufs_consumed; + reader->bytes_consumed = bytes_consumed; + if (reader->vfs_reader) + reader->pos.file->f_pos = 0; + else + reader->pos.f_pos = 0; + reader->offset_changed = 1; + } + read_unlock(&rchan->open_readers_lock); +} + +/** + * do_read - utility function to do the actual read to user + * @rchan: the channel + * @buf: user buf to read into, NULL if just getting info + * @count: bytes requested + * @read_offset: offset into channel + * @new_offset: new offset into channel after read + * @actual_read_offset: read offset actually used + * + * Returns the number of bytes read, 0 if none. + */ +static ssize_t +do_read(struct rchan *rchan, char *buf, size_t count, u32 read_offset, u32 *new_offset, u32 *actual_read_offset) +{ + u32 read_bufno, cur_bufno; + u32 avail_offset, cur_idx, max_offset, buf_end_offset; + u32 avail_count, buf_size; + int unused_bytes = 0; + size_t read_count = 0; + u32 last_buf_byte_offset; + + *actual_read_offset = read_offset; + + buf_size = rchan->buf_size; + if (unlikely(!buf_size)) BUG(); + + read_bufno = read_offset / buf_size; + if (unlikely(read_bufno >= RELAY_MAX_BUFS)) BUG(); + unused_bytes = rchan->unused_bytes[read_bufno]; + + avail_offset = cur_idx = relay_get_offset(rchan, &max_offset); + + if (cur_idx == read_offset) { + if (atomic_read(&rchan->suspended) == 1) { + read_offset += 1; + if (read_offset >= max_offset) + read_offset = 0; + *actual_read_offset = read_offset; + } else { + *new_offset = read_offset; + return 0; + } + } else { + last_buf_byte_offset = (read_bufno + 1) * buf_size - 1; + if (read_offset == last_buf_byte_offset) { + if (unused_bytes != 1) { + read_offset += 1; + if (read_offset >= max_offset) + read_offset = 0; + *actual_read_offset = read_offset; + } + } + } + + read_bufno = read_offset / buf_size; + if (unlikely(read_bufno >= RELAY_MAX_BUFS)) BUG(); + unused_bytes = rchan->unused_bytes[read_bufno]; + + cur_bufno = cur_idx / buf_size; + + buf_end_offset = (read_bufno + 1) * buf_size - unused_bytes; + if (avail_offset > buf_end_offset) + avail_offset = buf_end_offset; + else if (avail_offset < read_offset) + avail_offset = buf_end_offset; + avail_count = avail_offset - read_offset; + read_count = avail_count >= count ? count : avail_count; + + if (read_count && buf != NULL) + if (copy_to_user(buf, rchan->buf + read_offset, read_count)) + return -EFAULT; + + if (read_bufno == cur_bufno) + if (read_count && (read_offset + read_count >= buf_end_offset) && (read_offset + read_count <= cur_idx)) { + *new_offset = cur_idx; + return read_count; + } + + if (read_offset + read_count + unused_bytes > max_offset) + *new_offset = 0; + else if (read_offset + read_count >= buf_end_offset) + *new_offset = read_offset + read_count + unused_bytes; + else + *new_offset = read_offset + read_count; + + return read_count; +} + +/** + * __relay_read - read bytes from channel, relative to current reader pos + * @reader: channel reader + * @buf: user buf to read into, NULL if just getting info + * @count: bytes requested + * @read_offset: offset into channel + * @new_offset: new offset into channel after read + * @actual_read_offset: read offset actually used + * @wait: if non-zero, wait for something to read + * + * Internal - see relay_read() for details. + * + * Returns the number of bytes read, 0 if none, negative on failure. + */ +static ssize_t +__relay_read(struct rchan_reader *reader, char *buf, size_t count, u32 read_offset, u32 *new_offset, u32 *actual_read_offset, int wait) +{ + int err = 0; + size_t read_count = 0; + struct rchan *rchan = reader->rchan; + + if (!wait && !rchan->initialized) + return -EAGAIN; + + if (using_lockless(rchan)) + read_offset &= idx_mask(rchan); + + if (read_offset >= rchan->n_bufs * rchan->buf_size) { + *new_offset = 0; + if (!wait) + return -EAGAIN; + else + return -EINTR; + } + + if (buf != NULL && wait) { + err = wait_event_interruptible(rchan->read_wait, + ((rchan->finalized == 1) || + (atomic_read(&rchan->suspended) == 1) || + (relay_get_offset(rchan, NULL) != read_offset))); + + if (rchan->finalized) + return 0; + + if (reader->offset_changed) { + reader->offset_changed = 0; + return -EINTR; + } + + if (err) + return err; + } + + read_count = do_read(rchan, buf, count, read_offset, new_offset, actual_read_offset); + + if (read_count < 0) + err = read_count; + + if (err) + return err; + else + return read_count; +} + +/** + * relay_read - read bytes from channel, relative to current reader pos + * @reader: channel reader + * @buf: user buf to read into, NULL if just getting info + * @count: bytes requested + * @wait: if non-zero, wait for something to read + * @actual_read_offset: set read offset actually used, must not be NULL + * + * Reads count bytes from the channel, or as much as is available within + * the sub-buffer currently being read. The read offset that will be + * read from is the position contained within the reader object. If the + * wait flag is set, buf is non-NULL, and there is nothing available, + * it will wait until there is. If the wait flag is 0 and there is + * nothing available, -EAGAIN is returned. If buf is NULL, the value + * returned is the number of bytes that would have been read. + * actual_read_offset is the value that should be passed as the read + * offset to relay_bytes_consumed, needed only if the reader is not + * auto-consuming and the channel is MODE_NO_OVERWRITE, but in any case, + * it must not be NULL. See Documentation/filesystems/relayfs.txt for + * more details. + */ +ssize_t +relay_read(struct rchan_reader *reader, char *buf, size_t count, int wait, u32 *actual_read_offset) +{ + u32 new_offset; + u32 read_offset; + ssize_t read_count; + + if (reader == NULL || reader->rchan == NULL) + return -EBADF; + + if (actual_read_offset == NULL) + return -EINVAL; + + if (reader->vfs_reader) + read_offset = (u32)(reader->pos.file->f_pos); + else + read_offset = reader->pos.f_pos; + *actual_read_offset = read_offset; + + read_count = __relay_read(reader, buf, count, read_offset, + &new_offset, actual_read_offset, wait); + + if (read_count < 0) + return read_count; + + if (reader->vfs_reader) + reader->pos.file->f_pos = new_offset; + else + reader->pos.f_pos = new_offset; + + if (reader->auto_consume && ((read_count) || (new_offset != read_offset))) + __reader_bytes_consumed(reader, read_count, *actual_read_offset); + + if (read_count == 0 && !wait) + return -EAGAIN; + + return read_count; +} + +/** + * relay_bytes_avail - number of bytes available in current sub-buffer + * @reader: channel reader + * + * Returns the number of bytes available relative to the reader's + * current read position within the corresponding sub-buffer, 0 if + * there is nothing available. See Documentation/filesystems/relayfs.txt + * for more details. + */ +ssize_t +relay_bytes_avail(struct rchan_reader *reader) +{ + u32 f_pos; + u32 new_offset; + u32 actual_read_offset; + ssize_t bytes_read; + + if (reader == NULL || reader->rchan == NULL) + return -EBADF; + + if (reader->vfs_reader) + f_pos = (u32)reader->pos.file->f_pos; + else + f_pos = reader->pos.f_pos; + new_offset = f_pos; + + bytes_read = __relay_read(reader, NULL, reader->rchan->buf_size, + f_pos, &new_offset, &actual_read_offset, 0); + + if ((new_offset != f_pos) && + ((bytes_read == -EINTR) || (bytes_read == 0))) + bytes_read = -EAGAIN; + else if ((bytes_read < 0) && (bytes_read != -EAGAIN)) + bytes_read = 0; + + return bytes_read; +} + +/** + * rchan_empty - boolean, is the channel empty wrt reader? + * @reader: channel reader + * + * Returns 1 if the channel is empty, 0 otherwise. + */ +int +rchan_empty(struct rchan_reader *reader) +{ + ssize_t avail_count; + u32 buffers_ready; + struct rchan *rchan = reader->rchan; + u32 cur_idx, curbuf_bytes; + int mapped; + + if (atomic_read(&rchan->suspended) == 1) + return 0; + + mapped = atomic_read(&rchan->mapped); + + if (mapped && bulk_delivery(rchan)) { + buffers_ready = rchan->bufs_produced - rchan->bufs_consumed; + return buffers_ready ? 0 : 1; + } + + if (mapped && packet_delivery(rchan)) { + buffers_ready = rchan->bufs_produced - rchan->bufs_consumed; + if (buffers_ready) + return 0; + else { + cur_idx = relay_get_offset(rchan, NULL); + curbuf_bytes = cur_idx % rchan->buf_size; + return curbuf_bytes == rchan->bytes_consumed ? 1 : 0; + } + } + + avail_count = relay_bytes_avail(reader); + + return avail_count ? 0 : 1; +} + +/** + * rchan_full - boolean, is the channel full wrt consuming reader? + * @reader: channel reader + * + * Returns 1 if the channel is full, 0 otherwise. + */ +int +rchan_full(struct rchan_reader *reader) +{ + u32 buffers_ready; + struct rchan *rchan = reader->rchan; + + if (mode_continuous(rchan)) + return 0; + + buffers_ready = rchan->bufs_produced - rchan->bufs_consumed; + + return buffers_ready > reader->rchan->n_bufs - 1 ? 1 : 0; +} + +/** + * relay_info - get status and other information about a relay channel + * @rchan_id: relay channel id + * @rchan_info: pointer to the rchan_info struct to be filled in + * + * Fills in an rchan_info struct with channel status and attribute + * information. See Documentation/filesystems/relayfs.txt for details. + * + * Returns 0 if successful, negative otherwise. + */ +int +relay_info(int rchan_id, struct rchan_info *rchan_info) +{ + int i; + struct rchan *rchan; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + rchan_info->flags = rchan->flags; + rchan_info->buf_size = rchan->buf_size; + rchan_info->buf_addr = rchan->buf; + rchan_info->alloc_size = rchan->alloc_size; + rchan_info->n_bufs = rchan->n_bufs; + rchan_info->cur_idx = relay_get_offset(rchan, NULL); + rchan_info->bufs_produced = rchan->bufs_produced; + rchan_info->bufs_consumed = rchan->bufs_consumed; + rchan_info->buf_id = rchan->buf_id; + + for (i = 0; i < rchan->n_bufs; i++) { + rchan_info->unused_bytes[i] = rchan->unused_bytes[i]; + if (using_lockless(rchan)) + rchan_info->buffer_complete[i] = (atomic_read(&fill_count(rchan, i)) == rchan->buf_size); + else + rchan_info->buffer_complete[i] = 0; + } + + rchan_put(rchan); + + return 0; +} + +/** + * __add_rchan_reader - creates and adds a reader to a channel + * @rchan: relay channel + * @filp: the file associated with rchan, if applicable + * @auto_consume: boolean, whether reader's reads automatically consume + * @map_reader: boolean, whether reader's reading via a channel mapping + * + * Returns a pointer to the reader object create, NULL if unsuccessful + * + * Creates and initializes an rchan_reader object for reading the channel. + * If filp is non-NULL, the reader is a VFS reader, otherwise not. + * + * If the reader is a map reader, it isn't considered a VFS reader for + * our purposes. Also, map_readers can't be auto-consuming. + */ +struct rchan_reader * +__add_rchan_reader(struct rchan *rchan, struct file *filp, int auto_consume, int map_reader) +{ + struct rchan_reader *reader; + u32 will_read; + + reader = kmalloc(sizeof(struct rchan_reader), GFP_KERNEL); + + if (reader) { + write_lock(&rchan->open_readers_lock); + reader->rchan = rchan; + if (filp) { + reader->vfs_reader = 1; + reader->pos.file = filp; + } else { + reader->vfs_reader = 0; + reader->pos.f_pos = 0; + } + reader->map_reader = map_reader; + reader->auto_consume = auto_consume; + + if (!map_reader) { + will_read = rchan->bufs_produced % rchan->n_bufs; + if (!will_read && atomic_read(&rchan->suspended)) + will_read = rchan->n_bufs; + reader->bufs_consumed = rchan->bufs_produced - will_read; + rchan->bufs_consumed = reader->bufs_consumed; + rchan->bytes_consumed = reader->bytes_consumed = 0; + reader->offset_changed = 0; + } + + list_add(&reader->list, &rchan->open_readers); + write_unlock(&rchan->open_readers_lock); + } + + return reader; +} + +/** + * add_rchan_reader - create a reader for a channel + * @rchan_id: relay channel handle + * @auto_consume: boolean, whether reader's reads automatically consume + * + * Returns a pointer to the reader object created, NULL if unsuccessful + * + * Creates and initializes an rchan_reader object for reading the channel. + * This function is useful only for non-VFS readers. + */ +struct rchan_reader * +add_rchan_reader(int rchan_id, int auto_consume) +{ + struct rchan *rchan = rchan_get(rchan_id); + if (rchan == NULL) + return NULL; + + return __add_rchan_reader(rchan, NULL, auto_consume, 0); +} + +/** + * add_map_reader - create a map reader for a channel + * @rchan_id: relay channel handle + * + * Returns a pointer to the reader object created, NULL if unsuccessful + * + * Creates and initializes an rchan_reader object for reading the channel. + * This function is useful only for map readers. + */ +struct rchan_reader * +add_map_reader(int rchan_id) +{ + struct rchan *rchan = rchan_get(rchan_id); + if (rchan == NULL) + return NULL; + + return __add_rchan_reader(rchan, NULL, 0, 1); +} + +/** + * __remove_rchan_reader - destroy a channel reader + * @reader: channel reader + * + * Internal - removes reader from the open readers list, and frees it. + */ +void +__remove_rchan_reader(struct rchan_reader *reader) +{ + struct list_head *p; + struct rchan_reader *found_reader = NULL; + + write_lock(&reader->rchan->open_readers_lock); + list_for_each(p, &reader->rchan->open_readers) { + found_reader = list_entry(p, struct rchan_reader, list); + if (found_reader == reader) { + list_del(&found_reader->list); + break; + } + } + write_unlock(&reader->rchan->open_readers_lock); + + if (found_reader) + kfree(found_reader); +} + +/** + * remove_rchan_reader - destroy a channel reader + * @reader: channel reader + * + * Finds and removes the given reader from the channel. This function + * is useful only for non-VFS readers. + * + * Returns 0 if successful, negative otherwise. + */ +int +remove_rchan_reader(struct rchan_reader *reader) +{ + int err = 0; + + if (reader) { + rchan_put(reader->rchan); + __remove_rchan_reader(reader); + } else + err = -EINVAL; + + return err; +} + +/** + * remove_map_reader - destroy a map reader + * @reader: channel reader + * + * Finds and removes the given map reader from the channel. This function + * is useful only for map readers. + * + * Returns 0 if successful, negative otherwise. + */ +int +remove_map_reader(struct rchan_reader *reader) +{ + return remove_rchan_reader(reader); +} + +EXPORT_SYMBOL(relay_open); +EXPORT_SYMBOL(relay_close); +EXPORT_SYMBOL(relay_reset); +EXPORT_SYMBOL(relay_reserve); +EXPORT_SYMBOL(relay_commit); +EXPORT_SYMBOL(relay_read); +EXPORT_SYMBOL(relay_write); +EXPORT_SYMBOL(relay_bytes_avail); +EXPORT_SYMBOL(relay_buffers_consumed); +EXPORT_SYMBOL(relay_bytes_consumed); +EXPORT_SYMBOL(relay_info); +EXPORT_SYMBOL(relay_discard_init_buf); + + diff --git a/fs/relayfs/relay_locking.c b/fs/relayfs/relay_locking.c new file mode 100644 index 000000000..718f14967 --- /dev/null +++ b/fs/relayfs/relay_locking.c @@ -0,0 +1,322 @@ +/* + * RelayFS locking scheme implementation. + * + * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * + * This file is released under the GPL. + */ + +#include +#include "relay_locking.h" +#include "resize.h" + +/** + * switch_buffers - switches between read and write buffers. + * @cur_time: current time. + * @cur_tsc: the TSC associated with current_time, if applicable + * @rchan: the channel + * @finalizing: if true, don't start a new buffer + * @resetting: if true, + * + * This should be called from with interrupts disabled. + */ +static void +switch_buffers(struct timeval cur_time, + u32 cur_tsc, + struct rchan *rchan, + int finalizing, + int resetting, + int finalize_buffer_only) +{ + char *chan_buf_end; + int bytes_written; + + if (!rchan->half_switch) { + bytes_written = rchan->callbacks->buffer_end(rchan->id, + cur_write_pos(rchan), write_buf_end(rchan), + cur_time, cur_tsc, using_tsc(rchan)); + if (bytes_written == 0) + rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = + write_buf_end(rchan) - cur_write_pos(rchan); + } + + if (finalize_buffer_only) { + rchan->bufs_produced++; + return; + } + + chan_buf_end = rchan->buf + rchan->n_bufs * rchan->buf_size; + if((write_buf(rchan) + rchan->buf_size >= chan_buf_end) || resetting) + write_buf(rchan) = rchan->buf; + else + write_buf(rchan) += rchan->buf_size; + write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size; + write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve; + cur_write_pos(rchan) = write_buf(rchan); + + rchan->buf_start_time = cur_time; + rchan->buf_start_tsc = cur_tsc; + + if (resetting) + rchan->buf_idx = 0; + else + rchan->buf_idx++; + rchan->buf_id++; + + if (!packet_delivery(rchan)) + rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 0; + + if (resetting) { + rchan->bufs_produced = rchan->bufs_produced + rchan->n_bufs; + rchan->bufs_produced -= rchan->bufs_produced % rchan->n_bufs; + rchan->bufs_consumed = rchan->bufs_produced; + rchan->bytes_consumed = 0; + update_readers_consumed(rchan, rchan->bufs_consumed, rchan->bytes_consumed); + } else if (!rchan->half_switch) + rchan->bufs_produced++; + + rchan->half_switch = 0; + + if (!finalizing) { + bytes_written = rchan->callbacks->buffer_start(rchan->id, cur_write_pos(rchan), rchan->buf_id, cur_time, cur_tsc, using_tsc(rchan)); + cur_write_pos(rchan) += bytes_written; + } +} + +/** + * locking_reserve - reserve a slot in the buffer for an event. + * @rchan: the channel + * @slot_len: the length of the slot to reserve + * @ts: variable that will receive the time the slot was reserved + * @tsc: the timestamp counter associated with time + * @err: receives the result flags + * @interrupting: if this write is interrupting another, set to non-zero + * + * Returns pointer to the beginning of the reserved slot, NULL if error. + * + * The err value contains the result flags and is an ORed combination + * of the following: + * + * RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred + * RELAY_EVENT_DISCARD_NONE - event should not be discarded + * RELAY_BUFFER_SWITCH - buffer switch occurred + * RELAY_EVENT_DISCARD - event should be discarded (all buffers are full) + * RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer + */ +inline char * +locking_reserve(struct rchan *rchan, + u32 slot_len, + struct timeval *ts, + u32 *tsc, + int *err, + int *interrupting) +{ + u32 buffers_ready; + int bytes_written; + + *err = RELAY_BUFFER_SWITCH_NONE; + + if (slot_len >= rchan->buf_size) { + *err = RELAY_WRITE_DISCARD | RELAY_WRITE_TOO_LONG; + return NULL; + } + + if (rchan->initialized == 0) { + rchan->initialized = 1; + get_timestamp(&rchan->buf_start_time, + &rchan->buf_start_tsc, rchan); + rchan->unused_bytes[0] = 0; + bytes_written = rchan->callbacks->buffer_start( + rchan->id, cur_write_pos(rchan), + rchan->buf_id, rchan->buf_start_time, + rchan->buf_start_tsc, using_tsc(rchan)); + cur_write_pos(rchan) += bytes_written; + *tsc = get_time_delta(ts, rchan); + return cur_write_pos(rchan); + } + + *tsc = get_time_delta(ts, rchan); + + if (in_progress_event_size(rchan)) { + interrupted_pos(rchan) = cur_write_pos(rchan); + cur_write_pos(rchan) = in_progress_event_pos(rchan) + + in_progress_event_size(rchan) + + interrupting_size(rchan); + *interrupting = 1; + } else { + in_progress_event_pos(rchan) = cur_write_pos(rchan); + in_progress_event_size(rchan) = slot_len; + interrupting_size(rchan) = 0; + } + + if (cur_write_pos(rchan) + slot_len > write_limit(rchan)) { + if (atomic_read(&rchan->suspended) == 1) { + in_progress_event_pos(rchan) = NULL; + in_progress_event_size(rchan) = 0; + interrupting_size(rchan) = 0; + *err = RELAY_WRITE_DISCARD; + return NULL; + } + + buffers_ready = rchan->bufs_produced - rchan->bufs_consumed; + if (buffers_ready == rchan->n_bufs - 1) { + if (!mode_continuous(rchan)) { + atomic_set(&rchan->suspended, 1); + in_progress_event_pos(rchan) = NULL; + in_progress_event_size(rchan) = 0; + interrupting_size(rchan) = 0; + get_timestamp(ts, tsc, rchan); + switch_buffers(*ts, *tsc, rchan, 0, 0, 1); + recalc_time_delta(ts, tsc, rchan); + rchan->half_switch = 1; + + cur_write_pos(rchan) = write_buf_end(rchan) - 1; + *err = RELAY_BUFFER_SWITCH | RELAY_WRITE_DISCARD; + return NULL; + } + } + + get_timestamp(ts, tsc, rchan); + switch_buffers(*ts, *tsc, rchan, 0, 0, 0); + recalc_time_delta(ts, tsc, rchan); + *err = RELAY_BUFFER_SWITCH; + } + + return cur_write_pos(rchan); +} + +/** + * locking_commit - commit a reserved slot in the buffer + * @rchan: the channel + * @from: commit the length starting here + * @len: length committed + * @deliver: length committed + * @interrupting: not used + * + * Commits len bytes and calls deliver callback if applicable. + */ +inline void +locking_commit(struct rchan *rchan, + char *from, + u32 len, + int deliver, + int interrupting) +{ + cur_write_pos(rchan) += len; + + if (interrupting) { + cur_write_pos(rchan) = interrupted_pos(rchan); + interrupting_size(rchan) += len; + } else { + in_progress_event_size(rchan) = 0; + if (interrupting_size(rchan)) { + cur_write_pos(rchan) += interrupting_size(rchan); + interrupting_size(rchan) = 0; + } + } + + if (deliver) { + if (bulk_delivery(rchan)) { + u32 cur_idx = cur_write_pos(rchan) - rchan->buf; + u32 cur_bufno = cur_idx / rchan->buf_size; + from = rchan->buf + cur_bufno * rchan->buf_size; + len = cur_idx - cur_bufno * rchan->buf_size; + } + rchan->callbacks->deliver(rchan->id, from, len); + expand_check(rchan); + } +} + +/** + * locking_finalize: - finalize last buffer at end of channel use + * @rchan: the channel + */ +inline void +locking_finalize(struct rchan *rchan) +{ + unsigned long int flags; + struct timeval time; + u32 tsc; + + local_irq_save(flags); + get_timestamp(&time, &tsc, rchan); + switch_buffers(time, tsc, rchan, 1, 0, 0); + local_irq_restore(flags); +} + +/** + * locking_get_offset - get current and max 'file' offsets for VFS + * @rchan: the channel + * @max_offset: maximum channel offset + * + * Returns the current and maximum buffer offsets in VFS terms. + */ +u32 +locking_get_offset(struct rchan *rchan, + u32 *max_offset) +{ + if (max_offset) + *max_offset = rchan->buf_size * rchan->n_bufs - 1; + + return cur_write_pos(rchan) - rchan->buf; +} + +/** + * locking_reset - reset the channel + * @rchan: the channel + * @init: 1 if this is a first-time channel initialization + */ +void locking_reset(struct rchan *rchan, int init) +{ + if (init) + channel_lock(rchan) = SPIN_LOCK_UNLOCKED; + write_buf(rchan) = rchan->buf; + write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size; + cur_write_pos(rchan) = write_buf(rchan); + write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve; + in_progress_event_pos(rchan) = NULL; + in_progress_event_size(rchan) = 0; + interrupted_pos(rchan) = NULL; + interrupting_size(rchan) = 0; +} + +/** + * locking_reset_index - atomically set channel index to the beginning + * @rchan: the channel + * + * If this fails, it means that something else just logged something + * and therefore we probably no longer want to do this. It's up to the + * caller anyway... + * + * Returns 0 if the index was successfully set, negative otherwise + */ +int +locking_reset_index(struct rchan *rchan, u32 old_idx) +{ + unsigned long flags; + struct timeval time; + u32 tsc; + u32 cur_idx; + + relay_lock_channel(rchan, flags); + cur_idx = locking_get_offset(rchan, NULL); + if (cur_idx != old_idx) { + relay_unlock_channel(rchan, flags); + return -1; + } + + get_timestamp(&time, &tsc, rchan); + switch_buffers(time, tsc, rchan, 0, 1, 0); + + relay_unlock_channel(rchan, flags); + + return 0; +} + + + + + + + diff --git a/fs/relayfs/relay_locking.h b/fs/relayfs/relay_locking.h new file mode 100644 index 000000000..3dde7df52 --- /dev/null +++ b/fs/relayfs/relay_locking.h @@ -0,0 +1,34 @@ +#ifndef _RELAY_LOCKING_H +#define _RELAY_LOCKING_H + +extern char * +locking_reserve(struct rchan *rchan, + u32 slot_len, + struct timeval *time_stamp, + u32 *tsc, + int *err, + int *interrupting); + +extern void +locking_commit(struct rchan *rchan, + char *from, + u32 len, + int deliver, + int interrupting); + +extern void +locking_resume(struct rchan *rchan); + +extern void +locking_finalize(struct rchan *rchan); + +extern u32 +locking_get_offset(struct rchan *rchan, u32 *max_offset); + +extern void +locking_reset(struct rchan *rchan, int init); + +extern int +locking_reset_index(struct rchan *rchan, u32 old_idx); + +#endif /* _RELAY_LOCKING_H */ diff --git a/fs/relayfs/relay_lockless.c b/fs/relayfs/relay_lockless.c new file mode 100644 index 000000000..98524bf61 --- /dev/null +++ b/fs/relayfs/relay_lockless.c @@ -0,0 +1,541 @@ +/* + * RelayFS lockless scheme implementation. + * + * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 2002, 2003 - Bob Wisniewski (bob@watson.ibm.com), IBM Corp + * + * This file is released under the GPL. + */ + +#include +#include "relay_lockless.h" +#include "resize.h" + +/** + * compare_and_store_volatile - self-explicit + * @ptr: ptr to the word that will receive the new value + * @oval: the value we think is currently in *ptr + * @nval: the value *ptr will get if we were right + */ +inline int +compare_and_store_volatile(volatile u32 *ptr, + u32 oval, + u32 nval) +{ + u32 prev; + + barrier(); + prev = cmpxchg(ptr, oval, nval); + barrier(); + + return (prev == oval); +} + +/** + * atomic_set_volatile - atomically set the value in ptr to nval. + * @ptr: ptr to the word that will receive the new value + * @nval: the new value + */ +inline void +atomic_set_volatile(atomic_t *ptr, + u32 nval) +{ + barrier(); + atomic_set(ptr, (int)nval); + barrier(); +} + +/** + * atomic_add_volatile - atomically add val to the value at ptr. + * @ptr: ptr to the word that will receive the addition + * @val: the value to add to *ptr + */ +inline void +atomic_add_volatile(atomic_t *ptr, u32 val) +{ + barrier(); + atomic_add((int)val, ptr); + barrier(); +} + +/** + * atomic_sub_volatile - atomically substract val from the value at ptr. + * @ptr: ptr to the word that will receive the subtraction + * @val: the value to subtract from *ptr + */ +inline void +atomic_sub_volatile(atomic_t *ptr, s32 val) +{ + barrier(); + atomic_sub((int)val, ptr); + barrier(); +} + +/** + * lockless_commit - commit a reserved slot in the buffer + * @rchan: the channel + * @from: commit the length starting here + * @len: length committed + * @deliver: length committed + * @interrupting: not used + * + * Commits len bytes and calls deliver callback if applicable. + */ +inline void +lockless_commit(struct rchan *rchan, + char *from, + u32 len, + int deliver, + int interrupting) +{ + u32 bufno, idx; + + idx = from - rchan->buf; + + if (len > 0) { + bufno = RELAY_BUFNO_GET(idx, offset_bits(rchan)); + atomic_add_volatile(&fill_count(rchan, bufno), len); + } + + if (deliver) { + u32 mask = offset_mask(rchan); + if (bulk_delivery(rchan)) { + from = rchan->buf + RELAY_BUF_OFFSET_CLEAR(idx, mask); + len += RELAY_BUF_OFFSET_GET(idx, mask); + } + rchan->callbacks->deliver(rchan->id, from, len); + expand_check(rchan); + } +} + +/** + * get_buffer_end - get the address of the end of buffer + * @rchan: the channel + * @buf_idx: index into channel corresponding to address + */ +static inline char * +get_buffer_end(struct rchan *rchan, u32 buf_idx) +{ + return rchan->buf + + RELAY_BUF_OFFSET_CLEAR(buf_idx, offset_mask(rchan)) + + RELAY_BUF_SIZE(offset_bits(rchan)); +} + + +/** + * finalize_buffer - utility function consolidating end-of-buffer tasks. + * @rchan: the channel + * @end_idx: index into buffer to write the end-buffer event at + * @size_lost: number of unused bytes at the end of the buffer + * @time_stamp: the time of the end-buffer event + * @tsc: the timestamp counter associated with time + * @resetting: are we resetting the channel? + * + * This function must be called with local irqs disabled. + */ +static inline void +finalize_buffer(struct rchan *rchan, + u32 end_idx, + u32 size_lost, + struct timeval *time_stamp, + u32 *tsc, + int resetting) +{ + char* cur_write_pos; + char* write_buf_end; + u32 bufno; + int bytes_written; + + cur_write_pos = rchan->buf + end_idx; + write_buf_end = get_buffer_end(rchan, end_idx - 1); + + bytes_written = rchan->callbacks->buffer_end(rchan->id, cur_write_pos, + write_buf_end, *time_stamp, *tsc, using_tsc(rchan)); + if (bytes_written == 0) + rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = size_lost; + + bufno = RELAY_BUFNO_GET(end_idx, offset_bits(rchan)); + atomic_add_volatile(&fill_count(rchan, bufno), size_lost); + if (resetting) { + rchan->bufs_produced = rchan->bufs_produced + rchan->n_bufs; + rchan->bufs_produced -= rchan->bufs_produced % rchan->n_bufs; + rchan->bufs_consumed = rchan->bufs_produced; + rchan->bytes_consumed = 0; + update_readers_consumed(rchan, rchan->bufs_consumed, rchan->bytes_consumed); + } else + rchan->bufs_produced++; +} + +/** + * lockless_finalize: - finalize last buffer at end of channel use + * @rchan: the channel + */ +inline void +lockless_finalize(struct rchan *rchan) +{ + u32 event_end_idx; + u32 size_lost; + unsigned long int flags; + struct timeval time; + u32 tsc; + + event_end_idx = RELAY_BUF_OFFSET_GET(idx(rchan), offset_mask(rchan)); + size_lost = RELAY_BUF_SIZE(offset_bits(rchan)) - event_end_idx; + + local_irq_save(flags); + get_timestamp(&time, &tsc, rchan); + finalize_buffer(rchan, idx(rchan) & idx_mask(rchan), size_lost, + &time, &tsc, 0); + local_irq_restore(flags); +} + +/** + * discard_check: - determine whether a write should be discarded + * @rchan: the channel + * @old_idx: index into buffer where check for space should begin + * @write_len: the length of the write to check + * @time_stamp: the time of the end-buffer event + * @tsc: the timestamp counter associated with time + * + * The return value contains the result flags and is an ORed combination + * of the following: + * + * RELAY_WRITE_DISCARD_NONE - write should not be discarded + * RELAY_BUFFER_SWITCH - buffer switch occurred + * RELAY_WRITE_DISCARD - write should be discarded (all buffers are full) + * RELAY_WRITE_TOO_LONG - write won't fit into even an empty buffer + */ +static inline int +discard_check(struct rchan *rchan, + u32 old_idx, + u32 write_len, + struct timeval *time_stamp, + u32 *tsc) +{ + u32 buffers_ready; + u32 offset_mask = offset_mask(rchan); + u8 offset_bits = offset_bits(rchan); + u32 idx_mask = idx_mask(rchan); + u32 size_lost; + unsigned long int flags; + + if (write_len > RELAY_BUF_SIZE(offset_bits)) + return RELAY_WRITE_DISCARD | RELAY_WRITE_TOO_LONG; + + if (mode_continuous(rchan)) + return RELAY_WRITE_DISCARD_NONE; + + local_irq_save(flags); + if (atomic_read(&rchan->suspended) == 1) { + local_irq_restore(flags); + return RELAY_WRITE_DISCARD; + } + if (rchan->half_switch) { + local_irq_restore(flags); + return RELAY_WRITE_DISCARD_NONE; + } + buffers_ready = rchan->bufs_produced - rchan->bufs_consumed; + if (buffers_ready == rchan->n_bufs - 1) { + atomic_set(&rchan->suspended, 1); + size_lost = RELAY_BUF_SIZE(offset_bits) + - RELAY_BUF_OFFSET_GET(old_idx, offset_mask); + finalize_buffer(rchan, old_idx & idx_mask, size_lost, + time_stamp, tsc, 0); + rchan->half_switch = 1; + idx(rchan) = RELAY_BUF_OFFSET_CLEAR((old_idx & idx_mask), offset_mask(rchan)) + RELAY_BUF_SIZE(offset_bits) - 1; + local_irq_restore(flags); + + return RELAY_BUFFER_SWITCH | RELAY_WRITE_DISCARD; + } + local_irq_restore(flags); + + return RELAY_WRITE_DISCARD_NONE; +} + +/** + * switch_buffers - switch over to a new sub-buffer + * @rchan: the channel + * @slot_len: the length of the slot needed for the current write + * @offset: the offset calculated for the new index + * @ts: timestamp + * @tsc: the timestamp counter associated with time + * @old_idx: the value of the buffer control index when we were called + * @old_idx: the new calculated value of the buffer control index + * @resetting: are we resetting the channel? + */ +static inline void +switch_buffers(struct rchan *rchan, + u32 slot_len, + u32 offset, + struct timeval *ts, + u32 *tsc, + u32 new_idx, + u32 old_idx, + int resetting) +{ + u32 size_lost = rchan->end_reserve; + unsigned long int flags; + u32 idx_mask = idx_mask(rchan); + u8 offset_bits = offset_bits(rchan); + char *cur_write_pos; + u32 new_buf_no; + u32 start_reserve = rchan->start_reserve; + + if (resetting) + size_lost = RELAY_BUF_SIZE(offset_bits(rchan)) - old_idx % rchan->buf_size; + + if (offset > 0) + size_lost += slot_len - offset; + else + old_idx += slot_len; + + local_irq_save(flags); + if (!rchan->half_switch) + finalize_buffer(rchan, old_idx & idx_mask, size_lost, + ts, tsc, resetting); + rchan->half_switch = 0; + rchan->buf_start_time = *ts; + rchan->buf_start_tsc = *tsc; + local_irq_restore(flags); + + cur_write_pos = rchan->buf + RELAY_BUF_OFFSET_CLEAR((new_idx + & idx_mask), offset_mask(rchan)); + if (resetting) + rchan->buf_idx = 0; + else + rchan->buf_idx++; + rchan->buf_id++; + + rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 0; + + rchan->callbacks->buffer_start(rchan->id, cur_write_pos, + rchan->buf_id, *ts, *tsc, using_tsc(rchan)); + new_buf_no = RELAY_BUFNO_GET(new_idx & idx_mask, offset_bits); + atomic_sub_volatile(&fill_count(rchan, new_buf_no), + RELAY_BUF_SIZE(offset_bits) - start_reserve); + if (atomic_read(&fill_count(rchan, new_buf_no)) < start_reserve) + atomic_set_volatile(&fill_count(rchan, new_buf_no), + start_reserve); +} + +/** + * lockless_reserve_slow - the slow reserve path in the lockless scheme + * @rchan: the channel + * @slot_len: the length of the slot to reserve + * @ts: variable that will receive the time the slot was reserved + * @tsc: the timestamp counter associated with time + * @old_idx: the value of the buffer control index when we were called + * @err: receives the result flags + * + * Returns pointer to the beginning of the reserved slot, NULL if error. + + * err values same as for lockless_reserve. + */ +static inline char * +lockless_reserve_slow(struct rchan *rchan, + u32 slot_len, + struct timeval *ts, + u32 *tsc, + u32 old_idx, + int *err) +{ + u32 new_idx, offset; + unsigned long int flags; + u32 offset_mask = offset_mask(rchan); + u32 idx_mask = idx_mask(rchan); + u32 start_reserve = rchan->start_reserve; + u32 end_reserve = rchan->end_reserve; + int discard_event; + u32 reserved_idx; + char *cur_write_pos; + int initializing = 0; + + *err = RELAY_BUFFER_SWITCH_NONE; + + discard_event = discard_check(rchan, old_idx, slot_len, ts, tsc); + if (discard_event != RELAY_WRITE_DISCARD_NONE) { + *err = discard_event; + return NULL; + } + + local_irq_save(flags); + if (rchan->initialized == 0) { + rchan->initialized = initializing = 1; + idx(rchan) = rchan->start_reserve + rchan->rchan_start_reserve; + } + local_irq_restore(flags); + + do { + old_idx = idx(rchan); + new_idx = old_idx + slot_len; + + offset = RELAY_BUF_OFFSET_GET(new_idx + end_reserve, + offset_mask); + if ((offset < slot_len) && (offset > 0)) { + reserved_idx = RELAY_BUF_OFFSET_CLEAR(new_idx + + end_reserve, offset_mask) + start_reserve; + new_idx = reserved_idx + slot_len; + } else if (offset < slot_len) { + reserved_idx = old_idx; + new_idx = RELAY_BUF_OFFSET_CLEAR(new_idx + + end_reserve, offset_mask) + start_reserve; + } else + reserved_idx = old_idx; + get_timestamp(ts, tsc, rchan); + } while (!compare_and_store_volatile(&idx(rchan), old_idx, new_idx)); + + reserved_idx &= idx_mask; + + if (initializing == 1) { + cur_write_pos = rchan->buf + + RELAY_BUF_OFFSET_CLEAR((old_idx & idx_mask), + offset_mask(rchan)); + rchan->buf_start_time = *ts; + rchan->buf_start_tsc = *tsc; + rchan->unused_bytes[0] = 0; + + rchan->callbacks->buffer_start(rchan->id, cur_write_pos, + rchan->buf_id, *ts, *tsc, using_tsc(rchan)); + } + + if (offset < slot_len) { + switch_buffers(rchan, slot_len, offset, ts, tsc, new_idx, + old_idx, 0); + *err = RELAY_BUFFER_SWITCH; + } + + /* If not using TSC, need to calc time delta */ + recalc_time_delta(ts, tsc, rchan); + + return rchan->buf + reserved_idx; +} + +/** + * lockless_reserve - reserve a slot in the buffer for an event. + * @rchan: the channel + * @slot_len: the length of the slot to reserve + * @ts: variable that will receive the time the slot was reserved + * @tsc: the timestamp counter associated with time + * @err: receives the result flags + * @interrupting: not used + * + * Returns pointer to the beginning of the reserved slot, NULL if error. + * + * The err value contains the result flags and is an ORed combination + * of the following: + * + * RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred + * RELAY_EVENT_DISCARD_NONE - event should not be discarded + * RELAY_BUFFER_SWITCH - buffer switch occurred + * RELAY_EVENT_DISCARD - event should be discarded (all buffers are full) + * RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer + */ +inline char * +lockless_reserve(struct rchan *rchan, + u32 slot_len, + struct timeval *ts, + u32 *tsc, + int *err, + int *interrupting) +{ + u32 old_idx, new_idx, offset; + u32 offset_mask = offset_mask(rchan); + + do { + old_idx = idx(rchan); + new_idx = old_idx + slot_len; + + offset = RELAY_BUF_OFFSET_GET(new_idx + rchan->end_reserve, + offset_mask); + if (offset < slot_len) + return lockless_reserve_slow(rchan, slot_len, + ts, tsc, old_idx, err); + get_time_or_tsc(ts, tsc, rchan); + } while (!compare_and_store_volatile(&idx(rchan), old_idx, new_idx)); + + /* If not using TSC, need to calc time delta */ + recalc_time_delta(ts, tsc, rchan); + + *err = RELAY_BUFFER_SWITCH_NONE; + + return rchan->buf + (old_idx & idx_mask(rchan)); +} + +/** + * lockless_get_offset - get current and max channel offsets + * @rchan: the channel + * @max_offset: maximum channel offset + * + * Returns the current and maximum channel offsets. + */ +u32 +lockless_get_offset(struct rchan *rchan, + u32 *max_offset) +{ + if (max_offset) + *max_offset = rchan->buf_size * rchan->n_bufs - 1; + + return rchan->initialized ? idx(rchan) & idx_mask(rchan) : 0; +} + +/** + * lockless_reset - reset the channel + * @rchan: the channel + * @init: 1 if this is a first-time channel initialization + */ +void lockless_reset(struct rchan *rchan, int init) +{ + int i; + + /* Start first buffer at 0 - (end_reserve + 1) so that it + gets initialized via buffer_start callback as well. */ + idx(rchan) = 0UL - (rchan->end_reserve + 1); + idx_mask(rchan) = + (1UL << (bufno_bits(rchan) + offset_bits(rchan))) - 1; + atomic_set(&fill_count(rchan, 0), + (int)rchan->start_reserve + + (int)rchan->rchan_start_reserve); + for (i = 1; i < rchan->n_bufs; i++) + atomic_set(&fill_count(rchan, i), + (int)RELAY_BUF_SIZE(offset_bits(rchan))); +} + +/** + * lockless_reset_index - atomically set channel index to the beginning + * @rchan: the channel + * @old_idx: the current index + * + * If this fails, it means that something else just logged something + * and therefore we probably no longer want to do this. It's up to the + * caller anyway... + * + * Returns 0 if the index was successfully set, negative otherwise + */ +int +lockless_reset_index(struct rchan *rchan, u32 old_idx) +{ + struct timeval ts; + u32 tsc; + u32 new_idx; + + if (compare_and_store_volatile(&idx(rchan), old_idx, 0)) { + new_idx = rchan->start_reserve; + switch_buffers(rchan, 0, 0, &ts, &tsc, new_idx, old_idx, 1); + return 0; + } else + return -1; +} + + + + + + + + + + + + + diff --git a/fs/relayfs/relay_lockless.h b/fs/relayfs/relay_lockless.h new file mode 100644 index 000000000..8d4189e8c --- /dev/null +++ b/fs/relayfs/relay_lockless.h @@ -0,0 +1,34 @@ +#ifndef _RELAY_LOCKLESS_H +#define _RELAY_LOCKLESS_H + +extern char * +lockless_reserve(struct rchan *rchan, + u32 slot_len, + struct timeval *time_stamp, + u32 *tsc, + int * interrupting, + int * errcode); + +extern void +lockless_commit(struct rchan *rchan, + char * from, + u32 len, + int deliver, + int interrupting); + +extern void +lockless_resume(struct rchan *rchan); + +extern void +lockless_finalize(struct rchan *rchan); + +extern u32 +lockless_get_offset(struct rchan *rchan, u32 *max_offset); + +extern void +lockless_reset(struct rchan *rchan, int init); + +extern int +lockless_reset_index(struct rchan *rchan, u32 old_idx); + +#endif/* _RELAY_LOCKLESS_H */ diff --git a/fs/relayfs/resize.c b/fs/relayfs/resize.c new file mode 100644 index 000000000..25f00bfa6 --- /dev/null +++ b/fs/relayfs/resize.c @@ -0,0 +1,1091 @@ +/* + * RelayFS buffer management and resizing code. + * + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include "resize.h" + +/** + * alloc_page_array - alloc array to hold pages, but not pages + * @size: the total size of the memory represented by the page array + * @page_count: the number of pages the array can hold + * @err: 0 on success, negative otherwise + * + * Returns a pointer to the page array if successful, NULL otherwise. + */ +static struct page ** +alloc_page_array(int size, int *page_count, int *err) +{ + int n_pages; + struct page **page_array; + int page_array_size; + + *err = 0; + + size = PAGE_ALIGN(size); + n_pages = size >> PAGE_SHIFT; + page_array_size = n_pages * sizeof(struct page *); + page_array = kmalloc(page_array_size, GFP_KERNEL); + if (page_array == NULL) { + *err = -ENOMEM; + return NULL; + } + *page_count = n_pages; + memset(page_array, 0, page_array_size); + + return page_array; +} + +/** + * free_page_array - free array to hold pages, but not pages + * @page_array: pointer to the page array + */ +static inline void +free_page_array(struct page **page_array) +{ + kfree(page_array); +} + +/** + * depopulate_page_array - free and unreserve all pages in the array + * @page_array: pointer to the page array + * @page_count: number of pages to free + */ +static void +depopulate_page_array(struct page **page_array, int page_count) +{ + int i; + + for (i = 0; i < page_count; i++) { + ClearPageReserved(page_array[i]); + __free_page(page_array[i]); + } +} + +/** + * populate_page_array - allocate and reserve pages + * @page_array: pointer to the page array + * @page_count: number of pages to allocate + * + * Returns 0 if successful, negative otherwise. + */ +static int +populate_page_array(struct page **page_array, int page_count) +{ + int i; + + for (i = 0; i < page_count; i++) { + page_array[i] = alloc_page(GFP_KERNEL); + if (unlikely(!page_array[i])) { + depopulate_page_array(page_array, i); + return -ENOMEM; + } + SetPageReserved(page_array[i]); + } + return 0; +} + +/** + * alloc_rchan_buf - allocate the initial channel buffer + * @size: total size of the buffer + * @page_array: receives a pointer to the buffer's page array + * @page_count: receives the number of pages allocated + * + * Returns a pointer to the resulting buffer, NULL if unsuccessful + */ +void * +alloc_rchan_buf(unsigned long size, struct page ***page_array, int *page_count) +{ + void *mem; + int err; + + *page_array = alloc_page_array(size, page_count, &err); + if (!*page_array) + return NULL; + + err = populate_page_array(*page_array, *page_count); + if (err) { + free_page_array(*page_array); + *page_array = NULL; + return NULL; + } + + mem = vmap(*page_array, *page_count, GFP_KERNEL, PAGE_KERNEL); + if (!mem) { + depopulate_page_array(*page_array, *page_count); + free_page_array(*page_array); + *page_array = NULL; + return NULL; + } + memset(mem, 0, size); + + return mem; +} + +/** + * free_rchan_buf - free a channel buffer + * @buf: pointer to the buffer to free + * @page_array: pointer to the buffer's page array + * @page_count: number of pages in page array + */ +void +free_rchan_buf(void *buf, struct page **page_array, int page_count) +{ + vunmap(buf); + depopulate_page_array(page_array, page_count); + free_page_array(page_array); +} + +/** + * expand_check - check whether the channel needs expanding + * @rchan: the channel + * + * If the channel needs expanding, the needs_resize callback is + * called with RELAY_RESIZE_EXPAND. + * + * Returns the suggested number of sub-buffers for the new + * buffer. + */ +void +expand_check(struct rchan *rchan) +{ + u32 active_bufs; + u32 new_n_bufs = 0; + u32 threshold = rchan->n_bufs * RESIZE_THRESHOLD; + + if (rchan->init_buf) + return; + + if (rchan->resize_min == 0) + return; + + if (rchan->resizing || rchan->replace_buffer) + return; + + active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1; + + if (rchan->resize_max && active_bufs == threshold) { + new_n_bufs = rchan->n_bufs * 2; + } + + if (new_n_bufs && (new_n_bufs * rchan->buf_size <= rchan->resize_max)) + rchan->callbacks->needs_resize(rchan->id, + RELAY_RESIZE_EXPAND, + rchan->buf_size, + new_n_bufs); +} + +/** + * can_shrink - check whether the channel can shrink + * @rchan: the channel + * @cur_idx: the current channel index + * + * Returns the suggested number of sub-buffers for the new + * buffer, 0 if the buffer is not shrinkable. + */ +static inline u32 +can_shrink(struct rchan *rchan, u32 cur_idx) +{ + u32 active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1; + u32 new_n_bufs = 0; + u32 cur_bufno_bytes = cur_idx % rchan->buf_size; + + if (rchan->resize_min == 0 || + rchan->resize_min >= rchan->n_bufs * rchan->buf_size) + goto out; + + if (active_bufs > 1) + goto out; + + if (cur_bufno_bytes != rchan->bytes_consumed) + goto out; + + new_n_bufs = rchan->resize_min / rchan->buf_size; +out: + return new_n_bufs; +} + +/** + * shrink_check: - timer function checking whether the channel can shrink + * @data: unused + * + * Every SHRINK_TIMER_SECS, check whether the channel is shrinkable. + * If so, we attempt to atomically reset the channel to the beginning. + * The needs_resize callback is then called with RELAY_RESIZE_SHRINK. + * If the reset fails, it means we really shouldn't be shrinking now + * and need to wait until the next time around. + */ +static void +shrink_check(unsigned long data) +{ + struct rchan *rchan = (struct rchan *)data; + u32 shrink_to_nbufs, cur_idx; + + del_timer(&rchan->shrink_timer); + rchan->shrink_timer.expires = jiffies + SHRINK_TIMER_SECS * HZ; + add_timer(&rchan->shrink_timer); + + if (rchan->init_buf) + return; + + if (rchan->resizing || rchan->replace_buffer) + return; + + if (using_lockless(rchan)) + cur_idx = idx(rchan); + else + cur_idx = relay_get_offset(rchan, NULL); + + shrink_to_nbufs = can_shrink(rchan, cur_idx); + if (shrink_to_nbufs != 0 && reset_index(rchan, cur_idx) == 0) { + update_readers_consumed(rchan, rchan->bufs_consumed, 0); + rchan->callbacks->needs_resize(rchan->id, + RELAY_RESIZE_SHRINK, + rchan->buf_size, + shrink_to_nbufs); + } +} + +/** + * init_shrink_timer: - Start timer used to check shrinkability. + * @rchan: the channel + */ +void +init_shrink_timer(struct rchan *rchan) +{ + if (rchan->resize_min) { + init_timer(&rchan->shrink_timer); + rchan->shrink_timer.function = shrink_check; + rchan->shrink_timer.data = (unsigned long)rchan; + rchan->shrink_timer.expires = jiffies + SHRINK_TIMER_SECS * HZ; + add_timer(&rchan->shrink_timer); + } +} + + +/** + * alloc_new_pages - allocate new pages for expanding buffer + * @rchan: the channel + * + * Returns 0 on success, negative otherwise. + */ +static int +alloc_new_pages(struct rchan *rchan) +{ + int new_pages_size, err; + + if (unlikely(rchan->expand_page_array)) BUG(); + + new_pages_size = rchan->resize_alloc_size - rchan->alloc_size; + rchan->expand_page_array = alloc_page_array(new_pages_size, + &rchan->expand_page_count, &err); + if (rchan->expand_page_array == NULL) { + rchan->resize_err = -ENOMEM; + return -ENOMEM; + } + + err = populate_page_array(rchan->expand_page_array, + rchan->expand_page_count); + if (err) { + rchan->resize_err = -ENOMEM; + free_page_array(rchan->expand_page_array); + rchan->expand_page_array = NULL; + } + + return err; +} + +/** + * clear_resize_offset - helper function for buffer resizing + * @rchan: the channel + * + * Clear the saved offset change. + */ +static inline void +clear_resize_offset(struct rchan *rchan) +{ + rchan->resize_offset.ge = 0UL; + rchan->resize_offset.le = 0UL; + rchan->resize_offset.delta = 0; +} + +/** + * save_resize_offset - helper function for buffer resizing + * @rchan: the channel + * @ge: affected region ge this + * @le: affected region le this + * @delta: apply this delta + * + * Save a resize offset. + */ +static inline void +save_resize_offset(struct rchan *rchan, u32 ge, u32 le, int delta) +{ + rchan->resize_offset.ge = ge; + rchan->resize_offset.le = le; + rchan->resize_offset.delta = delta; +} + +/** + * update_file_offset - apply offset change to reader + * @reader: the channel reader + * @change_idx: the offset index into the offsets array + * + * Returns non-zero if the offset was applied. + * + * Apply the offset delta saved in change_idx to the reader's + * current read position. + */ +static inline int +update_file_offset(struct rchan_reader *reader) +{ + int applied = 0; + struct rchan *rchan = reader->rchan; + u32 f_pos; + int delta = reader->rchan->resize_offset.delta; + + if (reader->vfs_reader) + f_pos = (u32)reader->pos.file->f_pos; + else + f_pos = reader->pos.f_pos; + + if (f_pos == relay_get_offset(rchan, NULL)) + return 0; + + if ((f_pos >= rchan->resize_offset.ge - 1) && + (f_pos <= rchan->resize_offset.le)) { + if (reader->vfs_reader) + reader->pos.file->f_pos += delta; + else + reader->pos.f_pos += delta; + applied = 1; + } + + return applied; +} + +/** + * update_file_offsets - apply offset change to readers + * @rchan: the channel + * + * Apply the saved offset deltas to all files open on the channel. + */ +static inline void +update_file_offsets(struct rchan *rchan) +{ + struct list_head *p; + struct rchan_reader *reader; + + read_lock(&rchan->open_readers_lock); + list_for_each(p, &rchan->open_readers) { + reader = list_entry(p, struct rchan_reader, list); + if (update_file_offset(reader)) + reader->offset_changed = 1; + } + read_unlock(&rchan->open_readers_lock); +} + +/** + * setup_expand_buf - setup expand buffer for replacement + * @rchan: the channel + * @newsize: the size of the new buffer + * @oldsize: the size of the old buffer + * @old_n_bufs: the number of sub-buffers in the old buffer + * + * Inserts new pages into the old buffer to create a larger + * new channel buffer, splitting them at old_cur_idx, the bottom + * half of the old buffer going to the bottom of the new, likewise + * for the top half. + */ +static void +setup_expand_buf(struct rchan *rchan, int newsize, int oldsize, u32 old_n_bufs) +{ + u32 cur_idx; + int cur_bufno, delta, i, j; + u32 ge, le; + int cur_pageno; + u32 free_bufs, free_pages; + u32 free_pages_in_cur_buf; + u32 free_bufs_to_end; + u32 cur_pages = rchan->alloc_size >> PAGE_SHIFT; + u32 pages_per_buf = cur_pages / rchan->n_bufs; + u32 bufs_ready = rchan->bufs_produced - rchan->bufs_consumed; + + if (!rchan->resize_page_array || !rchan->expand_page_array || + !rchan->buf_page_array) + return; + + if (bufs_ready >= rchan->n_bufs) { + bufs_ready = rchan->n_bufs; + free_bufs = 0; + } else + free_bufs = rchan->n_bufs - bufs_ready - 1; + + cur_idx = relay_get_offset(rchan, NULL); + cur_pageno = cur_idx / PAGE_SIZE; + cur_bufno = cur_idx / rchan->buf_size; + + free_pages_in_cur_buf = (pages_per_buf - 1) - (cur_pageno % pages_per_buf); + free_pages = free_bufs * pages_per_buf + free_pages_in_cur_buf; + free_bufs_to_end = (rchan->n_bufs - 1) - cur_bufno; + if (free_bufs >= free_bufs_to_end) { + free_pages = free_bufs_to_end * pages_per_buf + free_pages_in_cur_buf; + free_bufs = free_bufs_to_end; + } + + for (i = 0, j = 0; i <= cur_pageno + free_pages; i++, j++) + rchan->resize_page_array[j] = rchan->buf_page_array[i]; + for (i = 0; i < rchan->expand_page_count; i++, j++) + rchan->resize_page_array[j] = rchan->expand_page_array[i]; + for (i = cur_pageno + free_pages + 1; i < rchan->buf_page_count; i++, j++) + rchan->resize_page_array[j] = rchan->buf_page_array[i]; + + delta = newsize - oldsize; + ge = (cur_pageno + 1 + free_pages) * PAGE_SIZE; + le = oldsize; + save_resize_offset(rchan, ge, le, delta); + + rchan->expand_buf_id = rchan->buf_id + 1 + free_bufs; +} + +/** + * setup_shrink_buf - setup shrink buffer for replacement + * @rchan: the channel + * + * Removes pages from the old buffer to create a smaller + * new channel buffer. + */ +static void +setup_shrink_buf(struct rchan *rchan) +{ + int i; + int copy_end_page; + + if (!rchan->resize_page_array || !rchan->shrink_page_array || + !rchan->buf_page_array) + return; + + copy_end_page = rchan->resize_alloc_size / PAGE_SIZE; + + for (i = 0; i < copy_end_page; i++) + rchan->resize_page_array[i] = rchan->buf_page_array[i]; +} + +/** + * cleanup_failed_alloc - relaybuf_alloc helper + */ +static void +cleanup_failed_alloc(struct rchan *rchan) +{ + if (rchan->expand_page_array) { + depopulate_page_array(rchan->expand_page_array, + rchan->expand_page_count); + free_page_array(rchan->expand_page_array); + rchan->expand_page_array = NULL; + rchan->expand_page_count = 0; + } else if (rchan->shrink_page_array) { + free_page_array(rchan->shrink_page_array); + rchan->shrink_page_array = NULL; + rchan->shrink_page_count = 0; + } + + if (rchan->resize_page_array) { + free_page_array(rchan->resize_page_array); + rchan->resize_page_array = NULL; + rchan->resize_page_count = 0; + } +} + +/** + * relaybuf_alloc - allocate a new resized channel buffer + * @private: pointer to the channel struct + * + * Internal - manages the allocation and remapping of new channel + * buffers. + */ +static void +relaybuf_alloc(void *private) +{ + struct rchan *rchan = (struct rchan *)private; + int i, j, err; + u32 old_cur_idx; + int free_size; + int free_start_page, free_end_page; + u32 newsize, oldsize; + + if (rchan->resize_alloc_size > rchan->alloc_size) { + err = alloc_new_pages(rchan); + if (err) goto cleanup; + } else { + free_size = rchan->alloc_size - rchan->resize_alloc_size; + BUG_ON(free_size <= 0); + rchan->shrink_page_array = alloc_page_array(free_size, + &rchan->shrink_page_count, &err); + if (rchan->shrink_page_array == NULL) + goto cleanup; + free_start_page = rchan->resize_alloc_size / PAGE_SIZE; + free_end_page = rchan->alloc_size / PAGE_SIZE; + for (i = 0, j = free_start_page; j < free_end_page; i++, j++) + rchan->shrink_page_array[i] = rchan->buf_page_array[j]; + } + + rchan->resize_page_array = alloc_page_array(rchan->resize_alloc_size, + &rchan->resize_page_count, &err); + if (rchan->resize_page_array == NULL) + goto cleanup; + + old_cur_idx = relay_get_offset(rchan, NULL); + clear_resize_offset(rchan); + newsize = rchan->resize_alloc_size; + oldsize = rchan->alloc_size; + if (newsize > oldsize) + setup_expand_buf(rchan, newsize, oldsize, rchan->n_bufs); + else + setup_shrink_buf(rchan); + + rchan->resize_buf = vmap(rchan->resize_page_array, rchan->resize_page_count, GFP_KERNEL, PAGE_KERNEL); + + if (rchan->resize_buf == NULL) + goto cleanup; + + rchan->replace_buffer = 1; + rchan->resizing = 0; + + rchan->callbacks->needs_resize(rchan->id, RELAY_RESIZE_REPLACE, 0, 0); + return; + +cleanup: + cleanup_failed_alloc(rchan); + rchan->resize_err = -ENOMEM; + return; +} + +/** + * relaybuf_free - free a resized channel buffer + * @private: pointer to the channel struct + * + * Internal - manages the de-allocation and unmapping of old channel + * buffers. + */ +static void +relaybuf_free(void *private) +{ + struct free_rchan_buf *free_buf = (struct free_rchan_buf *)private; + int i; + + if (free_buf->unmap_buf) + vunmap(free_buf->unmap_buf); + + for (i = 0; i < 3; i++) { + if (!free_buf->page_array[i].array) + continue; + if (free_buf->page_array[i].count) + depopulate_page_array(free_buf->page_array[i].array, + free_buf->page_array[i].count); + free_page_array(free_buf->page_array[i].array); + } + + kfree(free_buf); +} + +/** + * calc_order - determine the power-of-2 order of a resize + * @high: the larger size + * @low: the smaller size + * + * Returns order + */ +static inline int +calc_order(u32 high, u32 low) +{ + int order = 0; + + if (!high || !low || high <= low) + return 0; + + while (high > low) { + order++; + high /= 2; + } + + return order; +} + +/** + * check_size - check the sanity of the requested channel size + * @rchan: the channel + * @nbufs: the new number of sub-buffers + * @err: return code + * + * Returns the non-zero total buffer size if ok, otherwise 0 and + * sets errcode if not. + */ +static inline u32 +check_size(struct rchan *rchan, u32 nbufs, int *err) +{ + u32 new_channel_size = 0; + + *err = 0; + + if (nbufs > rchan->n_bufs) { + rchan->resize_order = calc_order(nbufs, rchan->n_bufs); + if (!rchan->resize_order) { + *err = -EINVAL; + goto out; + } + + new_channel_size = rchan->buf_size * nbufs; + if (new_channel_size > rchan->resize_max) { + *err = -EINVAL; + goto out; + } + } else if (nbufs < rchan->n_bufs) { + if (rchan->n_bufs < 2) { + *err = -EINVAL; + goto out; + } + rchan->resize_order = -calc_order(rchan->n_bufs, nbufs); + if (!rchan->resize_order) { + *err = -EINVAL; + goto out; + } + + new_channel_size = rchan->buf_size * nbufs; + if (new_channel_size < rchan->resize_min) { + *err = -EINVAL; + goto out; + } + } else + *err = -EINVAL; +out: + return new_channel_size; +} + +/** + * __relay_realloc_buffer - allocate a new channel buffer + * @rchan: the channel + * @new_nbufs: the new number of sub-buffers + * @async: do the allocation using a work queue + * + * Internal - see relay_realloc_buffer() for details. + */ +static int +__relay_realloc_buffer(struct rchan *rchan, u32 new_nbufs, int async) +{ + u32 new_channel_size; + int err = 0; + + if (new_nbufs == rchan->n_bufs) + return -EINVAL; + + if (down_trylock(&rchan->resize_sem)) + return -EBUSY; + + if (rchan->init_buf) { + err = -EPERM; + goto out; + } + + if (rchan->replace_buffer) { + err = -EBUSY; + goto out; + } + + if (rchan->resizing) { + err = -EBUSY; + goto out; + } else + rchan->resizing = 1; + + if (rchan->resize_failures > MAX_RESIZE_FAILURES) { + err = -ENOMEM; + goto out; + } + + new_channel_size = check_size(rchan, new_nbufs, &err); + if (err) + goto out; + + rchan->resize_n_bufs = new_nbufs; + rchan->resize_buf_size = rchan->buf_size; + rchan->resize_alloc_size = FIX_SIZE(new_channel_size); + + if (async) { + INIT_WORK(&rchan->work, relaybuf_alloc, rchan); + schedule_delayed_work(&rchan->work, 1); + } else + relaybuf_alloc((void *)rchan); +out: + up(&rchan->resize_sem); + + return err; +} + +/** + * relay_realloc_buffer - allocate a new channel buffer + * @rchan_id: the channel id + * @bufsize: the new sub-buffer size + * @nbufs: the new number of sub-buffers + * + * Allocates a new channel buffer using the specified sub-buffer size + * and count. If async is non-zero, the allocation is done in the + * background using a work queue. When the allocation has completed, + * the needs_resize() callback is called with a resize_type of + * RELAY_RESIZE_REPLACE. This function doesn't replace the old buffer + * with the new - see relay_replace_buffer(). See + * Documentation/filesystems/relayfs.txt for more details. + * + * Returns 0 on success, or errcode if the channel is busy or if + * the allocation couldn't happen for some reason. + */ +int +relay_realloc_buffer(int rchan_id, u32 new_nbufs, int async) +{ + int err; + + struct rchan *rchan; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + err = __relay_realloc_buffer(rchan, new_nbufs, async); + + rchan_put(rchan); + + return err; +} + +/** + * expand_cancel_check - check whether the current expand needs canceling + * @rchan: the channel + * + * Returns 1 if the expand should be canceled, 0 otherwise. + */ +static int +expand_cancel_check(struct rchan *rchan) +{ + if (rchan->buf_id >= rchan->expand_buf_id) + return 1; + else + return 0; +} + +/** + * shrink_cancel_check - check whether the current shrink needs canceling + * @rchan: the channel + * + * Returns 1 if the shrink should be canceled, 0 otherwise. + */ +static int +shrink_cancel_check(struct rchan *rchan, u32 newsize) +{ + u32 active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1; + u32 cur_idx = relay_get_offset(rchan, NULL); + + if (cur_idx >= newsize) + return 1; + + if (active_bufs > 1) + return 1; + + return 0; +} + +/** + * switch_rchan_buf - do_replace_buffer helper + */ +static void +switch_rchan_buf(struct rchan *rchan, + int newsize, + int oldsize, + u32 old_nbufs, + u32 cur_idx) +{ + u32 newbufs, cur_bufno; + int i; + + cur_bufno = cur_idx / rchan->buf_size; + + rchan->buf = rchan->resize_buf; + rchan->alloc_size = rchan->resize_alloc_size; + rchan->n_bufs = rchan->resize_n_bufs; + + if (newsize > oldsize) { + u32 ge = rchan->resize_offset.ge; + u32 moved_buf = ge / rchan->buf_size; + + newbufs = (newsize - oldsize) / rchan->buf_size; + for (i = moved_buf; i < old_nbufs; i++) { + if (using_lockless(rchan)) + atomic_set(&fill_count(rchan, i + newbufs), + atomic_read(&fill_count(rchan, i))); + rchan->unused_bytes[i + newbufs] = rchan->unused_bytes[i]; + } + for (i = moved_buf; i < moved_buf + newbufs; i++) { + if (using_lockless(rchan)) + atomic_set(&fill_count(rchan, i), + (int)RELAY_BUF_SIZE(offset_bits(rchan))); + rchan->unused_bytes[i] = 0; + } + } + + rchan->buf_idx = cur_bufno; + + if (!using_lockless(rchan)) { + cur_write_pos(rchan) = rchan->buf + cur_idx; + write_buf(rchan) = rchan->buf + cur_bufno * rchan->buf_size; + write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size; + write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve; + } else { + idx(rchan) &= idx_mask(rchan); + bufno_bits(rchan) += rchan->resize_order; + idx_mask(rchan) = + (1UL << (bufno_bits(rchan) + offset_bits(rchan))) - 1; + } +} + +/** + * do_replace_buffer - does the work of channel buffer replacement + * @rchan: the channel + * @newsize: new channel buffer size + * @oldsize: old channel buffer size + * @old_n_bufs: old channel sub-buffer count + * + * Returns 0 if replacement happened, 1 if canceled + * + * Does the work of switching buffers and fixing everything up + * so the channel can continue with a new size. + */ +static int +do_replace_buffer(struct rchan *rchan, + int newsize, + int oldsize, + u32 old_nbufs) +{ + u32 cur_idx; + int err = 0; + int canceled; + + cur_idx = relay_get_offset(rchan, NULL); + + if (newsize > oldsize) + canceled = expand_cancel_check(rchan); + else + canceled = shrink_cancel_check(rchan, newsize); + + if (canceled) { + err = -EAGAIN; + goto out; + } + + switch_rchan_buf(rchan, newsize, oldsize, old_nbufs, cur_idx); + + if (rchan->resize_offset.delta) + update_file_offsets(rchan); + + atomic_set(&rchan->suspended, 0); + + rchan->old_buf_page_array = rchan->buf_page_array; + rchan->buf_page_array = rchan->resize_page_array; + rchan->buf_page_count = rchan->resize_page_count; + rchan->resize_page_array = NULL; + rchan->resize_page_count = 0; + rchan->resize_buf = NULL; + rchan->resize_buf_size = 0; + rchan->resize_alloc_size = 0; + rchan->resize_n_bufs = 0; + rchan->resize_err = 0; + rchan->resize_order = 0; +out: + rchan->callbacks->needs_resize(rchan->id, + RELAY_RESIZE_REPLACED, + rchan->buf_size, + rchan->n_bufs); + return err; +} + +/** + * add_free_page_array - add a page_array to be freed + * @free_rchan_buf: the free_rchan_buf struct + * @page_array: the page array to free + * @page_count: the number of pages to free, 0 to free the array only + * + * Internal - Used add page_arrays to be freed asynchronously. + */ +static inline void +add_free_page_array(struct free_rchan_buf *free_rchan_buf, + struct page **page_array, int page_count) +{ + int cur = free_rchan_buf->cur++; + + free_rchan_buf->page_array[cur].array = page_array; + free_rchan_buf->page_array[cur].count = page_count; +} + +/** + * free_replaced_buffer - free a channel's old buffer + * @rchan: the channel + * @oldbuf: the old buffer + * @oldsize: old buffer size + * + * Frees a channel buffer via work queue. + */ +static int +free_replaced_buffer(struct rchan *rchan, char *oldbuf, int oldsize) +{ + struct free_rchan_buf *free_buf; + + free_buf = kmalloc(sizeof(struct free_rchan_buf), GFP_ATOMIC); + if (!free_buf) + return -ENOMEM; + memset(free_buf, 0, sizeof(struct free_rchan_buf)); + + free_buf->unmap_buf = oldbuf; + add_free_page_array(free_buf, rchan->old_buf_page_array, 0); + rchan->old_buf_page_array = NULL; + add_free_page_array(free_buf, rchan->expand_page_array, 0); + add_free_page_array(free_buf, rchan->shrink_page_array, rchan->shrink_page_count); + + rchan->expand_page_array = NULL; + rchan->expand_page_count = 0; + rchan->shrink_page_array = NULL; + rchan->shrink_page_count = 0; + + INIT_WORK(&free_buf->work, relaybuf_free, free_buf); + schedule_delayed_work(&free_buf->work, 1); + + return 0; +} + +/** + * free_canceled_resize - free buffers allocated for a canceled resize + * @rchan: the channel + * + * Frees canceled buffers via work queue. + */ +static int +free_canceled_resize(struct rchan *rchan) +{ + struct free_rchan_buf *free_buf; + + free_buf = kmalloc(sizeof(struct free_rchan_buf), GFP_ATOMIC); + if (!free_buf) + return -ENOMEM; + memset(free_buf, 0, sizeof(struct free_rchan_buf)); + + if (rchan->resize_alloc_size > rchan->alloc_size) + add_free_page_array(free_buf, rchan->expand_page_array, rchan->expand_page_count); + else + add_free_page_array(free_buf, rchan->shrink_page_array, 0); + + add_free_page_array(free_buf, rchan->resize_page_array, 0); + free_buf->unmap_buf = rchan->resize_buf; + + rchan->expand_page_array = NULL; + rchan->expand_page_count = 0; + rchan->shrink_page_array = NULL; + rchan->shrink_page_count = 0; + rchan->resize_page_array = NULL; + rchan->resize_page_count = 0; + rchan->resize_buf = NULL; + + INIT_WORK(&free_buf->work, relaybuf_free, free_buf); + schedule_delayed_work(&free_buf->work, 1); + + return 0; +} + +/** + * __relay_replace_buffer - replace channel buffer with new buffer + * @rchan: the channel + * + * Internal - see relay_replace_buffer() for details. + * + * Returns 0 if successful, negative otherwise. + */ +static int +__relay_replace_buffer(struct rchan *rchan) +{ + int oldsize; + int err = 0; + char *oldbuf; + + if (down_trylock(&rchan->resize_sem)) + return -EBUSY; + + if (rchan->init_buf) { + err = -EPERM; + goto out; + } + + if (!rchan->replace_buffer) + goto out; + + if (rchan->resizing) { + err = -EBUSY; + goto out; + } + + if (rchan->resize_buf == NULL) { + err = -EINVAL; + goto out; + } + + oldbuf = rchan->buf; + oldsize = rchan->alloc_size; + + err = do_replace_buffer(rchan, rchan->resize_alloc_size, + oldsize, rchan->n_bufs); + if (err == 0) + err = free_replaced_buffer(rchan, oldbuf, oldsize); + else + err = free_canceled_resize(rchan); +out: + rchan->replace_buffer = 0; + up(&rchan->resize_sem); + + return err; +} + +/** + * relay_replace_buffer - replace channel buffer with new buffer + * @rchan_id: the channel id + * + * Replaces the current channel buffer with the new buffer allocated + * by relay_alloc_buffer and contained in the channel struct. When the + * replacement is complete, the needs_resize() callback is called with + * RELAY_RESIZE_REPLACED. + * + * Returns 0 on success, or errcode if the channel is busy or if + * the replacement or previous allocation didn't happen for some reason. + */ +int +relay_replace_buffer(int rchan_id) +{ + int err; + + struct rchan *rchan; + + rchan = rchan_get(rchan_id); + if (rchan == NULL) + return -EBADF; + + err = __relay_replace_buffer(rchan); + + rchan_put(rchan); + + return err; +} + +EXPORT_SYMBOL(relay_realloc_buffer); +EXPORT_SYMBOL(relay_replace_buffer); + diff --git a/fs/relayfs/resize.h b/fs/relayfs/resize.h new file mode 100644 index 000000000..6f06d221d --- /dev/null +++ b/fs/relayfs/resize.h @@ -0,0 +1,51 @@ +#ifndef _RELAY_RESIZE_H +#define _RELAY_RESIZE_H + +/* + * If the channel usage has been below the low water mark for more than + * this amount of time, we can shrink the buffer if necessary. + */ +#define SHRINK_TIMER_SECS 60 + +/* This inspired by rtai/shmem */ +#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE + +/* Don't attempt resizing again after this many failures */ +#define MAX_RESIZE_FAILURES 1 + +/* Trigger resizing if a resizable channel is this full */ +#define RESIZE_THRESHOLD 3 / 4 + +/* + * Used for deferring resized channel free + */ +struct free_rchan_buf +{ + char *unmap_buf; + struct + { + struct page **array; + int count; + } page_array[3]; + + int cur; + struct work_struct work; /* resize de-allocation work struct */ +}; + +extern void * +alloc_rchan_buf(unsigned long size, + struct page ***page_array, + int *page_count); + +extern void +free_rchan_buf(void *buf, + struct page **page_array, + int page_count); + +extern void +expand_check(struct rchan *rchan); + +extern void +init_shrink_timer(struct rchan *rchan); + +#endif/* _RELAY_RESIZE_H */ diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index 7266ff5f3..e8946c455 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -87,7 +87,5 @@ extern int smb_request_send_req(struct smb_request *req); extern int smb_request_send_server(struct smb_sb_info *server); extern int smb_request_recv(struct smb_sb_info *server); /* symlink.c */ -extern int smb_read_link(struct dentry *dentry, char *buffer, int len); extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname); -extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd); extern struct inode_operations smb_link_inode_operations; diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c index 44d6f58b0..8c1a20130 100644 --- a/fs/smbfs/symlink.c +++ b/fs/smbfs/symlink.c @@ -26,19 +26,6 @@ #include "smb_debug.h" #include "proto.h" -int smb_read_link(struct dentry *dentry, char *buffer, int len) -{ - char link[256]; /* FIXME: pain ... */ - int r; - DEBUG1("read link buffer len = %d\n", len); - - r = smb_proc_read_link(server_from_dentry(dentry), dentry, link, - sizeof(link) - 1); - if (r < 0) - return -ENOENT; - return vfs_readlink(dentry, buffer, len, link); -} - int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname) { DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry)); @@ -46,24 +33,37 @@ int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname) return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname); } -int smb_follow_link(struct dentry *dentry, struct nameidata *nd) +static int smb_follow_link(struct dentry *dentry, struct nameidata *nd) { - char link[256]; /* FIXME: pain ... */ - int len; + char *link = __getname(); DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry)); - len = smb_proc_read_link(server_from_dentry(dentry), dentry, link, - sizeof(link) - 1); - if(len < 0) - return -ENOENT; - - link[len] = 0; - return vfs_follow_link(nd, link); + if (!link) { + link = ERR_PTR(-ENOMEM); + } else { + int len = smb_proc_read_link(server_from_dentry(dentry), + dentry, link, PATH_MAX - 1); + if (len < 0) { + kfree(link); + link = ERR_PTR(len); + } else { + link[len] = 0; + } + } + nd_set_link(nd, link); + return 0; } +static void smb_put_link(struct dentry *dentry, struct nameidata *nd) +{ + char *s = nd_get_link(nd); + if (!IS_ERR(s)) + putname(s); +} struct inode_operations smb_link_inode_operations = { - .readlink = smb_read_link, + .readlink = generic_readlink, .follow_link = smb_follow_link, + .put_link = smb_put_link, }; diff --git a/fs/stat.c b/fs/stat.c index 6bda9bfae..f28e994d7 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -131,8 +131,6 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta tmp.st_ino = stat->ino; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; - if (tmp.st_nlink != stat->nlink) - return -EOVERFLOW; SET_UID(tmp.st_uid, stat->uid); SET_GID(tmp.st_gid, stat->gid); tmp.st_rdev = old_encode_dev(stat->rdev); @@ -201,8 +199,6 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) tmp.st_ino = stat->ino; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; - if (tmp.st_nlink != stat->nlink) - return -EOVERFLOW; SET_UID(tmp.st_uid, stat->uid); SET_GID(tmp.st_gid, stat->gid); #if BITS_PER_LONG == 32 diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 72cd7076c..47c98d022 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -89,7 +89,6 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer) return -ENOMEM; count = ops->show(kobj,attr,buffer->page); - BUG_ON(count > PAGE_SIZE); if (count >= 0) buffer->count = count; else diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 379d42408..960da9b04 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -142,8 +142,9 @@ static inline void write3byte(struct sysv_sb_info *sbi, } static struct inode_operations sysv_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .getattr = sysv_getattr, }; diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c index 97ea76137..d35150966 100644 --- a/fs/sysv/symlink.c +++ b/fs/sysv/symlink.c @@ -7,19 +7,13 @@ #include "sysv.h" -static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - char *s = (char *)SYSV_I(dentry->d_inode)->i_data; - return vfs_readlink(dentry, buffer, buflen, s); -} - static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *s = (char *)SYSV_I(dentry->d_inode)->i_data; - return vfs_follow_link(nd, s); + nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data); + return 0; } struct inode_operations sysv_fast_symlink_inode_operations = { - .readlink = sysv_readlink, + .readlink = generic_readlink, .follow_link = sysv_follow_link, }; diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c index 245225e0d..44c10915b 100644 --- a/fs/ufs/symlink.c +++ b/fs/ufs/symlink.c @@ -28,19 +28,14 @@ #include #include -static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen) -{ - struct ufs_inode_info *p = UFS_I(dentry->d_inode); - return vfs_readlink(dentry, buffer, buflen, (char*)p->i_u1.i_symlink); -} - static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ufs_inode_info *p = UFS_I(dentry->d_inode); - return vfs_follow_link(nd, (char*)p->i_u1.i_symlink); + nd_set_link(nd, (char*)p->i_u1.i_symlink); + return 0; } struct inode_operations ufs_fast_symlink_inode_operations = { - .readlink = ufs_readlink, + .readlink = generic_readlink, .follow_link = ufs_follow_link, }; diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index f43f7c370..e7d4eba4c 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -419,13 +419,16 @@ linvfs_follow_link( ASSERT(nd); link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); - if (!link) - return -ENOMEM; + if (!link) { + nd_set_link(nd, ERR_PTR(-ENOMEM)); + return 0; + } uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); if (!uio) { kfree(link); - return -ENOMEM; + nd_set_link(nd, ERR_PTR(-ENOMEM)); + return 0; } vp = LINVFS_GET_VP(dentry->d_inode); @@ -441,18 +444,22 @@ linvfs_follow_link( VOP_READLINK(vp, uio, 0, NULL, error); if (error) { - kfree(uio); kfree(link); - return -error; + link = ERR_PTR(-error); + } else { + link[MAXNAMELEN - uio->uio_resid] = '\0'; } - - link[MAXNAMELEN - uio->uio_resid] = '\0'; kfree(uio); - /* vfs_follow_link returns (-) errors */ - error = vfs_follow_link(nd, link); - kfree(link); - return error; + nd_set_link(nd, link); + return 0; +} + +static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd) +{ + char *s = nd_get_link(nd); + if (!IS_ERR(s)) + kfree(s); } #ifdef CONFIG_XFS_POSIX_ACL @@ -692,6 +699,7 @@ struct inode_operations linvfs_dir_inode_operations = { struct inode_operations linvfs_symlink_inode_operations = { .readlink = linvfs_readlink, .follow_link = linvfs_follow_link, + .put_link = linvfs_put_link, .permission = linvfs_permission, .getattr = linvfs_getattr, .setattr = linvfs_setattr, diff --git a/fs/xfs/linux/kmem.h b/fs/xfs/linux/kmem.h deleted file mode 100644 index c9df16472..000000000 --- a/fs/xfs/linux/kmem.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_KMEM_H__ -#define __XFS_SUPPORT_KMEM_H__ - -#include -#include -#include -#include - -/* - * Cutoff point to use vmalloc instead of kmalloc. - */ -#define MAX_SLAB_SIZE 0x10000 - -/* - * XFS uses slightly different names for these due to the - * IRIX heritage. - */ -#define kmem_zone kmem_cache_s -#define kmem_zone_t kmem_cache_t - -#define KM_SLEEP 0x0001 -#define KM_NOSLEEP 0x0002 -#define KM_NOFS 0x0004 - -typedef unsigned long xfs_pflags_t; - -#define PFLAGS_TEST_FSTRANS() (current->flags & PF_FSTRANS) - -/* these could be nested, so we save state */ -#define PFLAGS_SET_FSTRANS(STATEP) do { \ - *(STATEP) = current->flags; \ - current->flags |= PF_FSTRANS; \ -} while (0) - -#define PFLAGS_CLEAR_FSTRANS(STATEP) do { \ - *(STATEP) = current->flags; \ - current->flags &= ~PF_FSTRANS; \ -} while (0) - -/* Restore the PF_FSTRANS state to what was saved in STATEP */ -#define PFLAGS_RESTORE_FSTRANS(STATEP) do { \ - current->flags = ((current->flags & ~PF_FSTRANS) | \ - (*(STATEP) & PF_FSTRANS)); \ -} while (0) - -#define PFLAGS_DUP(OSTATEP, NSTATEP) do { \ - *(NSTATEP) = *(OSTATEP); \ -} while (0) - -/* - * XXX get rid of the unconditional __GFP_NOFAIL by adding - * a KM_FAIL flag and using it where we're allowed to fail. - */ -static __inline unsigned int -kmem_flags_convert(int flags) -{ - int lflags; - -#if DEBUG - if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) { - printk(KERN_WARNING - "XFS: memory allocation with wrong flags (%x)\n", flags); - BUG(); - } -#endif - - lflags = (flags & KM_NOSLEEP) ? GFP_ATOMIC : (GFP_KERNEL|__GFP_NOFAIL); - - /* avoid recusive callbacks to filesystem during transactions */ - if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS)) - lflags &= ~__GFP_FS; - - return lflags; -} - -static __inline void * -kmem_alloc(size_t size, int flags) -{ - if (unlikely(MAX_SLAB_SIZE < size)) - /* Avoid doing filesystem sensitive stuff to get this */ - return __vmalloc(size, kmem_flags_convert(flags), PAGE_KERNEL); - return kmalloc(size, kmem_flags_convert(flags)); -} - -static __inline void * -kmem_zalloc(size_t size, int flags) -{ - void *ptr = kmem_alloc(size, flags); - if (likely(ptr != NULL)) - memset(ptr, 0, size); - return ptr; -} - -static __inline void -kmem_free(void *ptr, size_t size) -{ - if (unlikely((unsigned long)ptr < VMALLOC_START || - (unsigned long)ptr >= VMALLOC_END)) - kfree(ptr); - else - vfree(ptr); -} - -static __inline void * -kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags) -{ - void *new = kmem_alloc(newsize, flags); - - if (likely(ptr != NULL)) { - if (likely(new != NULL)) - memcpy(new, ptr, min(oldsize, newsize)); - kmem_free(ptr, oldsize); - } - - return new; -} - -static __inline kmem_zone_t * -kmem_zone_init(int size, char *zone_name) -{ - return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); -} - -static __inline void * -kmem_zone_alloc(kmem_zone_t *zone, int flags) -{ - return kmem_cache_alloc(zone, kmem_flags_convert(flags)); -} - -static __inline void * -kmem_zone_zalloc(kmem_zone_t *zone, int flags) -{ - void *ptr = kmem_zone_alloc(zone, flags); - if (likely(ptr != NULL)) - memset(ptr, 0, kmem_cache_size(zone)); - return ptr; -} - -static __inline void -kmem_zone_free(kmem_zone_t *zone, void *ptr) -{ - kmem_cache_free(zone, ptr); -} - -typedef struct shrinker *kmem_shaker_t; -typedef int (*kmem_shake_func_t)(int, unsigned int); - -static __inline kmem_shaker_t -kmem_shake_register(kmem_shake_func_t sfunc) -{ - return set_shrinker(DEFAULT_SEEKS, sfunc); -} - -static __inline void -kmem_shake_deregister(kmem_shaker_t shrinker) -{ - remove_shrinker(shrinker); -} - -static __inline int -kmem_shake_allow(unsigned int gfp_mask) -{ - return (gfp_mask & __GFP_WAIT); -} - -#endif /* __XFS_SUPPORT_KMEM_H__ */ diff --git a/fs/xfs/linux/mrlock.h b/fs/xfs/linux/mrlock.h deleted file mode 100644 index d2c11a098..000000000 --- a/fs/xfs/linux/mrlock.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_MRLOCK_H__ -#define __XFS_SUPPORT_MRLOCK_H__ - -#include - -enum { MR_NONE, MR_ACCESS, MR_UPDATE }; - -typedef struct { - struct rw_semaphore mr_lock; - int mr_writer; -} mrlock_t; - -#define mrinit(mrp, name) \ - ( (mrp)->mr_writer = 0, init_rwsem(&(mrp)->mr_lock) ) -#define mrlock_init(mrp, t,n,s) mrinit(mrp, n) -#define mrfree(mrp) do { } while (0) -#define mraccess(mrp) mraccessf(mrp, 0) -#define mrupdate(mrp) mrupdatef(mrp, 0) - -static inline void mraccessf(mrlock_t *mrp, int flags) -{ - down_read(&mrp->mr_lock); -} - -static inline void mrupdatef(mrlock_t *mrp, int flags) -{ - down_write(&mrp->mr_lock); - mrp->mr_writer = 1; -} - -static inline int mrtryaccess(mrlock_t *mrp) -{ - return down_read_trylock(&mrp->mr_lock); -} - -static inline int mrtryupdate(mrlock_t *mrp) -{ - if (!down_write_trylock(&mrp->mr_lock)) - return 0; - mrp->mr_writer = 1; - return 1; -} - -static inline void mrunlock(mrlock_t *mrp) -{ - if (mrp->mr_writer) { - mrp->mr_writer = 0; - up_write(&mrp->mr_lock); - } else { - up_read(&mrp->mr_lock); - } -} - -static inline void mrdemote(mrlock_t *mrp) -{ - mrp->mr_writer = 0; - downgrade_write(&mrp->mr_lock); -} - -#ifdef DEBUG -/* - * Debug-only routine, without some platform-specific asm code, we can - * now only answer requests regarding whether we hold the lock for write - * (reader state is outside our visibility, we only track writer state). - * Note: means !ismrlocked would give false positivies, so don't do that. - */ -static inline int ismrlocked(mrlock_t *mrp, int type) -{ - if (mrp && type == MR_UPDATE) - return mrp->mr_writer; - return 1; -} -#endif - -#endif /* __XFS_SUPPORT_MRLOCK_H__ */ diff --git a/fs/xfs/linux/mutex.h b/fs/xfs/linux/mutex.h deleted file mode 100644 index 0b296bb94..000000000 --- a/fs/xfs/linux/mutex.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_MUTEX_H__ -#define __XFS_SUPPORT_MUTEX_H__ - -#include -#include - -/* - * Map the mutex'es from IRIX to Linux semaphores. - * - * Destroy just simply initializes to -99 which should block all other - * callers. - */ -#define MUTEX_DEFAULT 0x0 -typedef struct semaphore mutex_t; - -#define mutex_init(lock, type, name) sema_init(lock, 1) -#define mutex_destroy(lock) sema_init(lock, -99) -#define mutex_lock(lock, num) down(lock) -#define mutex_trylock(lock) (down_trylock(lock) ? 0 : 1) -#define mutex_unlock(lock) up(lock) - -#endif /* __XFS_SUPPORT_MUTEX_H__ */ diff --git a/fs/xfs/linux/sema.h b/fs/xfs/linux/sema.h deleted file mode 100644 index 30b67b4e1..000000000 --- a/fs/xfs/linux/sema.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_SEMA_H__ -#define __XFS_SUPPORT_SEMA_H__ - -#include -#include -#include -#include - -/* - * sema_t structure just maps to struct semaphore in Linux kernel. - */ - -typedef struct semaphore sema_t; - -#define init_sema(sp, val, c, d) sema_init(sp, val) -#define initsema(sp, val) sema_init(sp, val) -#define initnsema(sp, val, name) sema_init(sp, val) -#define psema(sp, b) down(sp) -#define vsema(sp) up(sp) -#define valusema(sp) (atomic_read(&(sp)->count)) -#define freesema(sema) - -/* - * Map cpsema (try to get the sema) to down_trylock. We need to switch - * the return values since cpsema returns 1 (acquired) 0 (failed) and - * down_trylock returns the reverse 0 (acquired) 1 (failed). - */ - -#define cpsema(sp) (down_trylock(sp) ? 0 : 1) - -/* - * Didn't do cvsema(sp). Not sure how to map this to up/down/... - * It does a vsema if the values is < 0 other wise nothing. - */ - -#endif /* __XFS_SUPPORT_SEMA_H__ */ diff --git a/fs/xfs/linux/spin.h b/fs/xfs/linux/spin.h deleted file mode 100644 index 80a3a6bae..000000000 --- a/fs/xfs/linux/spin.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_SPIN_H__ -#define __XFS_SUPPORT_SPIN_H__ - -#include /* preempt needs this */ -#include - -/* - * Map lock_t from IRIX to Linux spinlocks. - * - * Note that linux turns on/off spinlocks depending on CONFIG_SMP. - * We don't need to worry about SMP or not here. - */ - -#define SPLDECL(s) unsigned long s - -typedef spinlock_t lock_t; - -#define spinlock_init(lock, name) spin_lock_init(lock) -#define spinlock_destroy(lock) - -static inline unsigned long mutex_spinlock(lock_t *lock) -{ - spin_lock(lock); - return 0; -} - -/*ARGSUSED*/ -static inline void mutex_spinunlock(lock_t *lock, unsigned long s) -{ - spin_unlock(lock); -} - -static inline void nested_spinlock(lock_t *lock) -{ - spin_lock(lock); -} - -static inline void nested_spinunlock(lock_t *lock) -{ - spin_unlock(lock); -} - -#endif /* __XFS_SUPPORT_SPIN_H__ */ diff --git a/fs/xfs/linux/sv.h b/fs/xfs/linux/sv.h deleted file mode 100644 index 821d3167e..000000000 --- a/fs/xfs/linux/sv.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_SV_H__ -#define __XFS_SUPPORT_SV_H__ - -#include -#include -#include - -/* - * Synchronisation variables. - * - * (Parameters "pri", "svf" and "rts" are not implemented) - */ - -typedef struct sv_s { - wait_queue_head_t waiters; -} sv_t; - -#define SV_FIFO 0x0 /* sv_t is FIFO type */ -#define SV_LIFO 0x2 /* sv_t is LIFO type */ -#define SV_PRIO 0x4 /* sv_t is PRIO type */ -#define SV_KEYED 0x6 /* sv_t is KEYED type */ -#define SV_DEFAULT SV_FIFO - - -static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state, - unsigned long timeout) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue_exclusive(&sv->waiters, &wait); - __set_current_state(state); - spin_unlock(lock); - - schedule_timeout(timeout); - - remove_wait_queue(&sv->waiters, &wait); -} - -#define init_sv(sv,type,name,flag) \ - init_waitqueue_head(&(sv)->waiters) -#define sv_init(sv,flag,name) \ - init_waitqueue_head(&(sv)->waiters) -#define sv_destroy(sv) \ - /*NOTHING*/ -#define sv_wait(sv, pri, lock, s) \ - _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) -#define sv_wait_sig(sv, pri, lock, s) \ - _sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) -#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \ - _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts)) -#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \ - _sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts)) -#define sv_signal(sv) \ - wake_up(&(sv)->waiters) -#define sv_broadcast(sv) \ - wake_up_all(&(sv)->waiters) - -#endif /* __XFS_SUPPORT_SV_H__ */ diff --git a/fs/xfs/linux/time.h b/fs/xfs/linux/time.h deleted file mode 100644 index 109b5c083..000000000 --- a/fs/xfs/linux/time.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPPORT_TIME_H__ -#define __XFS_SUPPORT_TIME_H__ - -#include -#include - -typedef struct timespec timespec_t; - -static inline void delay(long ticks) -{ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(ticks); -} - -static inline void nanotime(struct timespec *tvp) -{ - *tvp = CURRENT_TIME; -} - -#endif /* __XFS_SUPPORT_TIME_H__ */ diff --git a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c deleted file mode 100644 index 3afc61d10..000000000 --- a/fs/xfs/linux/xfs_aops.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_sb.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_trans.h" -#include "xfs_dmapi.h" -#include "xfs_mount.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_btree.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_error.h" -#include "xfs_rw.h" -#include "xfs_iomap.h" -#include - -STATIC void xfs_count_page_state(struct page *, int *, int *, int *); -STATIC void xfs_convert_page(struct inode *, struct page *, - xfs_iomap_t *, void *, int, int); - -#if defined(XFS_RW_TRACE) -void -xfs_page_trace( - int tag, - struct inode *inode, - struct page *page, - int mask) -{ - xfs_inode_t *ip; - bhv_desc_t *bdp; - vnode_t *vp = LINVFS_GET_VP(inode); - loff_t isize = i_size_read(inode); - loff_t offset = page->index << PAGE_CACHE_SHIFT; - int delalloc = -1, unmapped = -1, unwritten = -1; - - if (page_has_buffers(page)) - xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); - - bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); - ip = XFS_BHVTOI(bdp); - if (!ip->i_rwtrace) - return; - - ktrace_enter(ip->i_rwtrace, - (void *)((unsigned long)tag), - (void *)ip, - (void *)inode, - (void *)page, - (void *)((unsigned long)mask), - (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), - (void *)((unsigned long)((isize >> 32) & 0xffffffff)), - (void *)((unsigned long)(isize & 0xffffffff)), - (void *)((unsigned long)((offset >> 32) & 0xffffffff)), - (void *)((unsigned long)(offset & 0xffffffff)), - (void *)((unsigned long)delalloc), - (void *)((unsigned long)unmapped), - (void *)((unsigned long)unwritten), - (void *)NULL, - (void *)NULL); -} -#else -#define xfs_page_trace(tag, inode, page, mask) -#endif - -void -linvfs_unwritten_done( - struct buffer_head *bh, - int uptodate) -{ - xfs_buf_t *pb = (xfs_buf_t *)bh->b_private; - - ASSERT(buffer_unwritten(bh)); - bh->b_end_io = NULL; - clear_buffer_unwritten(bh); - if (!uptodate) - pagebuf_ioerror(pb, EIO); - if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) { - pagebuf_iodone(pb, 1, 1); - } - end_buffer_async_write(bh, uptodate); -} - -/* - * Issue transactions to convert a buffer range from unwritten - * to written extents (buffered IO). - */ -STATIC void -linvfs_unwritten_convert( - xfs_buf_t *bp) -{ - vnode_t *vp = XFS_BUF_FSPRIVATE(bp, vnode_t *); - int error; - - BUG_ON(atomic_read(&bp->pb_hold) < 1); - VOP_BMAP(vp, XFS_BUF_OFFSET(bp), XFS_BUF_SIZE(bp), - BMAPI_UNWRITTEN, NULL, NULL, error); - XFS_BUF_SET_FSPRIVATE(bp, NULL); - XFS_BUF_CLR_IODONE_FUNC(bp); - XFS_BUF_UNDATAIO(bp); - iput(LINVFS_GET_IP(vp)); - pagebuf_iodone(bp, 0, 0); -} - -/* - * Issue transactions to convert a buffer range from unwritten - * to written extents (direct IO). - */ -STATIC void -linvfs_unwritten_convert_direct( - struct inode *inode, - loff_t offset, - ssize_t size, - void *private) -{ - ASSERT(!private || inode == (struct inode *)private); - - /* private indicates an unwritten extent lay beneath this IO, - * see linvfs_get_block_core. - */ - if (private && size > 0) { - vnode_t *vp = LINVFS_GET_VP(inode); - int error; - - VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error); - } -} - -STATIC int -xfs_map_blocks( - struct inode *inode, - loff_t offset, - ssize_t count, - xfs_iomap_t *iomapp, - int flags) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - int error, niomaps = 1; - - if (((flags & (BMAPI_DIRECT|BMAPI_SYNC)) == BMAPI_DIRECT) && - (offset >= i_size_read(inode))) - count = max_t(ssize_t, count, XFS_WRITE_IO_LOG); -retry: - VOP_BMAP(vp, offset, count, flags, iomapp, &niomaps, error); - if ((error == EAGAIN) || (error == EIO)) - return -error; - if (unlikely((flags & (BMAPI_WRITE|BMAPI_DIRECT)) == - (BMAPI_WRITE|BMAPI_DIRECT) && niomaps && - (iomapp->iomap_flags & IOMAP_DELAY))) { - flags = BMAPI_ALLOCATE; - goto retry; - } - if (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)) { - VMODIFY(vp); - } - return -error; -} - -/* - * Finds the corresponding mapping in block @map array of the - * given @offset within a @page. - */ -STATIC xfs_iomap_t * -xfs_offset_to_map( - struct page *page, - xfs_iomap_t *iomapp, - unsigned long offset) -{ - loff_t full_offset; /* offset from start of file */ - - ASSERT(offset < PAGE_CACHE_SIZE); - - full_offset = page->index; /* NB: using 64bit number */ - full_offset <<= PAGE_CACHE_SHIFT; /* offset from file start */ - full_offset += offset; /* offset from page start */ - - if (full_offset < iomapp->iomap_offset) - return NULL; - if (iomapp->iomap_offset + iomapp->iomap_bsize > full_offset) - return iomapp; - return NULL; -} - -STATIC void -xfs_map_at_offset( - struct page *page, - struct buffer_head *bh, - unsigned long offset, - int block_bits, - xfs_iomap_t *iomapp) -{ - xfs_daddr_t bn; - loff_t delta; - int sector_shift; - - ASSERT(!(iomapp->iomap_flags & IOMAP_HOLE)); - ASSERT(!(iomapp->iomap_flags & IOMAP_DELAY)); - ASSERT(iomapp->iomap_bn != IOMAP_DADDR_NULL); - - delta = page->index; - delta <<= PAGE_CACHE_SHIFT; - delta += offset; - delta -= iomapp->iomap_offset; - delta >>= block_bits; - - sector_shift = block_bits - BBSHIFT; - bn = iomapp->iomap_bn >> sector_shift; - bn += delta; - ASSERT((bn << sector_shift) >= iomapp->iomap_bn); - - lock_buffer(bh); - bh->b_blocknr = bn; - bh->b_bdev = iomapp->iomap_target->pbr_bdev; - set_buffer_mapped(bh); - clear_buffer_delay(bh); -} - -/* - * Look for a page at index which is unlocked and contains our - * unwritten extent flagged buffers at its head. Returns page - * locked and with an extra reference count, and length of the - * unwritten extent component on this page that we can write, - * in units of filesystem blocks. - */ -STATIC struct page * -xfs_probe_unwritten_page( - struct address_space *mapping, - pgoff_t index, - xfs_iomap_t *iomapp, - xfs_buf_t *pb, - unsigned long max_offset, - unsigned long *fsbs, - unsigned int bbits) -{ - struct page *page; - - page = find_trylock_page(mapping, index); - if (!page) - return 0; - if (PageWriteback(page)) - goto out; - - if (page->mapping && page_has_buffers(page)) { - struct buffer_head *bh, *head; - unsigned long p_offset = 0; - - *fsbs = 0; - bh = head = page_buffers(page); - do { - if (!buffer_unwritten(bh)) - break; - if (!xfs_offset_to_map(page, iomapp, p_offset)) - break; - if (p_offset >= max_offset) - break; - xfs_map_at_offset(page, bh, p_offset, bbits, iomapp); - set_buffer_unwritten_io(bh); - bh->b_private = pb; - p_offset += bh->b_size; - (*fsbs)++; - } while ((bh = bh->b_this_page) != head); - - if (p_offset) - return page; - } - -out: - unlock_page(page); - return NULL; -} - -/* - * Look for a page at index which is unlocked and not mapped - * yet - clustering for mmap write case. - */ -STATIC unsigned int -xfs_probe_unmapped_page( - struct address_space *mapping, - pgoff_t index, - unsigned int pg_offset) -{ - struct page *page; - int ret = 0; - - page = find_trylock_page(mapping, index); - if (!page) - return 0; - if (PageWriteback(page)) - goto out; - - if (page->mapping && PageDirty(page)) { - if (page_has_buffers(page)) { - struct buffer_head *bh, *head; - - bh = head = page_buffers(page); - do { - if (buffer_mapped(bh) || !buffer_uptodate(bh)) - break; - ret += bh->b_size; - if (ret >= pg_offset) - break; - } while ((bh = bh->b_this_page) != head); - } else - ret = PAGE_CACHE_SIZE; - } - -out: - unlock_page(page); - return ret; -} - -STATIC unsigned int -xfs_probe_unmapped_cluster( - struct inode *inode, - struct page *startpage, - struct buffer_head *bh, - struct buffer_head *head) -{ - pgoff_t tindex, tlast, tloff; - unsigned int pg_offset, len, total = 0; - struct address_space *mapping = inode->i_mapping; - - /* First sum forwards in this page */ - do { - if (buffer_mapped(bh)) - break; - total += bh->b_size; - } while ((bh = bh->b_this_page) != head); - - /* If we reached the end of the page, sum forwards in - * following pages. - */ - if (bh == head) { - tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT; - /* Prune this back to avoid pathological behavior */ - tloff = min(tlast, startpage->index + 64); - for (tindex = startpage->index + 1; tindex < tloff; tindex++) { - len = xfs_probe_unmapped_page(mapping, tindex, - PAGE_CACHE_SIZE); - if (!len) - return total; - total += len; - } - if (tindex == tlast && - (pg_offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) { - total += xfs_probe_unmapped_page(mapping, - tindex, pg_offset); - } - } - return total; -} - -/* - * Probe for a given page (index) in the inode and test if it is delayed - * and without unwritten buffers. Returns page locked and with an extra - * reference count. - */ -STATIC struct page * -xfs_probe_delalloc_page( - struct inode *inode, - pgoff_t index) -{ - struct page *page; - - page = find_trylock_page(inode->i_mapping, index); - if (!page) - return NULL; - if (PageWriteback(page)) - goto out; - - if (page->mapping && page_has_buffers(page)) { - struct buffer_head *bh, *head; - int acceptable = 0; - - bh = head = page_buffers(page); - do { - if (buffer_unwritten(bh)) { - acceptable = 0; - break; - } else if (buffer_delay(bh)) { - acceptable = 1; - } - } while ((bh = bh->b_this_page) != head); - - if (acceptable) - return page; - } - -out: - unlock_page(page); - return NULL; -} - -STATIC int -xfs_map_unwritten( - struct inode *inode, - struct page *start_page, - struct buffer_head *head, - struct buffer_head *curr, - unsigned long p_offset, - int block_bits, - xfs_iomap_t *iomapp, - int startio, - int all_bh) -{ - struct buffer_head *bh = curr; - xfs_iomap_t *tmp; - xfs_buf_t *pb; - loff_t offset, size; - unsigned long nblocks = 0; - - offset = start_page->index; - offset <<= PAGE_CACHE_SHIFT; - offset += p_offset; - - /* get an "empty" pagebuf to manage IO completion - * Proper values will be set before returning */ - pb = pagebuf_lookup(iomapp->iomap_target, 0, 0, 0); - if (!pb) - return -EAGAIN; - - /* Take a reference to the inode to prevent it from - * being reclaimed while we have outstanding unwritten - * extent IO on it. - */ - if ((igrab(inode)) != inode) { - pagebuf_free(pb); - return -EAGAIN; - } - - /* Set the count to 1 initially, this will stop an I/O - * completion callout which happens before we have started - * all the I/O from calling pagebuf_iodone too early. - */ - atomic_set(&pb->pb_io_remaining, 1); - - /* First map forwards in the page consecutive buffers - * covering this unwritten extent - */ - do { - if (!buffer_unwritten(bh)) - break; - tmp = xfs_offset_to_map(start_page, iomapp, p_offset); - if (!tmp) - break; - xfs_map_at_offset(start_page, bh, p_offset, block_bits, iomapp); - set_buffer_unwritten_io(bh); - bh->b_private = pb; - p_offset += bh->b_size; - nblocks++; - } while ((bh = bh->b_this_page) != head); - - atomic_add(nblocks, &pb->pb_io_remaining); - - /* If we reached the end of the page, map forwards in any - * following pages which are also covered by this extent. - */ - if (bh == head) { - struct address_space *mapping = inode->i_mapping; - pgoff_t tindex, tloff, tlast; - unsigned long bs; - unsigned int pg_offset, bbits = inode->i_blkbits; - struct page *page; - - tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT; - tloff = (iomapp->iomap_offset + iomapp->iomap_bsize) >> PAGE_CACHE_SHIFT; - tloff = min(tlast, tloff); - for (tindex = start_page->index + 1; tindex < tloff; tindex++) { - page = xfs_probe_unwritten_page(mapping, - tindex, iomapp, pb, - PAGE_CACHE_SIZE, &bs, bbits); - if (!page) - break; - nblocks += bs; - atomic_add(bs, &pb->pb_io_remaining); - xfs_convert_page(inode, page, iomapp, pb, - startio, all_bh); - /* stop if converting the next page might add - * enough blocks that the corresponding byte - * count won't fit in our ulong page buf length */ - if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits)) - goto enough; - } - - if (tindex == tlast && - (pg_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) { - page = xfs_probe_unwritten_page(mapping, - tindex, iomapp, pb, - pg_offset, &bs, bbits); - if (page) { - nblocks += bs; - atomic_add(bs, &pb->pb_io_remaining); - xfs_convert_page(inode, page, iomapp, pb, - startio, all_bh); - if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits)) - goto enough; - } - } - } - -enough: - size = nblocks; /* NB: using 64bit number here */ - size <<= block_bits; /* convert fsb's to byte range */ - - XFS_BUF_DATAIO(pb); - XFS_BUF_ASYNC(pb); - XFS_BUF_SET_SIZE(pb, size); - XFS_BUF_SET_COUNT(pb, size); - XFS_BUF_SET_OFFSET(pb, offset); - XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode)); - XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_convert); - - if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) { - pagebuf_iodone(pb, 1, 1); - } - - return 0; -} - -STATIC void -xfs_submit_page( - struct page *page, - struct buffer_head *bh_arr[], - int cnt) -{ - struct buffer_head *bh; - int i; - - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - clear_page_dirty(page); - unlock_page(page); - - if (cnt) { - for (i = 0; i < cnt; i++) { - bh = bh_arr[i]; - mark_buffer_async_write(bh); - if (buffer_unwritten(bh)) - set_buffer_unwritten_io(bh); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - } - - for (i = 0; i < cnt; i++) - submit_bh(WRITE, bh_arr[i]); - } else - end_page_writeback(page); -} - -/* - * Allocate & map buffers for page given the extent map. Write it out. - * except for the original page of a writepage, this is called on - * delalloc/unwritten pages only, for the original page it is possible - * that the page has no mapping at all. - */ -STATIC void -xfs_convert_page( - struct inode *inode, - struct page *page, - xfs_iomap_t *iomapp, - void *private, - int startio, - int all_bh) -{ - struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; - xfs_iomap_t *mp = iomapp, *tmp; - unsigned long end, offset; - pgoff_t end_index; - int i = 0, index = 0; - int bbits = inode->i_blkbits; - - end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT; - if (page->index < end_index) { - end = PAGE_CACHE_SIZE; - } else { - end = i_size_read(inode) & (PAGE_CACHE_SIZE-1); - } - bh = head = page_buffers(page); - do { - offset = i << bbits; - if (!(PageUptodate(page) || buffer_uptodate(bh))) - continue; - if (buffer_mapped(bh) && all_bh && - !buffer_unwritten(bh) && !buffer_delay(bh)) { - if (startio && (offset < end)) { - lock_buffer(bh); - bh_arr[index++] = bh; - } - continue; - } - tmp = xfs_offset_to_map(page, mp, offset); - if (!tmp) - continue; - ASSERT(!(tmp->iomap_flags & IOMAP_HOLE)); - ASSERT(!(tmp->iomap_flags & IOMAP_DELAY)); - - /* If this is a new unwritten extent buffer (i.e. one - * that we haven't passed in private data for, we must - * now map this buffer too. - */ - if (buffer_unwritten(bh) && !bh->b_end_io) { - ASSERT(tmp->iomap_flags & IOMAP_UNWRITTEN); - xfs_map_unwritten(inode, page, head, bh, - offset, bbits, tmp, startio, all_bh); - } else if (! (buffer_unwritten(bh) && buffer_locked(bh))) { - xfs_map_at_offset(page, bh, offset, bbits, tmp); - if (buffer_unwritten(bh)) { - set_buffer_unwritten_io(bh); - bh->b_private = private; - ASSERT(private); - } - } - if (startio && (offset < end)) { - bh_arr[index++] = bh; - } else { - set_buffer_dirty(bh); - unlock_buffer(bh); - mark_buffer_dirty(bh); - } - } while (i++, (bh = bh->b_this_page) != head); - - if (startio) { - xfs_submit_page(page, bh_arr, index); - } else { - unlock_page(page); - } -} - -/* - * Convert & write out a cluster of pages in the same extent as defined - * by mp and following the start page. - */ -STATIC void -xfs_cluster_write( - struct inode *inode, - pgoff_t tindex, - xfs_iomap_t *iomapp, - int startio, - int all_bh) -{ - pgoff_t tlast; - struct page *page; - - tlast = (iomapp->iomap_offset + iomapp->iomap_bsize) >> PAGE_CACHE_SHIFT; - for (; tindex < tlast; tindex++) { - page = xfs_probe_delalloc_page(inode, tindex); - if (!page) - break; - xfs_convert_page(inode, page, iomapp, NULL, startio, all_bh); - } -} - -/* - * Calling this without startio set means we are being asked to make a dirty - * page ready for freeing it's buffers. When called with startio set then - * we are coming from writepage. - * - * When called with startio set it is important that we write the WHOLE - * page if possible. - * The bh->b_state's cannot know if any of the blocks or which block for - * that matter are dirty due to mmap writes, and therefore bh uptodate is - * only vaild if the page itself isn't completely uptodate. Some layers - * may clear the page dirty flag prior to calling write page, under the - * assumption the entire page will be written out; by not writing out the - * whole page the page can be reused before all valid dirty data is - * written out. Note: in the case of a page that has been dirty'd by - * mapwrite and but partially setup by block_prepare_write the - * bh->b_states's will not agree and only ones setup by BPW/BCW will have - * valid state, thus the whole page must be written out thing. - */ - -STATIC int -xfs_page_state_convert( - struct inode *inode, - struct page *page, - int startio, - int unmapped) /* also implies page uptodate */ -{ - struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; - xfs_iomap_t *iomp, iomap; - unsigned long p_offset = 0; - pgoff_t end_index; - loff_t offset; - unsigned long long end_offset; - int len, err, i, cnt = 0, uptodate = 1; - int flags = startio ? 0 : BMAPI_TRYLOCK; - int page_dirty = 1; - - - /* Are we off the end of the file ? */ - end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT; - if (page->index >= end_index) { - if ((page->index >= end_index + 1) || - !(i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) { - err = -EIO; - goto error; - } - } - - offset = (loff_t)page->index << PAGE_CACHE_SHIFT; - end_offset = min_t(unsigned long long, - offset + PAGE_CACHE_SIZE, i_size_read(inode)); - - bh = head = page_buffers(page); - iomp = NULL; - - len = bh->b_size; - do { - if (offset >= end_offset) - break; - if (!buffer_uptodate(bh)) - uptodate = 0; - if (!(PageUptodate(page) || buffer_uptodate(bh)) && !startio) - continue; - - if (iomp) { - iomp = xfs_offset_to_map(page, &iomap, p_offset); - } - - /* - * First case, map an unwritten extent and prepare for - * extent state conversion transaction on completion. - */ - if (buffer_unwritten(bh)) { - if (!iomp) { - err = xfs_map_blocks(inode, offset, len, &iomap, - BMAPI_READ|BMAPI_IGNSTATE); - if (err) { - goto error; - } - iomp = xfs_offset_to_map(page, &iomap, - p_offset); - } - if (iomp && startio) { - if (!bh->b_end_io) { - err = xfs_map_unwritten(inode, page, - head, bh, p_offset, - inode->i_blkbits, iomp, - startio, unmapped); - if (err) { - goto error; - } - } - bh_arr[cnt++] = bh; - page_dirty = 0; - } - /* - * Second case, allocate space for a delalloc buffer. - * We can return EAGAIN here in the release page case. - */ - } else if (buffer_delay(bh)) { - if (!iomp) { - err = xfs_map_blocks(inode, offset, len, &iomap, - BMAPI_ALLOCATE | flags); - if (err) { - goto error; - } - iomp = xfs_offset_to_map(page, &iomap, - p_offset); - } - if (iomp) { - xfs_map_at_offset(page, bh, p_offset, - inode->i_blkbits, iomp); - if (startio) { - bh_arr[cnt++] = bh; - } else { - set_buffer_dirty(bh); - unlock_buffer(bh); - mark_buffer_dirty(bh); - } - page_dirty = 0; - } - } else if ((buffer_uptodate(bh) || PageUptodate(page)) && - (unmapped || startio)) { - - if (!buffer_mapped(bh)) { - int size; - - /* - * Getting here implies an unmapped buffer - * was found, and we are in a path where we - * need to write the whole page out. - */ - if (!iomp) { - size = xfs_probe_unmapped_cluster( - inode, page, bh, head); - err = xfs_map_blocks(inode, offset, - size, &iomap, - BMAPI_WRITE|BMAPI_MMAP); - if (err) { - goto error; - } - iomp = xfs_offset_to_map(page, &iomap, - p_offset); - } - if (iomp) { - xfs_map_at_offset(page, - bh, p_offset, - inode->i_blkbits, iomp); - if (startio) { - bh_arr[cnt++] = bh; - } else { - set_buffer_dirty(bh); - unlock_buffer(bh); - mark_buffer_dirty(bh); - } - page_dirty = 0; - } - } else if (startio) { - if (buffer_uptodate(bh) && - !test_and_set_bit(BH_Lock, &bh->b_state)) { - bh_arr[cnt++] = bh; - page_dirty = 0; - } - } - } - } while (offset += len, p_offset += len, - ((bh = bh->b_this_page) != head)); - - if (uptodate && bh == head) - SetPageUptodate(page); - - if (startio) - xfs_submit_page(page, bh_arr, cnt); - - if (iomp) - xfs_cluster_write(inode, page->index + 1, iomp, startio, unmapped); - - return page_dirty; - -error: - for (i = 0; i < cnt; i++) { - unlock_buffer(bh_arr[i]); - } - - /* - * If it's delalloc and we have nowhere to put it, - * throw it away, unless the lower layers told - * us to try again. - */ - if (err != -EAGAIN) { - if (!unmapped) { - block_invalidatepage(page, 0); - } - ClearPageUptodate(page); - } - return err; -} - -STATIC int -linvfs_get_block_core( - struct inode *inode, - sector_t iblock, - unsigned long blocks, - struct buffer_head *bh_result, - int create, - int direct, - bmapi_flags_t flags) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - xfs_iomap_t iomap; - int retpbbm = 1; - int error; - ssize_t size; - loff_t offset = (loff_t)iblock << inode->i_blkbits; - - /* If we are doing writes at the end of the file, - * allocate in chunks - */ - if (blocks) - size = blocks << inode->i_blkbits; - else if (create && (offset >= i_size_read(inode))) - size = 1 << XFS_WRITE_IO_LOG; - else - size = 1 << inode->i_blkbits; - - VOP_BMAP(vp, offset, size, - create ? flags : BMAPI_READ, &iomap, &retpbbm, error); - if (error) - return -error; - - if (retpbbm == 0) - return 0; - - if (iomap.iomap_bn != IOMAP_DADDR_NULL) { - xfs_daddr_t bn; - loff_t delta; - - /* For unwritten extents do not report a disk address on - * the read case (treat as if we're reading into a hole). - */ - if (create || !(iomap.iomap_flags & IOMAP_UNWRITTEN)) { - delta = offset - iomap.iomap_offset; - delta >>= inode->i_blkbits; - - bn = iomap.iomap_bn >> (inode->i_blkbits - BBSHIFT); - bn += delta; - - bh_result->b_blocknr = bn; - bh_result->b_bdev = iomap.iomap_target->pbr_bdev; - set_buffer_mapped(bh_result); - } - if (create && (iomap.iomap_flags & IOMAP_UNWRITTEN)) { - if (direct) - bh_result->b_private = inode; - set_buffer_unwritten(bh_result); - set_buffer_delay(bh_result); - } - } - - /* If this is a realtime file, data might be on a new device */ - bh_result->b_bdev = iomap.iomap_target->pbr_bdev; - - /* If we previously allocated a block out beyond eof and - * we are now coming back to use it then we will need to - * flag it as new even if it has a disk address. - */ - if (create && - ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) || - (offset >= i_size_read(inode)) || (iomap.iomap_flags & IOMAP_NEW))) { - set_buffer_new(bh_result); - } - - if (iomap.iomap_flags & IOMAP_DELAY) { - if (unlikely(direct)) - BUG(); - if (create) { - set_buffer_mapped(bh_result); - set_buffer_uptodate(bh_result); - } - bh_result->b_bdev = iomap.iomap_target->pbr_bdev; - set_buffer_delay(bh_result); - } - - if (blocks) { - loff_t iosize; - iosize = (iomap.iomap_bsize - iomap.iomap_delta); - bh_result->b_size = - (ssize_t)min(iosize, (loff_t)(blocks << inode->i_blkbits)); - } - - return 0; -} - -int -linvfs_get_block( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create) -{ - return linvfs_get_block_core(inode, iblock, 0, bh_result, - create, 0, BMAPI_WRITE); -} - -STATIC int -linvfs_get_block_sync( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create) -{ - return linvfs_get_block_core(inode, iblock, 0, bh_result, - create, 0, BMAPI_SYNC|BMAPI_WRITE); -} - -STATIC int -linvfs_get_blocks_direct( - struct inode *inode, - sector_t iblock, - unsigned long max_blocks, - struct buffer_head *bh_result, - int create) -{ - return linvfs_get_block_core(inode, iblock, max_blocks, bh_result, - create, 1, BMAPI_WRITE|BMAPI_DIRECT); -} - -STATIC ssize_t -linvfs_direct_IO( - int rw, - struct kiocb *iocb, - const struct iovec *iov, - loff_t offset, - unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - vnode_t *vp = LINVFS_GET_VP(inode); - xfs_iomap_t iomap; - int maps = 1; - int error; - - VOP_BMAP(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps, error); - if (error) - return -error; - - return blockdev_direct_IO_no_locking(rw, iocb, inode, - iomap.iomap_target->pbr_bdev, - iov, offset, nr_segs, - linvfs_get_blocks_direct, - linvfs_unwritten_convert_direct); -} - - -STATIC sector_t -linvfs_bmap( - struct address_space *mapping, - sector_t block) -{ - struct inode *inode = (struct inode *)mapping->host; - vnode_t *vp = LINVFS_GET_VP(inode); - int error; - - vn_trace_entry(vp, "linvfs_bmap", (inst_t *)__return_address); - - VOP_RWLOCK(vp, VRWLOCK_READ); - VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); - VOP_RWUNLOCK(vp, VRWLOCK_READ); - return generic_block_bmap(mapping, block, linvfs_get_block); -} - -STATIC int -linvfs_readpage( - struct file *unused, - struct page *page) -{ - return mpage_readpage(page, linvfs_get_block); -} - -STATIC int -linvfs_readpages( - struct file *unused, - struct address_space *mapping, - struct list_head *pages, - unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, linvfs_get_block); -} - -STATIC void -xfs_count_page_state( - struct page *page, - int *delalloc, - int *unmapped, - int *unwritten) -{ - struct buffer_head *bh, *head; - - *delalloc = *unmapped = *unwritten = 0; - - bh = head = page_buffers(page); - do { - if (buffer_uptodate(bh) && !buffer_mapped(bh)) - (*unmapped) = 1; - else if (buffer_unwritten(bh) && !buffer_delay(bh)) - clear_buffer_unwritten(bh); - else if (buffer_unwritten(bh)) - (*unwritten) = 1; - else if (buffer_delay(bh)) - (*delalloc) = 1; - } while ((bh = bh->b_this_page) != head); -} - - -/* - * writepage: Called from one of two places: - * - * 1. we are flushing a delalloc buffer head. - * - * 2. we are writing out a dirty page. Typically the page dirty - * state is cleared before we get here. In this case is it - * conceivable we have no buffer heads. - * - * For delalloc space on the page we need to allocate space and - * flush it. For unmapped buffer heads on the page we should - * allocate space if the page is uptodate. For any other dirty - * buffer heads on the page we should flush them. - * - * If we detect that a transaction would be required to flush - * the page, we have to check the process flags first, if we - * are already in a transaction or disk I/O during allocations - * is off, we need to fail the writepage and redirty the page. - */ - -STATIC int -linvfs_writepage( - struct page *page, - struct writeback_control *wbc) -{ - int error; - int need_trans; - int delalloc, unmapped, unwritten; - struct inode *inode = page->mapping->host; - - xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0); - - /* - * We need a transaction if: - * 1. There are delalloc buffers on the page - * 2. The page is uptodate and we have unmapped buffers - * 3. The page is uptodate and we have no buffers - * 4. There are unwritten buffers on the page - */ - - if (!page_has_buffers(page)) { - unmapped = 1; - need_trans = 1; - } else { - xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); - if (!PageUptodate(page)) - unmapped = 0; - need_trans = delalloc + unmapped + unwritten; - } - - /* - * If we need a transaction and the process flags say - * we are already in a transaction, or no IO is allowed - * then mark the page dirty again and leave the page - * as is. - */ - if (PFLAGS_TEST_FSTRANS() && need_trans) - goto out_fail; - - /* - * Delay hooking up buffer heads until we have - * made our go/no-go decision. - */ - if (!page_has_buffers(page)) - create_empty_buffers(page, 1 << inode->i_blkbits, 0); - - /* - * Convert delayed allocate, unwritten or unmapped space - * to real space and flush out to disk. - */ - error = xfs_page_state_convert(inode, page, 1, unmapped); - if (error == -EAGAIN) - goto out_fail; - if (unlikely(error < 0)) - goto out_unlock; - - return 0; - -out_fail: - set_page_dirty(page); - unlock_page(page); - return 0; -out_unlock: - unlock_page(page); - return error; -} - -/* - * Called to move a page into cleanable state - and from there - * to be released. Possibly the page is already clean. We always - * have buffer heads in this call. - * - * Returns 0 if the page is ok to release, 1 otherwise. - * - * Possible scenarios are: - * - * 1. We are being called to release a page which has been written - * to via regular I/O. buffer heads will be dirty and possibly - * delalloc. If no delalloc buffer heads in this case then we - * can just return zero. - * - * 2. We are called to release a page which has been written via - * mmap, all we need to do is ensure there is no delalloc - * state in the buffer heads, if not we can let the caller - * free them and we should come back later via writepage. - */ -STATIC int -linvfs_release_page( - struct page *page, - int gfp_mask) -{ - struct inode *inode = page->mapping->host; - int dirty, delalloc, unmapped, unwritten; - - xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask); - - xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); - if (!delalloc && !unwritten) - goto free_buffers; - - if (!(gfp_mask & __GFP_FS)) - return 0; - - /* If we are already inside a transaction or the thread cannot - * do I/O, we cannot release this page. - */ - if (PFLAGS_TEST_FSTRANS()) - return 0; - - /* - * Convert delalloc space to real space, do not flush the - * data out to disk, that will be done by the caller. - * Never need to allocate space here - we will always - * come back to writepage in that case. - */ - dirty = xfs_page_state_convert(inode, page, 0, 0); - if (dirty == 0 && !unwritten) - goto free_buffers; - return 0; - -free_buffers: - return try_to_free_buffers(page); -} - -STATIC int -linvfs_prepare_write( - struct file *file, - struct page *page, - unsigned int from, - unsigned int to) -{ - if (file && (file->f_flags & O_SYNC)) { - return block_prepare_write(page, from, to, - linvfs_get_block_sync); - } else { - return block_prepare_write(page, from, to, - linvfs_get_block); - } -} - -struct address_space_operations linvfs_aops = { - .readpage = linvfs_readpage, - .readpages = linvfs_readpages, - .writepage = linvfs_writepage, - .sync_page = block_sync_page, - .releasepage = linvfs_release_page, - .prepare_write = linvfs_prepare_write, - .commit_write = generic_commit_write, - .bmap = linvfs_bmap, - .direct_IO = linvfs_direct_IO, -}; diff --git a/fs/xfs/linux/xfs_buf.c b/fs/xfs/linux/xfs_buf.c deleted file mode 100644 index 69050a0de..000000000 --- a/fs/xfs/linux/xfs_buf.c +++ /dev/null @@ -1,1811 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -/* - * The xfs_buf.c code provides an abstract buffer cache model on top - * of the Linux page cache. Cached metadata blocks for a file system - * are hashed to the inode for the block device. xfs_buf.c assembles - * buffers (xfs_buf_t) on demand to aggregate such cached pages for I/O. - * - * Written by Steve Lord, Jim Mostek, Russell Cattelan - * and Rajagopal Ananthanarayanan ("ananth") at SGI. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xfs_linux.h" - -#ifndef GFP_READAHEAD -#define GFP_READAHEAD (__GFP_NOWARN|__GFP_NORETRY) -#endif - -/* - * File wide globals - */ - -STATIC kmem_cache_t *pagebuf_cache; -STATIC void pagebuf_daemon_wakeup(void); -STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); -STATIC struct workqueue_struct *pagebuf_logio_workqueue; -STATIC struct workqueue_struct *pagebuf_dataio_workqueue; - -/* - * Pagebuf debugging - */ - -#ifdef PAGEBUF_TRACE -void -pagebuf_trace( - xfs_buf_t *pb, - char *id, - void *data, - void *ra) -{ - ktrace_enter(pagebuf_trace_buf, - pb, id, - (void *)(unsigned long)pb->pb_flags, - (void *)(unsigned long)pb->pb_hold.counter, - (void *)(unsigned long)pb->pb_sema.count.counter, - (void *)current, - data, ra, - (void *)(unsigned long)((pb->pb_file_offset>>32) & 0xffffffff), - (void *)(unsigned long)(pb->pb_file_offset & 0xffffffff), - (void *)(unsigned long)pb->pb_buffer_length, - NULL, NULL, NULL, NULL, NULL); -} -ktrace_t *pagebuf_trace_buf; -#define PAGEBUF_TRACE_SIZE 4096 -#define PB_TRACE(pb, id, data) \ - pagebuf_trace(pb, id, (void *)data, (void *)__builtin_return_address(0)) -#else -#define PB_TRACE(pb, id, data) do { } while (0) -#endif - -#ifdef PAGEBUF_LOCK_TRACKING -# define PB_SET_OWNER(pb) ((pb)->pb_last_holder = current->pid) -# define PB_CLEAR_OWNER(pb) ((pb)->pb_last_holder = -1) -# define PB_GET_OWNER(pb) ((pb)->pb_last_holder) -#else -# define PB_SET_OWNER(pb) do { } while (0) -# define PB_CLEAR_OWNER(pb) do { } while (0) -# define PB_GET_OWNER(pb) do { } while (0) -#endif - -/* - * Pagebuf allocation / freeing. - */ - -#define pb_to_gfp(flags) \ - (((flags) & PBF_READ_AHEAD) ? GFP_READAHEAD : \ - ((flags) & PBF_DONT_BLOCK) ? GFP_NOFS : GFP_KERNEL) - -#define pb_to_km(flags) \ - (((flags) & PBF_DONT_BLOCK) ? KM_NOFS : KM_SLEEP) - - -#define pagebuf_allocate(flags) \ - kmem_zone_alloc(pagebuf_cache, pb_to_km(flags)) -#define pagebuf_deallocate(pb) \ - kmem_zone_free(pagebuf_cache, (pb)); - -/* - * Pagebuf hashing - */ - -#define NBITS 8 -#define NHASH (1<pb_hash_index] - -STATIC int -_bhash( - struct block_device *bdev, - loff_t base) -{ - int bit, hval; - - base >>= 9; - base ^= (unsigned long)bdev / L1_CACHE_BYTES; - for (bit = hval = 0; base && bit < sizeof(base) * 8; bit += NBITS) { - hval ^= (int)base & (NHASH-1); - base >>= NBITS; - } - return hval; -} - -/* - * Mapping of multi-page buffers into contiguous virtual space - */ - -typedef struct a_list { - void *vm_addr; - struct a_list *next; -} a_list_t; - -STATIC a_list_t *as_free_head; -STATIC int as_list_len; -STATIC spinlock_t as_lock = SPIN_LOCK_UNLOCKED; - -/* - * Try to batch vunmaps because they are costly. - */ -STATIC void -free_address( - void *addr) -{ - a_list_t *aentry; - - aentry = kmalloc(sizeof(a_list_t), GFP_ATOMIC); - if (aentry) { - spin_lock(&as_lock); - aentry->next = as_free_head; - aentry->vm_addr = addr; - as_free_head = aentry; - as_list_len++; - spin_unlock(&as_lock); - } else { - vunmap(addr); - } -} - -STATIC void -purge_addresses(void) -{ - a_list_t *aentry, *old; - - if (as_free_head == NULL) - return; - - spin_lock(&as_lock); - aentry = as_free_head; - as_free_head = NULL; - as_list_len = 0; - spin_unlock(&as_lock); - - while ((old = aentry) != NULL) { - vunmap(aentry->vm_addr); - aentry = aentry->next; - kfree(old); - } -} - -/* - * Internal pagebuf object manipulation - */ - -STATIC void -_pagebuf_initialize( - xfs_buf_t *pb, - xfs_buftarg_t *target, - loff_t range_base, - size_t range_length, - page_buf_flags_t flags) -{ - /* - * We don't want certain flags to appear in pb->pb_flags. - */ - flags &= ~(PBF_LOCK|PBF_MAPPED|PBF_DONT_BLOCK|PBF_READ_AHEAD); - - memset(pb, 0, sizeof(xfs_buf_t)); - atomic_set(&pb->pb_hold, 1); - init_MUTEX_LOCKED(&pb->pb_iodonesema); - INIT_LIST_HEAD(&pb->pb_list); - INIT_LIST_HEAD(&pb->pb_hash_list); - init_MUTEX_LOCKED(&pb->pb_sema); /* held, no waiters */ - PB_SET_OWNER(pb); - pb->pb_target = target; - pb->pb_file_offset = range_base; - /* - * Set buffer_length and count_desired to the same value initially. - * I/O routines should use count_desired, which will be the same in - * most cases but may be reset (e.g. XFS recovery). - */ - pb->pb_buffer_length = pb->pb_count_desired = range_length; - pb->pb_flags = flags | PBF_NONE; - pb->pb_bn = XFS_BUF_DADDR_NULL; - atomic_set(&pb->pb_pin_count, 0); - init_waitqueue_head(&pb->pb_waiters); - - XFS_STATS_INC(pb_create); - PB_TRACE(pb, "initialize", target); -} - -/* - * Allocate a page array capable of holding a specified number - * of pages, and point the page buf at it. - */ -STATIC int -_pagebuf_get_pages( - xfs_buf_t *pb, - int page_count, - page_buf_flags_t flags) -{ - /* Make sure that we have a page list */ - if (pb->pb_pages == NULL) { - pb->pb_offset = page_buf_poff(pb->pb_file_offset); - pb->pb_page_count = page_count; - if (page_count <= PB_PAGES) { - pb->pb_pages = pb->pb_page_array; - } else { - pb->pb_pages = kmem_alloc(sizeof(struct page *) * - page_count, pb_to_km(flags)); - if (pb->pb_pages == NULL) - return -ENOMEM; - } - memset(pb->pb_pages, 0, sizeof(struct page *) * page_count); - } - return 0; -} - -/* - * Frees pb_pages if it was malloced. - */ -STATIC void -_pagebuf_free_pages( - xfs_buf_t *bp) -{ - if (bp->pb_pages != bp->pb_page_array) { - kmem_free(bp->pb_pages, - bp->pb_page_count * sizeof(struct page *)); - } -} - -/* - * Releases the specified buffer. - * - * The modification state of any associated pages is left unchanged. - * The buffer most not be on any hash - use pagebuf_rele instead for - * hashed and refcounted buffers - */ -void -pagebuf_free( - xfs_buf_t *bp) -{ - PB_TRACE(bp, "free", 0); - - ASSERT(list_empty(&bp->pb_hash_list)); - - if (bp->pb_flags & _PBF_PAGE_CACHE) { - uint i; - - if ((bp->pb_flags & PBF_MAPPED) && (bp->pb_page_count > 1)) - free_address(bp->pb_addr - bp->pb_offset); - - for (i = 0; i < bp->pb_page_count; i++) - page_cache_release(bp->pb_pages[i]); - _pagebuf_free_pages(bp); - } else if (bp->pb_flags & _PBF_KMEM_ALLOC) { - /* - * XXX(hch): bp->pb_count_desired might be incorrect (see - * pagebuf_associate_memory for details), but fortunately - * the Linux version of kmem_free ignores the len argument.. - */ - kmem_free(bp->pb_addr, bp->pb_count_desired); - _pagebuf_free_pages(bp); - } - - pagebuf_deallocate(bp); -} - -/* - * Finds all pages for buffer in question and builds it's page list. - */ -STATIC int -_pagebuf_lookup_pages( - xfs_buf_t *bp, - uint flags) -{ - struct address_space *mapping = bp->pb_target->pbr_mapping; - unsigned int sectorshift = bp->pb_target->pbr_sshift; - size_t blocksize = bp->pb_target->pbr_bsize; - size_t size = bp->pb_count_desired; - size_t nbytes, offset; - int gfp_mask = pb_to_gfp(flags); - unsigned short page_count, i; - pgoff_t first; - loff_t end; - int error; - - end = bp->pb_file_offset + bp->pb_buffer_length; - page_count = page_buf_btoc(end) - page_buf_btoct(bp->pb_file_offset); - - error = _pagebuf_get_pages(bp, page_count, flags); - if (unlikely(error)) - return error; - - offset = bp->pb_offset; - first = bp->pb_file_offset >> PAGE_CACHE_SHIFT; - - for (i = 0; i < bp->pb_page_count; i++) { - struct page *page; - uint retries = 0; - - retry: - page = find_or_create_page(mapping, first + i, gfp_mask); - if (unlikely(page == NULL)) { - if (flags & PBF_READ_AHEAD) - return -ENOMEM; - - /* - * This could deadlock. - * - * But until all the XFS lowlevel code is revamped to - * handle buffer allocation failures we can't do much. - */ - if (!(++retries % 100)) { - printk(KERN_ERR "possibly deadlocking in %s\n", - __FUNCTION__); - } - - XFS_STATS_INC(pb_page_retries); - pagebuf_daemon_wakeup(); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(10); - goto retry; - } - - XFS_STATS_INC(pb_page_found); - - nbytes = min_t(size_t, size, PAGE_CACHE_SIZE - offset); - size -= nbytes; - - if (!PageUptodate(page)) { - page_count--; - if (blocksize == PAGE_CACHE_SIZE) { - if (flags & PBF_READ) - bp->pb_locked = 1; - } else if (!PagePrivate(page)) { - unsigned long j, range; - - /* - * In this case page->private holds a bitmap - * of uptodate sectors within the page - */ - ASSERT(blocksize < PAGE_CACHE_SIZE); - range = (offset + nbytes) >> sectorshift; - for (j = offset >> sectorshift; j < range; j++) - if (!test_bit(j, &page->private)) - break; - if (j == range) - page_count++; - } - } - - bp->pb_pages[i] = page; - offset = 0; - } - - if (!bp->pb_locked) { - for (i = 0; i < bp->pb_page_count; i++) - unlock_page(bp->pb_pages[i]); - } - - bp->pb_flags |= _PBF_PAGE_CACHE; - - if (page_count) { - /* if we have any uptodate pages, mark that in the buffer */ - bp->pb_flags &= ~PBF_NONE; - - /* if some pages aren't uptodate, mark that in the buffer */ - if (page_count != bp->pb_page_count) - bp->pb_flags |= PBF_PARTIAL; - } - - PB_TRACE(bp, "lookup_pages", (long)page_count); - return error; -} - -/* - * Map buffer into kernel address-space if nessecary. - */ -STATIC int -_pagebuf_map_pages( - xfs_buf_t *bp, - uint flags) -{ - /* A single page buffer is always mappable */ - if (bp->pb_page_count == 1) { - bp->pb_addr = page_address(bp->pb_pages[0]) + bp->pb_offset; - bp->pb_flags |= PBF_MAPPED; - } else if (flags & PBF_MAPPED) { - if (as_list_len > 64) - purge_addresses(); - bp->pb_addr = vmap(bp->pb_pages, bp->pb_page_count, - VM_MAP, PAGE_KERNEL); - if (unlikely(bp->pb_addr == NULL)) - return -ENOMEM; - bp->pb_addr += bp->pb_offset; - bp->pb_flags |= PBF_MAPPED; - } - - return 0; -} - -/* - * Finding and Reading Buffers - */ - -/* - * _pagebuf_find - * - * Looks up, and creates if absent, a lockable buffer for - * a given range of an inode. The buffer is returned - * locked. If other overlapping buffers exist, they are - * released before the new buffer is created and locked, - * which may imply that this call will block until those buffers - * are unlocked. No I/O is implied by this call. - */ -STATIC xfs_buf_t * -_pagebuf_find( /* find buffer for block */ - xfs_buftarg_t *target,/* target for block */ - loff_t ioff, /* starting offset of range */ - size_t isize, /* length of range */ - page_buf_flags_t flags, /* PBF_TRYLOCK */ - xfs_buf_t *new_pb)/* newly allocated buffer */ -{ - loff_t range_base; - size_t range_length; - int hval; - pb_hash_t *h; - xfs_buf_t *pb, *n; - int not_locked; - - range_base = (ioff << BBSHIFT); - range_length = (isize << BBSHIFT); - - /* Ensure we never do IOs smaller than the sector size */ - BUG_ON(range_length < (1 << target->pbr_sshift)); - - /* Ensure we never do IOs that are not sector aligned */ - BUG_ON(range_base & (loff_t)target->pbr_smask); - - hval = _bhash(target->pbr_bdev, range_base); - h = &pbhash[hval]; - - spin_lock(&h->pb_hash_lock); - list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) { - if (pb->pb_target == target && - pb->pb_file_offset == range_base && - pb->pb_buffer_length == range_length) { - /* If we look at something bring it to the - * front of the list for next time - */ - atomic_inc(&pb->pb_hold); - list_move(&pb->pb_hash_list, &h->pb_hash); - goto found; - } - } - - /* No match found */ - if (new_pb) { - _pagebuf_initialize(new_pb, target, range_base, - range_length, flags); - new_pb->pb_hash_index = hval; - list_add(&new_pb->pb_hash_list, &h->pb_hash); - } else { - XFS_STATS_INC(pb_miss_locked); - } - - spin_unlock(&h->pb_hash_lock); - return (new_pb); - -found: - spin_unlock(&h->pb_hash_lock); - - /* Attempt to get the semaphore without sleeping, - * if this does not work then we need to drop the - * spinlock and do a hard attempt on the semaphore. - */ - not_locked = down_trylock(&pb->pb_sema); - if (not_locked) { - if (!(flags & PBF_TRYLOCK)) { - /* wait for buffer ownership */ - PB_TRACE(pb, "get_lock", 0); - pagebuf_lock(pb); - XFS_STATS_INC(pb_get_locked_waited); - } else { - /* We asked for a trylock and failed, no need - * to look at file offset and length here, we - * know that this pagebuf at least overlaps our - * pagebuf and is locked, therefore our buffer - * either does not exist, or is this buffer - */ - - pagebuf_rele(pb); - XFS_STATS_INC(pb_busy_locked); - return (NULL); - } - } else { - /* trylock worked */ - PB_SET_OWNER(pb); - } - - if (pb->pb_flags & PBF_STALE) - pb->pb_flags &= PBF_MAPPED; - PB_TRACE(pb, "got_lock", 0); - XFS_STATS_INC(pb_get_locked); - return (pb); -} - - -/* - * pagebuf_find - * - * pagebuf_find returns a buffer matching the specified range of - * data for the specified target, if any of the relevant blocks - * are in memory. The buffer may have unallocated holes, if - * some, but not all, of the blocks are in memory. Even where - * pages are present in the buffer, not all of every page may be - * valid. - */ -xfs_buf_t * -pagebuf_find( /* find buffer for block */ - /* if the block is in memory */ - xfs_buftarg_t *target,/* target for block */ - loff_t ioff, /* starting offset of range */ - size_t isize, /* length of range */ - page_buf_flags_t flags) /* PBF_TRYLOCK */ -{ - return _pagebuf_find(target, ioff, isize, flags, NULL); -} - -/* - * pagebuf_get - * - * pagebuf_get assembles a buffer covering the specified range. - * Some or all of the blocks in the range may be valid. Storage - * in memory for all portions of the buffer will be allocated, - * although backing storage may not be. If PBF_READ is set in - * flags, pagebuf_iostart is called also. - */ -xfs_buf_t * -pagebuf_get( /* allocate a buffer */ - xfs_buftarg_t *target,/* target for buffer */ - loff_t ioff, /* starting offset of range */ - size_t isize, /* length of range */ - page_buf_flags_t flags) /* PBF_TRYLOCK */ -{ - xfs_buf_t *pb, *new_pb; - int error = 0, i; - - new_pb = pagebuf_allocate(flags); - if (unlikely(!new_pb)) - return NULL; - - pb = _pagebuf_find(target, ioff, isize, flags, new_pb); - if (pb == new_pb) { - error = _pagebuf_lookup_pages(pb, flags); - if (unlikely(error)) { - printk(KERN_WARNING - "pagebuf_get: failed to lookup pages\n"); - goto no_buffer; - } - } else { - pagebuf_deallocate(new_pb); - if (unlikely(pb == NULL)) - return NULL; - } - - for (i = 0; i < pb->pb_page_count; i++) - mark_page_accessed(pb->pb_pages[i]); - - if (!(pb->pb_flags & PBF_MAPPED)) { - error = _pagebuf_map_pages(pb, flags); - if (unlikely(error)) { - printk(KERN_WARNING - "pagebuf_get: failed to map pages\n"); - goto no_buffer; - } - } - - XFS_STATS_INC(pb_get); - - /* - * Always fill in the block number now, the mapped cases can do - * their own overlay of this later. - */ - pb->pb_bn = ioff; - pb->pb_count_desired = pb->pb_buffer_length; - - if (flags & PBF_READ) { - if (PBF_NOT_DONE(pb)) { - PB_TRACE(pb, "get_read", (unsigned long)flags); - XFS_STATS_INC(pb_get_read); - pagebuf_iostart(pb, flags); - } else if (flags & PBF_ASYNC) { - PB_TRACE(pb, "get_read_async", (unsigned long)flags); - /* - * Read ahead call which is already satisfied, - * drop the buffer - */ - goto no_buffer; - } else { - PB_TRACE(pb, "get_read_done", (unsigned long)flags); - /* We do not want read in the flags */ - pb->pb_flags &= ~PBF_READ; - } - } else { - PB_TRACE(pb, "get_write", (unsigned long)flags); - } - - return pb; - -no_buffer: - if (flags & (PBF_LOCK | PBF_TRYLOCK)) - pagebuf_unlock(pb); - pagebuf_rele(pb); - return NULL; -} - -/* - * Create a skeletal pagebuf (no pages associated with it). - */ -xfs_buf_t * -pagebuf_lookup( - xfs_buftarg_t *target, - loff_t ioff, - size_t isize, - page_buf_flags_t flags) -{ - xfs_buf_t *pb; - - pb = pagebuf_allocate(flags); - if (pb) { - _pagebuf_initialize(pb, target, ioff, isize, flags); - } - return pb; -} - -/* - * If we are not low on memory then do the readahead in a deadlock - * safe manner. - */ -void -pagebuf_readahead( - xfs_buftarg_t *target, - loff_t ioff, - size_t isize, - page_buf_flags_t flags) -{ - struct backing_dev_info *bdi; - - bdi = target->pbr_mapping->backing_dev_info; - if (bdi_read_congested(bdi)) - return; - if (bdi_write_congested(bdi)) - return; - - flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_READ_AHEAD); - pagebuf_get(target, ioff, isize, flags); -} - -xfs_buf_t * -pagebuf_get_empty( - size_t len, - xfs_buftarg_t *target) -{ - xfs_buf_t *pb; - - pb = pagebuf_allocate(0); - if (pb) - _pagebuf_initialize(pb, target, 0, len, 0); - return pb; -} - -static inline struct page * -mem_to_page( - void *addr) -{ - if (((unsigned long)addr < VMALLOC_START) || - ((unsigned long)addr >= VMALLOC_END)) { - return virt_to_page(addr); - } else { - return vmalloc_to_page(addr); - } -} - -int -pagebuf_associate_memory( - xfs_buf_t *pb, - void *mem, - size_t len) -{ - int rval; - int i = 0; - size_t ptr; - size_t end, end_cur; - off_t offset; - int page_count; - - page_count = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT; - offset = (off_t) mem - ((off_t)mem & PAGE_CACHE_MASK); - if (offset && (len > PAGE_CACHE_SIZE)) - page_count++; - - /* Free any previous set of page pointers */ - if (pb->pb_pages) - _pagebuf_free_pages(pb); - - pb->pb_pages = NULL; - pb->pb_addr = mem; - - rval = _pagebuf_get_pages(pb, page_count, 0); - if (rval) - return rval; - - pb->pb_offset = offset; - ptr = (size_t) mem & PAGE_CACHE_MASK; - end = PAGE_CACHE_ALIGN((size_t) mem + len); - end_cur = end; - /* set up first page */ - pb->pb_pages[0] = mem_to_page(mem); - - ptr += PAGE_CACHE_SIZE; - pb->pb_page_count = ++i; - while (ptr < end) { - pb->pb_pages[i] = mem_to_page((void *)ptr); - pb->pb_page_count = ++i; - ptr += PAGE_CACHE_SIZE; - } - pb->pb_locked = 0; - - pb->pb_count_desired = pb->pb_buffer_length = len; - pb->pb_flags |= PBF_MAPPED; - - return 0; -} - -xfs_buf_t * -pagebuf_get_no_daddr( - size_t len, - xfs_buftarg_t *target) -{ - size_t malloc_len = len; - xfs_buf_t *bp; - void *data; - int error; - - if (unlikely(len > 0x20000)) - goto fail; - - bp = pagebuf_allocate(0); - if (unlikely(bp == NULL)) - goto fail; - _pagebuf_initialize(bp, target, 0, len, PBF_FORCEIO); - - try_again: - data = kmem_alloc(malloc_len, KM_SLEEP); - if (unlikely(data == NULL)) - goto fail_free_buf; - - /* check whether alignment matches.. */ - if ((__psunsigned_t)data != - ((__psunsigned_t)data & ~target->pbr_smask)) { - /* .. else double the size and try again */ - kmem_free(data, malloc_len); - malloc_len <<= 1; - goto try_again; - } - - error = pagebuf_associate_memory(bp, data, len); - if (error) - goto fail_free_mem; - bp->pb_flags |= _PBF_KMEM_ALLOC; - - pagebuf_unlock(bp); - - PB_TRACE(bp, "no_daddr", data); - return bp; - fail_free_mem: - kmem_free(data, malloc_len); - fail_free_buf: - pagebuf_free(bp); - fail: - return NULL; -} - -/* - * pagebuf_hold - * - * Increment reference count on buffer, to hold the buffer concurrently - * with another thread which may release (free) the buffer asynchronously. - * - * Must hold the buffer already to call this function. - */ -void -pagebuf_hold( - xfs_buf_t *pb) -{ - atomic_inc(&pb->pb_hold); - PB_TRACE(pb, "hold", 0); -} - -/* - * pagebuf_rele - * - * pagebuf_rele releases a hold on the specified buffer. If the - * the hold count is 1, pagebuf_rele calls pagebuf_free. - */ -void -pagebuf_rele( - xfs_buf_t *pb) -{ - pb_hash_t *hash = pb_hash(pb); - - PB_TRACE(pb, "rele", pb->pb_relse); - - if (atomic_dec_and_lock(&pb->pb_hold, &hash->pb_hash_lock)) { - int do_free = 1; - - if (pb->pb_relse) { - atomic_inc(&pb->pb_hold); - spin_unlock(&hash->pb_hash_lock); - (*(pb->pb_relse)) (pb); - spin_lock(&hash->pb_hash_lock); - do_free = 0; - } - - if (pb->pb_flags & PBF_DELWRI) { - pb->pb_flags |= PBF_ASYNC; - atomic_inc(&pb->pb_hold); - pagebuf_delwri_queue(pb, 0); - do_free = 0; - } else if (pb->pb_flags & PBF_FS_MANAGED) { - do_free = 0; - } - - if (do_free) { - list_del_init(&pb->pb_hash_list); - spin_unlock(&hash->pb_hash_lock); - pagebuf_free(pb); - } else { - spin_unlock(&hash->pb_hash_lock); - } - } -} - - -/* - * Mutual exclusion on buffers. Locking model: - * - * Buffers associated with inodes for which buffer locking - * is not enabled are not protected by semaphores, and are - * assumed to be exclusively owned by the caller. There is a - * spinlock in the buffer, used by the caller when concurrent - * access is possible. - */ - -/* - * pagebuf_cond_lock - * - * pagebuf_cond_lock locks a buffer object, if it is not already locked. - * Note that this in no way - * locks the underlying pages, so it is only useful for synchronizing - * concurrent use of page buffer objects, not for synchronizing independent - * access to the underlying pages. - */ -int -pagebuf_cond_lock( /* lock buffer, if not locked */ - /* returns -EBUSY if locked) */ - xfs_buf_t *pb) -{ - int locked; - - locked = down_trylock(&pb->pb_sema) == 0; - if (locked) { - PB_SET_OWNER(pb); - } - PB_TRACE(pb, "cond_lock", (long)locked); - return(locked ? 0 : -EBUSY); -} - -/* - * pagebuf_lock_value - * - * Return lock value for a pagebuf - */ -int -pagebuf_lock_value( - xfs_buf_t *pb) -{ - return(atomic_read(&pb->pb_sema.count)); -} - -/* - * pagebuf_lock - * - * pagebuf_lock locks a buffer object. Note that this in no way - * locks the underlying pages, so it is only useful for synchronizing - * concurrent use of page buffer objects, not for synchronizing independent - * access to the underlying pages. - */ -int -pagebuf_lock( - xfs_buf_t *pb) -{ - PB_TRACE(pb, "lock", 0); - if (atomic_read(&pb->pb_io_remaining)) - blk_run_address_space(pb->pb_target->pbr_mapping); - down(&pb->pb_sema); - PB_SET_OWNER(pb); - PB_TRACE(pb, "locked", 0); - return 0; -} - -/* - * pagebuf_unlock - * - * pagebuf_unlock releases the lock on the buffer object created by - * pagebuf_lock or pagebuf_cond_lock (not any - * pinning of underlying pages created by pagebuf_pin). - */ -void -pagebuf_unlock( /* unlock buffer */ - xfs_buf_t *pb) /* buffer to unlock */ -{ - PB_CLEAR_OWNER(pb); - up(&pb->pb_sema); - PB_TRACE(pb, "unlock", 0); -} - - -/* - * Pinning Buffer Storage in Memory - */ - -/* - * pagebuf_pin - * - * pagebuf_pin locks all of the memory represented by a buffer in - * memory. Multiple calls to pagebuf_pin and pagebuf_unpin, for - * the same or different buffers affecting a given page, will - * properly count the number of outstanding "pin" requests. The - * buffer may be released after the pagebuf_pin and a different - * buffer used when calling pagebuf_unpin, if desired. - * pagebuf_pin should be used by the file system when it wants be - * assured that no attempt will be made to force the affected - * memory to disk. It does not assure that a given logical page - * will not be moved to a different physical page. - */ -void -pagebuf_pin( - xfs_buf_t *pb) -{ - atomic_inc(&pb->pb_pin_count); - PB_TRACE(pb, "pin", (long)pb->pb_pin_count.counter); -} - -/* - * pagebuf_unpin - * - * pagebuf_unpin reverses the locking of memory performed by - * pagebuf_pin. Note that both functions affected the logical - * pages associated with the buffer, not the buffer itself. - */ -void -pagebuf_unpin( - xfs_buf_t *pb) -{ - if (atomic_dec_and_test(&pb->pb_pin_count)) { - wake_up_all(&pb->pb_waiters); - } - PB_TRACE(pb, "unpin", (long)pb->pb_pin_count.counter); -} - -int -pagebuf_ispin( - xfs_buf_t *pb) -{ - return atomic_read(&pb->pb_pin_count); -} - -/* - * pagebuf_wait_unpin - * - * pagebuf_wait_unpin waits until all of the memory associated - * with the buffer is not longer locked in memory. It returns - * immediately if none of the affected pages are locked. - */ -static inline void -_pagebuf_wait_unpin( - xfs_buf_t *pb) -{ - DECLARE_WAITQUEUE (wait, current); - - if (atomic_read(&pb->pb_pin_count) == 0) - return; - - add_wait_queue(&pb->pb_waiters, &wait); - for (;;) { - current->state = TASK_UNINTERRUPTIBLE; - if (atomic_read(&pb->pb_pin_count) == 0) - break; - if (atomic_read(&pb->pb_io_remaining)) - blk_run_address_space(pb->pb_target->pbr_mapping); - schedule(); - } - remove_wait_queue(&pb->pb_waiters, &wait); - current->state = TASK_RUNNING; -} - -/* - * Buffer Utility Routines - */ - -/* - * pagebuf_iodone - * - * pagebuf_iodone marks a buffer for which I/O is in progress - * done with respect to that I/O. The pb_iodone routine, if - * present, will be called as a side-effect. - */ -void -pagebuf_iodone_work( - void *v) -{ - xfs_buf_t *bp = (xfs_buf_t *)v; - - if (bp->pb_iodone) - (*(bp->pb_iodone))(bp); - else if (bp->pb_flags & PBF_ASYNC) - xfs_buf_relse(bp); -} - -void -pagebuf_iodone( - xfs_buf_t *pb, - int dataio, - int schedule) -{ - pb->pb_flags &= ~(PBF_READ | PBF_WRITE); - if (pb->pb_error == 0) { - pb->pb_flags &= ~(PBF_PARTIAL | PBF_NONE); - } - - PB_TRACE(pb, "iodone", pb->pb_iodone); - - if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) { - if (schedule) { - INIT_WORK(&pb->pb_iodone_work, pagebuf_iodone_work, pb); - queue_work(dataio ? pagebuf_dataio_workqueue : - pagebuf_logio_workqueue, &pb->pb_iodone_work); - } else { - pagebuf_iodone_work(pb); - } - } else { - up(&pb->pb_iodonesema); - } -} - -/* - * pagebuf_ioerror - * - * pagebuf_ioerror sets the error code for a buffer. - */ -void -pagebuf_ioerror( /* mark/clear buffer error flag */ - xfs_buf_t *pb, /* buffer to mark */ - int error) /* error to store (0 if none) */ -{ - ASSERT(error >= 0 && error <= 0xffff); - pb->pb_error = (unsigned short)error; - PB_TRACE(pb, "ioerror", (unsigned long)error); -} - -/* - * pagebuf_iostart - * - * pagebuf_iostart initiates I/O on a buffer, based on the flags supplied. - * If necessary, it will arrange for any disk space allocation required, - * and it will break up the request if the block mappings require it. - * The pb_iodone routine in the buffer supplied will only be called - * when all of the subsidiary I/O requests, if any, have been completed. - * pagebuf_iostart calls the pagebuf_ioinitiate routine or - * pagebuf_iorequest, if the former routine is not defined, to start - * the I/O on a given low-level request. - */ -int -pagebuf_iostart( /* start I/O on a buffer */ - xfs_buf_t *pb, /* buffer to start */ - page_buf_flags_t flags) /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ - /* PBF_WRITE, PBF_DELWRI, */ - /* PBF_DONT_BLOCK */ -{ - int status = 0; - - PB_TRACE(pb, "iostart", (unsigned long)flags); - - if (flags & PBF_DELWRI) { - pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC); - pb->pb_flags |= flags & (PBF_DELWRI | PBF_ASYNC); - pagebuf_delwri_queue(pb, 1); - return status; - } - - pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_DELWRI | \ - PBF_READ_AHEAD | _PBF_RUN_QUEUES); - pb->pb_flags |= flags & (PBF_READ | PBF_WRITE | PBF_ASYNC | \ - PBF_READ_AHEAD | _PBF_RUN_QUEUES); - - BUG_ON(pb->pb_bn == XFS_BUF_DADDR_NULL); - - /* For writes allow an alternate strategy routine to precede - * the actual I/O request (which may not be issued at all in - * a shutdown situation, for example). - */ - status = (flags & PBF_WRITE) ? - pagebuf_iostrategy(pb) : pagebuf_iorequest(pb); - - /* Wait for I/O if we are not an async request. - * Note: async I/O request completion will release the buffer, - * and that can already be done by this point. So using the - * buffer pointer from here on, after async I/O, is invalid. - */ - if (!status && !(flags & PBF_ASYNC)) - status = pagebuf_iowait(pb); - - return status; -} - -/* - * Helper routine for pagebuf_iorequest - */ - -STATIC __inline__ int -_pagebuf_iolocked( - xfs_buf_t *pb) -{ - ASSERT(pb->pb_flags & (PBF_READ|PBF_WRITE)); - if (pb->pb_flags & PBF_READ) - return pb->pb_locked; - return 0; -} - -STATIC __inline__ void -_pagebuf_iodone( - xfs_buf_t *pb, - int schedule) -{ - if (atomic_dec_and_test(&pb->pb_io_remaining) == 1) { - pb->pb_locked = 0; - pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), schedule); - } -} - -STATIC int -bio_end_io_pagebuf( - struct bio *bio, - unsigned int bytes_done, - int error) -{ - xfs_buf_t *pb = (xfs_buf_t *)bio->bi_private; - unsigned int i, blocksize = pb->pb_target->pbr_bsize; - unsigned int sectorshift = pb->pb_target->pbr_sshift; - struct bio_vec *bvec = bio->bi_io_vec; - - if (bio->bi_size) - return 1; - - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - pb->pb_error = EIO; - - for (i = 0; i < bio->bi_vcnt; i++, bvec++) { - struct page *page = bvec->bv_page; - - if (pb->pb_error) { - SetPageError(page); - } else if (blocksize == PAGE_CACHE_SIZE) { - SetPageUptodate(page); - } else if (!PagePrivate(page) && - (pb->pb_flags & _PBF_PAGE_CACHE)) { - unsigned long j, range; - - ASSERT(blocksize < PAGE_CACHE_SIZE); - range = (bvec->bv_offset + bvec->bv_len) >> sectorshift; - for (j = bvec->bv_offset >> sectorshift; j < range; j++) - set_bit(j, &page->private); - if (page->private == (unsigned long)(PAGE_CACHE_SIZE-1)) - SetPageUptodate(page); - } - - if (_pagebuf_iolocked(pb)) { - unlock_page(page); - } - } - - _pagebuf_iodone(pb, 1); - bio_put(bio); - return 0; -} - -void -_pagebuf_ioapply( - xfs_buf_t *pb) -{ - int i, map_i, total_nr_pages, nr_pages; - struct bio *bio; - int offset = pb->pb_offset; - int size = pb->pb_count_desired; - sector_t sector = pb->pb_bn; - unsigned int blocksize = pb->pb_target->pbr_bsize; - int locking = _pagebuf_iolocked(pb); - - total_nr_pages = pb->pb_page_count; - map_i = 0; - - /* Special code path for reading a sub page size pagebuf in -- - * we populate up the whole page, and hence the other metadata - * in the same page. This optimization is only valid when the - * filesystem block size and the page size are equal. - */ - if ((pb->pb_buffer_length < PAGE_CACHE_SIZE) && - (pb->pb_flags & PBF_READ) && locking && - (blocksize == PAGE_CACHE_SIZE)) { - bio = bio_alloc(GFP_NOIO, 1); - - bio->bi_bdev = pb->pb_target->pbr_bdev; - bio->bi_sector = sector - (offset >> BBSHIFT); - bio->bi_end_io = bio_end_io_pagebuf; - bio->bi_private = pb; - - bio_add_page(bio, pb->pb_pages[0], PAGE_CACHE_SIZE, 0); - size = 0; - - atomic_inc(&pb->pb_io_remaining); - - goto submit_io; - } - - /* Lock down the pages which we need to for the request */ - if (locking && (pb->pb_flags & PBF_WRITE) && (pb->pb_locked == 0)) { - for (i = 0; size; i++) { - int nbytes = PAGE_CACHE_SIZE - offset; - struct page *page = pb->pb_pages[i]; - - if (nbytes > size) - nbytes = size; - - lock_page(page); - - size -= nbytes; - offset = 0; - } - offset = pb->pb_offset; - size = pb->pb_count_desired; - } - -next_chunk: - atomic_inc(&pb->pb_io_remaining); - nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - BBSHIFT); - if (nr_pages > total_nr_pages) - nr_pages = total_nr_pages; - - bio = bio_alloc(GFP_NOIO, nr_pages); - bio->bi_bdev = pb->pb_target->pbr_bdev; - bio->bi_sector = sector; - bio->bi_end_io = bio_end_io_pagebuf; - bio->bi_private = pb; - - for (; size && nr_pages; nr_pages--, map_i++) { - int nbytes = PAGE_CACHE_SIZE - offset; - - if (nbytes > size) - nbytes = size; - - if (bio_add_page(bio, pb->pb_pages[map_i], - nbytes, offset) < nbytes) - break; - - offset = 0; - sector += nbytes >> BBSHIFT; - size -= nbytes; - total_nr_pages--; - } - -submit_io: - if (likely(bio->bi_size)) { - submit_bio((pb->pb_flags & PBF_READ) ? READ : WRITE, bio); - if (size) - goto next_chunk; - } else { - bio_put(bio); - pagebuf_ioerror(pb, EIO); - } - - if (pb->pb_flags & _PBF_RUN_QUEUES) { - pb->pb_flags &= ~_PBF_RUN_QUEUES; - if (atomic_read(&pb->pb_io_remaining) > 1) - blk_run_address_space(pb->pb_target->pbr_mapping); - } -} - -/* - * pagebuf_iorequest -- the core I/O request routine. - */ -int -pagebuf_iorequest( /* start real I/O */ - xfs_buf_t *pb) /* buffer to convey to device */ -{ - PB_TRACE(pb, "iorequest", 0); - - if (pb->pb_flags & PBF_DELWRI) { - pagebuf_delwri_queue(pb, 1); - return 0; - } - - if (pb->pb_flags & PBF_WRITE) { - _pagebuf_wait_unpin(pb); - } - - pagebuf_hold(pb); - - /* Set the count to 1 initially, this will stop an I/O - * completion callout which happens before we have started - * all the I/O from calling pagebuf_iodone too early. - */ - atomic_set(&pb->pb_io_remaining, 1); - _pagebuf_ioapply(pb); - _pagebuf_iodone(pb, 0); - - pagebuf_rele(pb); - return 0; -} - -/* - * pagebuf_iowait - * - * pagebuf_iowait waits for I/O to complete on the buffer supplied. - * It returns immediately if no I/O is pending. In any case, it returns - * the error code, if any, or 0 if there is no error. - */ -int -pagebuf_iowait( - xfs_buf_t *pb) -{ - PB_TRACE(pb, "iowait", 0); - if (atomic_read(&pb->pb_io_remaining)) - blk_run_address_space(pb->pb_target->pbr_mapping); - down(&pb->pb_iodonesema); - PB_TRACE(pb, "iowaited", (long)pb->pb_error); - return pb->pb_error; -} - -caddr_t -pagebuf_offset( - xfs_buf_t *pb, - size_t offset) -{ - struct page *page; - - offset += pb->pb_offset; - - page = pb->pb_pages[offset >> PAGE_CACHE_SHIFT]; - return (caddr_t) page_address(page) + (offset & (PAGE_CACHE_SIZE - 1)); -} - -/* - * pagebuf_iomove - * - * Move data into or out of a buffer. - */ -void -pagebuf_iomove( - xfs_buf_t *pb, /* buffer to process */ - size_t boff, /* starting buffer offset */ - size_t bsize, /* length to copy */ - caddr_t data, /* data address */ - page_buf_rw_t mode) /* read/write flag */ -{ - size_t bend, cpoff, csize; - struct page *page; - - bend = boff + bsize; - while (boff < bend) { - page = pb->pb_pages[page_buf_btoct(boff + pb->pb_offset)]; - cpoff = page_buf_poff(boff + pb->pb_offset); - csize = min_t(size_t, - PAGE_CACHE_SIZE-cpoff, pb->pb_count_desired-boff); - - ASSERT(((csize + cpoff) <= PAGE_CACHE_SIZE)); - - switch (mode) { - case PBRW_ZERO: - memset(page_address(page) + cpoff, 0, csize); - break; - case PBRW_READ: - memcpy(data, page_address(page) + cpoff, csize); - break; - case PBRW_WRITE: - memcpy(page_address(page) + cpoff, data, csize); - } - - boff += csize; - data += csize; - } -} - -/* - * Handling of buftargs. - */ - -void -xfs_free_buftarg( - xfs_buftarg_t *btp, - int external) -{ - xfs_flush_buftarg(btp, 1); - if (external) - xfs_blkdev_put(btp->pbr_bdev); - kmem_free(btp, sizeof(*btp)); -} - -void -xfs_incore_relse( - xfs_buftarg_t *btp, - int delwri_only, - int wait) -{ - invalidate_bdev(btp->pbr_bdev, 1); - truncate_inode_pages(btp->pbr_mapping, 0LL); -} - -void -xfs_setsize_buftarg( - xfs_buftarg_t *btp, - unsigned int blocksize, - unsigned int sectorsize) -{ - btp->pbr_bsize = blocksize; - btp->pbr_sshift = ffs(sectorsize) - 1; - btp->pbr_smask = sectorsize - 1; - - if (set_blocksize(btp->pbr_bdev, sectorsize)) { - printk(KERN_WARNING - "XFS: Cannot set_blocksize to %u on device %s\n", - sectorsize, XFS_BUFTARG_NAME(btp)); - } -} - -xfs_buftarg_t * -xfs_alloc_buftarg( - struct block_device *bdev) -{ - xfs_buftarg_t *btp; - - btp = kmem_zalloc(sizeof(*btp), KM_SLEEP); - - btp->pbr_dev = bdev->bd_dev; - btp->pbr_bdev = bdev; - btp->pbr_mapping = bdev->bd_inode->i_mapping; - xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE, bdev_hardsect_size(bdev)); - - return btp; -} - - -/* - * Pagebuf delayed write buffer handling - */ - -STATIC LIST_HEAD(pbd_delwrite_queue); -STATIC spinlock_t pbd_delwrite_lock = SPIN_LOCK_UNLOCKED; - -STATIC void -pagebuf_delwri_queue( - xfs_buf_t *pb, - int unlock) -{ - PB_TRACE(pb, "delwri_q", (long)unlock); - ASSERT(pb->pb_flags & PBF_DELWRI); - - spin_lock(&pbd_delwrite_lock); - /* If already in the queue, dequeue and place at tail */ - if (!list_empty(&pb->pb_list)) { - if (unlock) { - atomic_dec(&pb->pb_hold); - } - list_del(&pb->pb_list); - } - - list_add_tail(&pb->pb_list, &pbd_delwrite_queue); - pb->pb_queuetime = jiffies; - spin_unlock(&pbd_delwrite_lock); - - if (unlock) - pagebuf_unlock(pb); -} - -void -pagebuf_delwri_dequeue( - xfs_buf_t *pb) -{ - PB_TRACE(pb, "delwri_uq", 0); - spin_lock(&pbd_delwrite_lock); - list_del_init(&pb->pb_list); - pb->pb_flags &= ~PBF_DELWRI; - spin_unlock(&pbd_delwrite_lock); -} - -STATIC void -pagebuf_runall_queues( - struct workqueue_struct *queue) -{ - flush_workqueue(queue); -} - -/* Defines for pagebuf daemon */ -STATIC DECLARE_COMPLETION(pagebuf_daemon_done); -STATIC struct task_struct *pagebuf_daemon_task; -STATIC int pagebuf_daemon_active; -STATIC int force_flush; - -STATIC void -pagebuf_daemon_wakeup(void) -{ - force_flush = 1; - barrier(); - wake_up_process(pagebuf_daemon_task); -} - -STATIC int -pagebuf_daemon( - void *data) -{ - struct list_head tmp; - xfs_buf_t *pb, *n; - - /* Set up the thread */ - daemonize("xfsbufd"); - current->flags |= PF_MEMALLOC; - - pagebuf_daemon_task = current; - pagebuf_daemon_active = 1; - barrier(); - - INIT_LIST_HEAD(&tmp); - do { - /* swsusp */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(xfs_flush_interval); - - spin_lock(&pbd_delwrite_lock); - list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) { - PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb)); - ASSERT(pb->pb_flags & PBF_DELWRI); - - if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { - if (!force_flush && - time_before(jiffies, - pb->pb_queuetime + - xfs_age_buffer)) { - pagebuf_unlock(pb); - break; - } - - pb->pb_flags &= ~PBF_DELWRI; - pb->pb_flags |= PBF_WRITE; - list_move(&pb->pb_list, &tmp); - } - } - spin_unlock(&pbd_delwrite_lock); - - while (!list_empty(&tmp)) { - pb = list_entry(tmp.next, xfs_buf_t, pb_list); - list_del_init(&pb->pb_list); - pagebuf_iostrategy(pb); - blk_run_address_space(pb->pb_target->pbr_mapping); - } - - if (as_list_len > 0) - purge_addresses(); - - force_flush = 0; - } while (pagebuf_daemon_active); - - complete_and_exit(&pagebuf_daemon_done, 0); -} - -/* - * Go through all incore buffers, and release buffers if they belong to - * the given device. This is used in filesystem error handling to - * preserve the consistency of its metadata. - */ -int -xfs_flush_buftarg( - xfs_buftarg_t *target, - int wait) -{ - struct list_head tmp; - xfs_buf_t *pb, *n; - int pincount = 0; - - pagebuf_runall_queues(pagebuf_dataio_workqueue); - pagebuf_runall_queues(pagebuf_logio_workqueue); - - INIT_LIST_HEAD(&tmp); - spin_lock(&pbd_delwrite_lock); - list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) { - - if (pb->pb_target != target) - continue; - - ASSERT(pb->pb_flags & PBF_DELWRI); - PB_TRACE(pb, "walkq2", (long)pagebuf_ispin(pb)); - if (pagebuf_ispin(pb)) { - pincount++; - continue; - } - - pb->pb_flags &= ~PBF_DELWRI; - pb->pb_flags |= PBF_WRITE; - list_move(&pb->pb_list, &tmp); - } - spin_unlock(&pbd_delwrite_lock); - - /* - * Dropped the delayed write list lock, now walk the temporary list - */ - list_for_each_entry_safe(pb, n, &tmp, pb_list) { - if (wait) - pb->pb_flags &= ~PBF_ASYNC; - else - list_del_init(&pb->pb_list); - - pagebuf_lock(pb); - pagebuf_iostrategy(pb); - } - - /* - * Remaining list items must be flushed before returning - */ - while (!list_empty(&tmp)) { - pb = list_entry(tmp.next, xfs_buf_t, pb_list); - - list_del_init(&pb->pb_list); - xfs_iowait(pb); - xfs_buf_relse(pb); - } - - if (wait) - blk_run_address_space(target->pbr_mapping); - - return pincount; -} - -STATIC int -pagebuf_daemon_start(void) -{ - int rval; - - pagebuf_logio_workqueue = create_workqueue("xfslogd"); - if (!pagebuf_logio_workqueue) - return -ENOMEM; - - pagebuf_dataio_workqueue = create_workqueue("xfsdatad"); - if (!pagebuf_dataio_workqueue) { - destroy_workqueue(pagebuf_logio_workqueue); - return -ENOMEM; - } - - rval = kernel_thread(pagebuf_daemon, NULL, CLONE_FS|CLONE_FILES); - if (rval < 0) { - destroy_workqueue(pagebuf_logio_workqueue); - destroy_workqueue(pagebuf_dataio_workqueue); - } - - return rval; -} - -/* - * pagebuf_daemon_stop - * - * Note: do not mark as __exit, it is called from pagebuf_terminate. - */ -STATIC void -pagebuf_daemon_stop(void) -{ - pagebuf_daemon_active = 0; - barrier(); - wait_for_completion(&pagebuf_daemon_done); - - destroy_workqueue(pagebuf_logio_workqueue); - destroy_workqueue(pagebuf_dataio_workqueue); -} - -/* - * Initialization and Termination - */ - -int __init -pagebuf_init(void) -{ - int i; - - pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if (pagebuf_cache == NULL) { - printk("pagebuf: couldn't init pagebuf cache\n"); - pagebuf_terminate(); - return -ENOMEM; - } - - for (i = 0; i < NHASH; i++) { - spin_lock_init(&pbhash[i].pb_hash_lock); - INIT_LIST_HEAD(&pbhash[i].pb_hash); - } - -#ifdef PAGEBUF_TRACE - pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP); -#endif - - pagebuf_daemon_start(); - return 0; -} - - -/* - * pagebuf_terminate. - * - * Note: do not mark as __exit, this is also called from the __init code. - */ -void -pagebuf_terminate(void) -{ - pagebuf_daemon_stop(); - -#ifdef PAGEBUF_TRACE - ktrace_free(pagebuf_trace_buf); -#endif - - kmem_cache_destroy(pagebuf_cache); -} diff --git a/fs/xfs/linux/xfs_buf.h b/fs/xfs/linux/xfs_buf.h deleted file mode 100644 index f97e6c0cd..000000000 --- a/fs/xfs/linux/xfs_buf.h +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -/* - * Written by Steve Lord, Jim Mostek, Russell Cattelan at SGI - */ - -#ifndef __XFS_BUF_H__ -#define __XFS_BUF_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Base types - */ - -#define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL)) - -#define page_buf_ctob(pp) ((pp) * PAGE_CACHE_SIZE) -#define page_buf_btoc(dd) (((dd) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -#define page_buf_btoct(dd) ((dd) >> PAGE_CACHE_SHIFT) -#define page_buf_poff(aa) ((aa) & ~PAGE_CACHE_MASK) - -typedef enum page_buf_rw_e { - PBRW_READ = 1, /* transfer into target memory */ - PBRW_WRITE = 2, /* transfer from target memory */ - PBRW_ZERO = 3 /* Zero target memory */ -} page_buf_rw_t; - - -typedef enum page_buf_flags_e { /* pb_flags values */ - PBF_READ = (1 << 0), /* buffer intended for reading from device */ - PBF_WRITE = (1 << 1), /* buffer intended for writing to device */ - PBF_MAPPED = (1 << 2), /* buffer mapped (pb_addr valid) */ - PBF_PARTIAL = (1 << 3), /* buffer partially read */ - PBF_ASYNC = (1 << 4), /* initiator will not wait for completion */ - PBF_NONE = (1 << 5), /* buffer not read at all */ - PBF_DELWRI = (1 << 6), /* buffer has dirty pages */ - PBF_STALE = (1 << 7), /* buffer has been staled, do not find it */ - PBF_FS_MANAGED = (1 << 8), /* filesystem controls freeing memory */ - PBF_FS_DATAIOD = (1 << 9), /* schedule IO completion on fs datad */ - PBF_FORCEIO = (1 << 10), /* ignore any cache state */ - PBF_FLUSH = (1 << 11), /* flush disk write cache */ - PBF_READ_AHEAD = (1 << 12), /* asynchronous read-ahead */ - - /* flags used only as arguments to access routines */ - PBF_LOCK = (1 << 14), /* lock requested */ - PBF_TRYLOCK = (1 << 15), /* lock requested, but do not wait */ - PBF_DONT_BLOCK = (1 << 16), /* do not block in current thread */ - - /* flags used only internally */ - _PBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */ - _PBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc() */ - _PBF_RUN_QUEUES = (1 << 19),/* run block device task queue */ -} page_buf_flags_t; - -#define PBF_UPDATE (PBF_READ | PBF_WRITE) -#define PBF_NOT_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) != 0) -#define PBF_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) == 0) - -typedef struct xfs_buftarg { - dev_t pbr_dev; - struct block_device *pbr_bdev; - struct address_space *pbr_mapping; - unsigned int pbr_bsize; - unsigned int pbr_sshift; - size_t pbr_smask; -} xfs_buftarg_t; - -/* - * xfs_buf_t: Buffer structure for page cache-based buffers - * - * This buffer structure is used by the page cache buffer management routines - * to refer to an assembly of pages forming a logical buffer. The actual - * I/O is performed with buffer_head or bio structures, as required by drivers, - * for drivers which do not understand this structure. The buffer structure is - * used on temporary basis only, and discarded when released. - * - * The real data storage is recorded in the page cache. Metadata is - * hashed to the inode for the block device on which the file system resides. - * File data is hashed to the inode for the file. Pages which are only - * partially filled with data have bits set in their block_map entry - * to indicate which disk blocks in the page are not valid. - */ - -struct xfs_buf; -typedef void (*page_buf_iodone_t)(struct xfs_buf *); - /* call-back function on I/O completion */ -typedef void (*page_buf_relse_t)(struct xfs_buf *); - /* call-back function on I/O completion */ -typedef int (*page_buf_bdstrat_t)(struct xfs_buf *); - -#define PB_PAGES 4 - -typedef struct xfs_buf { - struct semaphore pb_sema; /* semaphore for lockables */ - unsigned long pb_queuetime; /* time buffer was queued */ - atomic_t pb_pin_count; /* pin count */ - wait_queue_head_t pb_waiters; /* unpin waiters */ - struct list_head pb_list; - page_buf_flags_t pb_flags; /* status flags */ - struct list_head pb_hash_list; - xfs_buftarg_t *pb_target; /* logical object */ - atomic_t pb_hold; /* reference count */ - xfs_daddr_t pb_bn; /* block number for I/O */ - loff_t pb_file_offset; /* offset in file */ - size_t pb_buffer_length; /* size of buffer in bytes */ - size_t pb_count_desired; /* desired transfer size */ - void *pb_addr; /* virtual address of buffer */ - struct work_struct pb_iodone_work; - atomic_t pb_io_remaining;/* #outstanding I/O requests */ - page_buf_iodone_t pb_iodone; /* I/O completion function */ - page_buf_relse_t pb_relse; /* releasing function */ - page_buf_bdstrat_t pb_strat; /* pre-write function */ - struct semaphore pb_iodonesema; /* Semaphore for I/O waiters */ - void *pb_fspriv; - void *pb_fspriv2; - void *pb_fspriv3; - unsigned short pb_error; /* error code on I/O */ - unsigned short pb_page_count; /* size of page array */ - unsigned short pb_offset; /* page offset in first page */ - unsigned char pb_locked; /* page array is locked */ - unsigned char pb_hash_index; /* hash table index */ - struct page **pb_pages; /* array of page pointers */ - struct page *pb_page_array[PB_PAGES]; /* inline pages */ -#ifdef PAGEBUF_LOCK_TRACKING - int pb_last_holder; -#endif -} xfs_buf_t; - - -/* Finding and Reading Buffers */ - -extern xfs_buf_t *pagebuf_find( /* find buffer for block if */ - /* the block is in memory */ - xfs_buftarg_t *, /* inode for block */ - loff_t, /* starting offset of range */ - size_t, /* length of range */ - page_buf_flags_t); /* PBF_LOCK */ - -extern xfs_buf_t *pagebuf_get( /* allocate a buffer */ - xfs_buftarg_t *, /* inode for buffer */ - loff_t, /* starting offset of range */ - size_t, /* length of range */ - page_buf_flags_t); /* PBF_LOCK, PBF_READ, */ - /* PBF_ASYNC */ - -extern xfs_buf_t *pagebuf_lookup( - xfs_buftarg_t *, - loff_t, /* starting offset of range */ - size_t, /* length of range */ - page_buf_flags_t); /* PBF_READ, PBF_WRITE, */ - /* PBF_FORCEIO, */ - -extern xfs_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with */ - /* no memory or disk address */ - size_t len, - xfs_buftarg_t *); /* mount point "fake" inode */ - -extern xfs_buf_t *pagebuf_get_no_daddr(/* allocate pagebuf struct */ - /* without disk address */ - size_t len, - xfs_buftarg_t *); /* mount point "fake" inode */ - -extern int pagebuf_associate_memory( - xfs_buf_t *, - void *, - size_t); - -extern void pagebuf_hold( /* increment reference count */ - xfs_buf_t *); /* buffer to hold */ - -extern void pagebuf_readahead( /* read ahead into cache */ - xfs_buftarg_t *, /* target for buffer (or NULL) */ - loff_t, /* starting offset of range */ - size_t, /* length of range */ - page_buf_flags_t); /* additional read flags */ - -/* Releasing Buffers */ - -extern void pagebuf_free( /* deallocate a buffer */ - xfs_buf_t *); /* buffer to deallocate */ - -extern void pagebuf_rele( /* release hold on a buffer */ - xfs_buf_t *); /* buffer to release */ - -/* Locking and Unlocking Buffers */ - -extern int pagebuf_cond_lock( /* lock buffer, if not locked */ - /* (returns -EBUSY if locked) */ - xfs_buf_t *); /* buffer to lock */ - -extern int pagebuf_lock_value( /* return count on lock */ - xfs_buf_t *); /* buffer to check */ - -extern int pagebuf_lock( /* lock buffer */ - xfs_buf_t *); /* buffer to lock */ - -extern void pagebuf_unlock( /* unlock buffer */ - xfs_buf_t *); /* buffer to unlock */ - -/* Buffer Read and Write Routines */ - -extern void pagebuf_iodone( /* mark buffer I/O complete */ - xfs_buf_t *, /* buffer to mark */ - int, /* use data/log helper thread. */ - int); /* run completion locally, or in - * a helper thread. */ - -extern void pagebuf_ioerror( /* mark buffer in error (or not) */ - xfs_buf_t *, /* buffer to mark */ - int); /* error to store (0 if none) */ - -extern int pagebuf_iostart( /* start I/O on a buffer */ - xfs_buf_t *, /* buffer to start */ - page_buf_flags_t); /* PBF_LOCK, PBF_ASYNC, */ - /* PBF_READ, PBF_WRITE, */ - /* PBF_DELWRI */ - -extern int pagebuf_iorequest( /* start real I/O */ - xfs_buf_t *); /* buffer to convey to device */ - -extern int pagebuf_iowait( /* wait for buffer I/O done */ - xfs_buf_t *); /* buffer to wait on */ - -extern void pagebuf_iomove( /* move data in/out of pagebuf */ - xfs_buf_t *, /* buffer to manipulate */ - size_t, /* starting buffer offset */ - size_t, /* length in buffer */ - caddr_t, /* data pointer */ - page_buf_rw_t); /* direction */ - -static inline int pagebuf_iostrategy(xfs_buf_t *pb) -{ - return pb->pb_strat ? pb->pb_strat(pb) : pagebuf_iorequest(pb); -} - -static inline int pagebuf_geterror(xfs_buf_t *pb) -{ - return pb ? pb->pb_error : ENOMEM; -} - -/* Buffer Utility Routines */ - -extern caddr_t pagebuf_offset( /* pointer at offset in buffer */ - xfs_buf_t *, /* buffer to offset into */ - size_t); /* offset */ - -/* Pinning Buffer Storage in Memory */ - -extern void pagebuf_pin( /* pin buffer in memory */ - xfs_buf_t *); /* buffer to pin */ - -extern void pagebuf_unpin( /* unpin buffered data */ - xfs_buf_t *); /* buffer to unpin */ - -extern int pagebuf_ispin( /* check if buffer is pinned */ - xfs_buf_t *); /* buffer to check */ - -/* Delayed Write Buffer Routines */ - -extern void pagebuf_delwri_dequeue(xfs_buf_t *); - -/* Buffer Daemon Setup Routines */ - -extern int pagebuf_init(void); -extern void pagebuf_terminate(void); - - -#ifdef PAGEBUF_TRACE -extern ktrace_t *pagebuf_trace_buf; -extern void pagebuf_trace( - xfs_buf_t *, /* buffer being traced */ - char *, /* description of operation */ - void *, /* arbitrary diagnostic value */ - void *); /* return address */ -#else -# define pagebuf_trace(pb, id, ptr, ra) do { } while (0) -#endif - -#define pagebuf_target_name(target) \ - ({ char __b[BDEVNAME_SIZE]; bdevname((target)->pbr_bdev, __b); __b; }) - - - - - -/* These are just for xfs_syncsub... it sets an internal variable - * then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t - */ -#define XFS_B_ASYNC PBF_ASYNC -#define XFS_B_DELWRI PBF_DELWRI -#define XFS_B_READ PBF_READ -#define XFS_B_WRITE PBF_WRITE -#define XFS_B_STALE PBF_STALE - -#define XFS_BUF_TRYLOCK PBF_TRYLOCK -#define XFS_INCORE_TRYLOCK PBF_TRYLOCK -#define XFS_BUF_LOCK PBF_LOCK -#define XFS_BUF_MAPPED PBF_MAPPED - -#define BUF_BUSY PBF_DONT_BLOCK - -#define XFS_BUF_BFLAGS(x) ((x)->pb_flags) -#define XFS_BUF_ZEROFLAGS(x) \ - ((x)->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_DELWRI)) - -#define XFS_BUF_STALE(x) ((x)->pb_flags |= XFS_B_STALE) -#define XFS_BUF_UNSTALE(x) ((x)->pb_flags &= ~XFS_B_STALE) -#define XFS_BUF_ISSTALE(x) ((x)->pb_flags & XFS_B_STALE) -#define XFS_BUF_SUPER_STALE(x) do { \ - XFS_BUF_STALE(x); \ - xfs_buf_undelay(x); \ - XFS_BUF_DONE(x); \ - } while (0) - -#define XFS_BUF_MANAGE PBF_FS_MANAGED -#define XFS_BUF_UNMANAGE(x) ((x)->pb_flags &= ~PBF_FS_MANAGED) - -static inline void xfs_buf_undelay(xfs_buf_t *pb) -{ - if (pb->pb_flags & PBF_DELWRI) { - if (pb->pb_list.next != &pb->pb_list) { - pagebuf_delwri_dequeue(pb); - pagebuf_rele(pb); - } else { - pb->pb_flags &= ~PBF_DELWRI; - } - } -} - -#define XFS_BUF_DELAYWRITE(x) ((x)->pb_flags |= PBF_DELWRI) -#define XFS_BUF_UNDELAYWRITE(x) xfs_buf_undelay(x) -#define XFS_BUF_ISDELAYWRITE(x) ((x)->pb_flags & PBF_DELWRI) - -#define XFS_BUF_ERROR(x,no) pagebuf_ioerror(x,no) -#define XFS_BUF_GETERROR(x) pagebuf_geterror(x) -#define XFS_BUF_ISERROR(x) (pagebuf_geterror(x)?1:0) - -#define XFS_BUF_DONE(x) ((x)->pb_flags &= ~(PBF_PARTIAL|PBF_NONE)) -#define XFS_BUF_UNDONE(x) ((x)->pb_flags |= PBF_PARTIAL|PBF_NONE) -#define XFS_BUF_ISDONE(x) (!(PBF_NOT_DONE(x))) - -#define XFS_BUF_BUSY(x) ((x)->pb_flags |= PBF_FORCEIO) -#define XFS_BUF_UNBUSY(x) ((x)->pb_flags &= ~PBF_FORCEIO) -#define XFS_BUF_ISBUSY(x) (1) - -#define XFS_BUF_ASYNC(x) ((x)->pb_flags |= PBF_ASYNC) -#define XFS_BUF_UNASYNC(x) ((x)->pb_flags &= ~PBF_ASYNC) -#define XFS_BUF_ISASYNC(x) ((x)->pb_flags & PBF_ASYNC) - -#define XFS_BUF_FLUSH(x) ((x)->pb_flags |= PBF_FLUSH) -#define XFS_BUF_UNFLUSH(x) ((x)->pb_flags &= ~PBF_FLUSH) -#define XFS_BUF_ISFLUSH(x) ((x)->pb_flags & PBF_FLUSH) - -#define XFS_BUF_SHUT(x) printk("XFS_BUF_SHUT not implemented yet\n") -#define XFS_BUF_UNSHUT(x) printk("XFS_BUF_UNSHUT not implemented yet\n") -#define XFS_BUF_ISSHUT(x) (0) - -#define XFS_BUF_HOLD(x) pagebuf_hold(x) -#define XFS_BUF_READ(x) ((x)->pb_flags |= PBF_READ) -#define XFS_BUF_UNREAD(x) ((x)->pb_flags &= ~PBF_READ) -#define XFS_BUF_ISREAD(x) ((x)->pb_flags & PBF_READ) - -#define XFS_BUF_WRITE(x) ((x)->pb_flags |= PBF_WRITE) -#define XFS_BUF_UNWRITE(x) ((x)->pb_flags &= ~PBF_WRITE) -#define XFS_BUF_ISWRITE(x) ((x)->pb_flags & PBF_WRITE) - -#define XFS_BUF_ISUNINITIAL(x) (0) -#define XFS_BUF_UNUNINITIAL(x) (0) - -#define XFS_BUF_BP_ISMAPPED(bp) 1 - -#define XFS_BUF_DATAIO(x) ((x)->pb_flags |= PBF_FS_DATAIOD) -#define XFS_BUF_UNDATAIO(x) ((x)->pb_flags &= ~PBF_FS_DATAIOD) - -#define XFS_BUF_IODONE_FUNC(buf) (buf)->pb_iodone -#define XFS_BUF_SET_IODONE_FUNC(buf, func) \ - (buf)->pb_iodone = (func) -#define XFS_BUF_CLR_IODONE_FUNC(buf) \ - (buf)->pb_iodone = NULL -#define XFS_BUF_SET_BDSTRAT_FUNC(buf, func) \ - (buf)->pb_strat = (func) -#define XFS_BUF_CLR_BDSTRAT_FUNC(buf) \ - (buf)->pb_strat = NULL - -#define XFS_BUF_FSPRIVATE(buf, type) \ - ((type)(buf)->pb_fspriv) -#define XFS_BUF_SET_FSPRIVATE(buf, value) \ - (buf)->pb_fspriv = (void *)(value) -#define XFS_BUF_FSPRIVATE2(buf, type) \ - ((type)(buf)->pb_fspriv2) -#define XFS_BUF_SET_FSPRIVATE2(buf, value) \ - (buf)->pb_fspriv2 = (void *)(value) -#define XFS_BUF_FSPRIVATE3(buf, type) \ - ((type)(buf)->pb_fspriv3) -#define XFS_BUF_SET_FSPRIVATE3(buf, value) \ - (buf)->pb_fspriv3 = (void *)(value) -#define XFS_BUF_SET_START(buf) - -#define XFS_BUF_SET_BRELSE_FUNC(buf, value) \ - (buf)->pb_relse = (value) - -#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->pb_addr) - -extern inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset) -{ - if (bp->pb_flags & PBF_MAPPED) - return XFS_BUF_PTR(bp) + offset; - return (xfs_caddr_t) pagebuf_offset(bp, offset); -} - -#define XFS_BUF_SET_PTR(bp, val, count) \ - pagebuf_associate_memory(bp, val, count) -#define XFS_BUF_ADDR(bp) ((bp)->pb_bn) -#define XFS_BUF_SET_ADDR(bp, blk) \ - ((bp)->pb_bn = (blk)) -#define XFS_BUF_OFFSET(bp) ((bp)->pb_file_offset) -#define XFS_BUF_SET_OFFSET(bp, off) \ - ((bp)->pb_file_offset = (off)) -#define XFS_BUF_COUNT(bp) ((bp)->pb_count_desired) -#define XFS_BUF_SET_COUNT(bp, cnt) \ - ((bp)->pb_count_desired = (cnt)) -#define XFS_BUF_SIZE(bp) ((bp)->pb_buffer_length) -#define XFS_BUF_SET_SIZE(bp, cnt) \ - ((bp)->pb_buffer_length = (cnt)) -#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) -#define XFS_BUF_SET_VTYPE(bp, type) -#define XFS_BUF_SET_REF(bp, ref) - -#define XFS_BUF_ISPINNED(bp) pagebuf_ispin(bp) - -#define XFS_BUF_VALUSEMA(bp) pagebuf_lock_value(bp) -#define XFS_BUF_CPSEMA(bp) (pagebuf_cond_lock(bp) == 0) -#define XFS_BUF_VSEMA(bp) pagebuf_unlock(bp) -#define XFS_BUF_PSEMA(bp,x) pagebuf_lock(bp) -#define XFS_BUF_V_IODONESEMA(bp) up(&bp->pb_iodonesema); - -/* setup the buffer target from a buftarg structure */ -#define XFS_BUF_SET_TARGET(bp, target) \ - (bp)->pb_target = (target) -#define XFS_BUF_TARGET(bp) ((bp)->pb_target) -#define XFS_BUFTARG_NAME(target) \ - pagebuf_target_name(target) - -#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) -#define XFS_BUF_SET_VTYPE(bp, type) -#define XFS_BUF_SET_REF(bp, ref) - -#define xfs_buf_read(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), \ - PBF_LOCK | PBF_READ | PBF_MAPPED) -#define xfs_buf_get(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), \ - PBF_LOCK | PBF_MAPPED) - -#define xfs_buf_read_flags(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), PBF_READ | (flags)) -#define xfs_buf_get_flags(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), (flags)) - -static inline int xfs_bawrite(void *mp, xfs_buf_t *bp) -{ - bp->pb_fspriv3 = mp; - bp->pb_strat = xfs_bdstrat_cb; - xfs_buf_undelay(bp); - return pagebuf_iostart(bp, PBF_WRITE | PBF_ASYNC | _PBF_RUN_QUEUES); -} - -static inline void xfs_buf_relse(xfs_buf_t *bp) -{ - if (!bp->pb_relse) - pagebuf_unlock(bp); - pagebuf_rele(bp); -} - -#define xfs_bpin(bp) pagebuf_pin(bp) -#define xfs_bunpin(bp) pagebuf_unpin(bp) - -#define xfs_buftrace(id, bp) \ - pagebuf_trace(bp, id, NULL, (void *)__builtin_return_address(0)) - -#define xfs_biodone(pb) \ - pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 0) - -#define xfs_incore(buftarg,blkno,len,lockit) \ - pagebuf_find(buftarg, blkno ,len, lockit) - - -#define xfs_biomove(pb, off, len, data, rw) \ - pagebuf_iomove((pb), (off), (len), (data), \ - ((rw) == XFS_B_WRITE) ? PBRW_WRITE : PBRW_READ) - -#define xfs_biozero(pb, off, len) \ - pagebuf_iomove((pb), (off), (len), NULL, PBRW_ZERO) - - -static inline int XFS_bwrite(xfs_buf_t *pb) -{ - int iowait = (pb->pb_flags & PBF_ASYNC) == 0; - int error = 0; - - if (!iowait) - pb->pb_flags |= _PBF_RUN_QUEUES; - - xfs_buf_undelay(pb); - pagebuf_iostrategy(pb); - if (iowait) { - error = pagebuf_iowait(pb); - xfs_buf_relse(pb); - } - return error; -} - -#define XFS_bdwrite(pb) \ - pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC) - -static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp) -{ - bp->pb_strat = xfs_bdstrat_cb; - bp->pb_fspriv3 = mp; - - return pagebuf_iostart(bp, PBF_DELWRI | PBF_ASYNC); -} - -#define XFS_bdstrat(bp) pagebuf_iorequest(bp) - -#define xfs_iowait(pb) pagebuf_iowait(pb) - -#define xfs_baread(target, rablkno, ralen) \ - pagebuf_readahead((target), (rablkno), (ralen), PBF_DONT_BLOCK) - -#define xfs_buf_get_empty(len, target) pagebuf_get_empty((len), (target)) -#define xfs_buf_get_noaddr(len, target) pagebuf_get_no_daddr((len), (target)) -#define xfs_buf_free(bp) pagebuf_free(bp) - - -/* - * Handling of buftargs. - */ - -extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *); -extern void xfs_free_buftarg(xfs_buftarg_t *, int); -extern void xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); -extern void xfs_incore_relse(xfs_buftarg_t *, int, int); -extern int xfs_flush_buftarg(xfs_buftarg_t *, int); - -#define xfs_getsize_buftarg(buftarg) \ - block_size((buftarg)->pbr_bdev) -#define xfs_readonly_buftarg(buftarg) \ - bdev_read_only((buftarg)->pbr_bdev) -#define xfs_binval(buftarg) \ - xfs_flush_buftarg(buftarg, 1) -#define XFS_bflush(buftarg) \ - xfs_flush_buftarg(buftarg, 1) - -#endif /* __XFS_BUF_H__ */ diff --git a/fs/xfs/linux/xfs_cred.h b/fs/xfs/linux/xfs_cred.h deleted file mode 100644 index 00c45849d..000000000 --- a/fs/xfs/linux/xfs_cred.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_CRED_H__ -#define __XFS_CRED_H__ - -/* - * Credentials - */ -typedef struct cred { - /* EMPTY */ -} cred_t; - -extern struct cred *sys_cred; - -/* this is a hack.. (assums sys_cred is the only cred_t in the system) */ -static __inline int capable_cred(cred_t *cr, int cid) -{ - return (cr == sys_cred) ? 1 : capable(cid); -} - -#endif /* __XFS_CRED_H__ */ diff --git a/fs/xfs/linux/xfs_file.c b/fs/xfs/linux/xfs_file.c deleted file mode 100644 index 8d9f3b55f..000000000 --- a/fs/xfs/linux/xfs_file.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_sb.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_trans.h" -#include "xfs_dmapi.h" -#include "xfs_mount.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_btree.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_error.h" -#include "xfs_rw.h" - -#include - -static struct vm_operations_struct linvfs_file_vm_ops; - - -STATIC inline ssize_t -__linvfs_read( - struct kiocb *iocb, - char __user *buf, - int ioflags, - size_t count, - loff_t pos) -{ - struct iovec iov = {buf, count}; - struct file *file = iocb->ki_filp; - vnode_t *vp = LINVFS_GET_VP(file->f_dentry->d_inode); - ssize_t rval; - - BUG_ON(iocb->ki_pos != pos); - - if (unlikely(file->f_flags & O_DIRECT)) - ioflags |= IO_ISDIRECT; - VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval); - return rval; -} - - -STATIC ssize_t -linvfs_read( - struct kiocb *iocb, - char __user *buf, - size_t count, - loff_t pos) -{ - return __linvfs_read(iocb, buf, 0, count, pos); -} - -STATIC ssize_t -linvfs_read_invis( - struct kiocb *iocb, - char __user *buf, - size_t count, - loff_t pos) -{ - return __linvfs_read(iocb, buf, IO_INVIS, count, pos); -} - - -STATIC inline ssize_t -__linvfs_write( - struct kiocb *iocb, - const char *buf, - int ioflags, - size_t count, - loff_t pos) -{ - struct iovec iov = {(void *)buf, count}; - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - vnode_t *vp = LINVFS_GET_VP(inode); - ssize_t rval; - - BUG_ON(iocb->ki_pos != pos); - if (unlikely(file->f_flags & O_DIRECT)) { - ioflags |= IO_ISDIRECT; - VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, - ioflags, NULL, rval); - } else { - down(&inode->i_sem); - VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, - ioflags, NULL, rval); - up(&inode->i_sem); - } - - return rval; -} - - -STATIC ssize_t -linvfs_write( - struct kiocb *iocb, - const char __user *buf, - size_t count, - loff_t pos) -{ - return __linvfs_write(iocb, buf, 0, count, pos); -} - -STATIC ssize_t -linvfs_write_invis( - struct kiocb *iocb, - const char __user *buf, - size_t count, - loff_t pos) -{ - return __linvfs_write(iocb, buf, IO_INVIS, count, pos); -} - - -STATIC inline ssize_t -__linvfs_readv( - struct file *file, - const struct iovec *iov, - int ioflags, - unsigned long nr_segs, - loff_t *ppos) -{ - struct inode *inode = file->f_mapping->host; - vnode_t *vp = LINVFS_GET_VP(inode); - struct kiocb kiocb; - ssize_t rval; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - - if (unlikely(file->f_flags & O_DIRECT)) - ioflags |= IO_ISDIRECT; - VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval); - if (rval == -EIOCBQUEUED) - rval = wait_on_sync_kiocb(&kiocb); - - *ppos = kiocb.ki_pos; - return rval; -} - -STATIC ssize_t -linvfs_readv( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __linvfs_readv(file, iov, 0, nr_segs, ppos); -} - -STATIC ssize_t -linvfs_readv_invis( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __linvfs_readv(file, iov, IO_INVIS, nr_segs, ppos); -} - - -STATIC inline ssize_t -__linvfs_writev( - struct file *file, - const struct iovec *iov, - int ioflags, - unsigned long nr_segs, - loff_t *ppos) -{ - struct inode *inode = file->f_mapping->host; - vnode_t *vp = LINVFS_GET_VP(inode); - struct kiocb kiocb; - ssize_t rval; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - if (unlikely(file->f_flags & O_DIRECT)) { - ioflags |= IO_ISDIRECT; - VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, - ioflags, NULL, rval); - } else { - down(&inode->i_sem); - VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, - ioflags, NULL, rval); - up(&inode->i_sem); - } - - if (rval == -EIOCBQUEUED) - rval = wait_on_sync_kiocb(&kiocb); - - *ppos = kiocb.ki_pos; - return rval; -} - - -STATIC ssize_t -linvfs_writev( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __linvfs_writev(file, iov, 0, nr_segs, ppos); -} - -STATIC ssize_t -linvfs_writev_invis( - struct file *file, - const struct iovec *iov, - unsigned long nr_segs, - loff_t *ppos) -{ - return __linvfs_writev(file, iov, IO_INVIS, nr_segs, ppos); -} - -STATIC ssize_t -linvfs_sendfile( - struct file *filp, - loff_t *ppos, - size_t count, - read_actor_t actor, - void *target) -{ - vnode_t *vp = LINVFS_GET_VP(filp->f_dentry->d_inode); - int error; - - VOP_SENDFILE(vp, filp, ppos, 0, count, actor, target, NULL, error); - return error; -} - - -STATIC int -linvfs_open( - struct inode *inode, - struct file *filp) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - int error; - - if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EFBIG; - - ASSERT(vp); - VOP_OPEN(vp, NULL, error); - return -error; -} - - -STATIC int -linvfs_release( - struct inode *inode, - struct file *filp) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - int error = 0; - - if (vp) - VOP_RELEASE(vp, error); - return -error; -} - - -STATIC int -linvfs_fsync( - struct file *filp, - struct dentry *dentry, - int datasync) -{ - struct inode *inode = dentry->d_inode; - vnode_t *vp = LINVFS_GET_VP(inode); - int error; - int flags = FSYNC_WAIT; - - if (datasync) - flags |= FSYNC_DATA; - - ASSERT(vp); - VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error); - return -error; -} - -/* - * linvfs_readdir maps to VOP_READDIR(). - * We need to build a uio, cred, ... - */ - -#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen)) - -STATIC int -linvfs_readdir( - struct file *filp, - void *dirent, - filldir_t filldir) -{ - int error = 0; - vnode_t *vp; - uio_t uio; - iovec_t iov; - int eof = 0; - caddr_t read_buf; - int namelen, size = 0; - size_t rlen = PAGE_CACHE_SIZE; - xfs_off_t start_offset, curr_offset; - xfs_dirent_t *dbp = NULL; - - vp = LINVFS_GET_VP(filp->f_dentry->d_inode); - ASSERT(vp); - - /* Try fairly hard to get memory */ - do { - if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL))) - break; - rlen >>= 1; - } while (rlen >= 1024); - - if (read_buf == NULL) - return -ENOMEM; - - uio.uio_iov = &iov; - uio.uio_segflg = UIO_SYSSPACE; - curr_offset = filp->f_pos; - if (filp->f_pos != 0x7fffffff) - uio.uio_offset = filp->f_pos; - else - uio.uio_offset = 0xffffffff; - - while (!eof) { - uio.uio_resid = iov.iov_len = rlen; - iov.iov_base = read_buf; - uio.uio_iovcnt = 1; - - start_offset = uio.uio_offset; - - VOP_READDIR(vp, &uio, NULL, &eof, error); - if ((uio.uio_offset == start_offset) || error) { - size = 0; - break; - } - - size = rlen - uio.uio_resid; - dbp = (xfs_dirent_t *)read_buf; - while (size > 0) { - namelen = strlen(dbp->d_name); - - if (filldir(dirent, dbp->d_name, namelen, - (loff_t) curr_offset & 0x7fffffff, - (ino_t) dbp->d_ino, - DT_UNKNOWN)) { - goto done; - } - size -= dbp->d_reclen; - curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */; - dbp = nextdp(dbp); - } - } -done: - if (!error) { - if (size == 0) - filp->f_pos = uio.uio_offset & 0x7fffffff; - else if (dbp) - filp->f_pos = curr_offset; - } - - kfree(read_buf); - return -error; -} - - -STATIC int -linvfs_file_mmap( - struct file *filp, - struct vm_area_struct *vma) -{ - struct inode *ip = filp->f_dentry->d_inode; - vnode_t *vp = LINVFS_GET_VP(ip); - vattr_t va = { .va_mask = XFS_AT_UPDATIME }; - int error; - - if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) { - xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); - - error = -XFS_SEND_MMAP(mp, vma, 0); - if (error) - return error; - } - - vma->vm_ops = &linvfs_file_vm_ops; - - VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); - return 0; -} - - -STATIC int -linvfs_ioctl( - struct inode *inode, - struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - int error; - vnode_t *vp = LINVFS_GET_VP(inode); - - ASSERT(vp); - VOP_IOCTL(vp, inode, filp, 0, cmd, arg, error); - VMODIFY(vp); - - /* NOTE: some of the ioctl's return positive #'s as a - * byte count indicating success, such as - * readlink_by_handle. So we don't "sign flip" - * like most other routines. This means true - * errors need to be returned as a negative value. - */ - return error; -} - -STATIC int -linvfs_ioctl_invis( - struct inode *inode, - struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - int error; - vnode_t *vp = LINVFS_GET_VP(inode); - - ASSERT(vp); - VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, arg, error); - VMODIFY(vp); - - /* NOTE: some of the ioctl's return positive #'s as a - * byte count indicating success, such as - * readlink_by_handle. So we don't "sign flip" - * like most other routines. This means true - * errors need to be returned as a negative value. - */ - return error; -} - -#ifdef HAVE_VMOP_MPROTECT -STATIC int -linvfs_mprotect( - struct vm_area_struct *vma, - unsigned int newflags) -{ - vnode_t *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode); - int error = 0; - - if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) { - if ((vma->vm_flags & VM_MAYSHARE) && - (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) { - xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); - - error = XFS_SEND_MMAP(mp, vma, VM_WRITE); - } - } - return error; -} -#endif /* HAVE_VMOP_MPROTECT */ - - -struct file_operations linvfs_file_operations = { - .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .readv = linvfs_readv, - .writev = linvfs_writev, - .aio_read = linvfs_read, - .aio_write = linvfs_write, - .sendfile = linvfs_sendfile, - .ioctl = linvfs_ioctl, - .mmap = linvfs_file_mmap, - .open = linvfs_open, - .release = linvfs_release, - .fsync = linvfs_fsync, -}; - -struct file_operations linvfs_invis_file_operations = { - .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .readv = linvfs_readv_invis, - .writev = linvfs_writev_invis, - .aio_read = linvfs_read_invis, - .aio_write = linvfs_write_invis, - .sendfile = linvfs_sendfile, - .ioctl = linvfs_ioctl_invis, - .mmap = linvfs_file_mmap, - .open = linvfs_open, - .release = linvfs_release, - .fsync = linvfs_fsync, -}; - - -struct file_operations linvfs_dir_operations = { - .read = generic_read_dir, - .readdir = linvfs_readdir, - .ioctl = linvfs_ioctl, - .fsync = linvfs_fsync, -}; - -static struct vm_operations_struct linvfs_file_vm_ops = { - .nopage = filemap_nopage, -#ifdef HAVE_VMOP_MPROTECT - .mprotect = linvfs_mprotect, -#endif -}; diff --git a/fs/xfs/linux/xfs_fs_subr.c b/fs/xfs/linux/xfs_fs_subr.c deleted file mode 100644 index afad97018..000000000 --- a/fs/xfs/linux/xfs_fs_subr.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" - -/* - * Stub for no-op vnode operations that return error status. - */ -int -fs_noerr() -{ - return 0; -} - -/* - * Operation unsupported under this file system. - */ -int -fs_nosys() -{ - return ENOSYS; -} - -/* - * Stub for inactive, strategy, and read/write lock/unlock. Does nothing. - */ -/* ARGSUSED */ -void -fs_noval() -{ -} - -/* - * vnode pcache layer for vnode_tosspages. - * 'last' parameter unused but left in for IRIX compatibility - */ -void -fs_tosspages( - bhv_desc_t *bdp, - xfs_off_t first, - xfs_off_t last, - int fiopt) -{ - vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = LINVFS_GET_IP(vp); - - if (VN_CACHED(vp)) - truncate_inode_pages(ip->i_mapping, first); -} - - -/* - * vnode pcache layer for vnode_flushinval_pages. - * 'last' parameter unused but left in for IRIX compatibility - */ -void -fs_flushinval_pages( - bhv_desc_t *bdp, - xfs_off_t first, - xfs_off_t last, - int fiopt) -{ - vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = LINVFS_GET_IP(vp); - - if (VN_CACHED(vp)) { - filemap_fdatawrite(ip->i_mapping); - filemap_fdatawait(ip->i_mapping); - - truncate_inode_pages(ip->i_mapping, first); - } -} - -/* - * vnode pcache layer for vnode_flush_pages. - * 'last' parameter unused but left in for IRIX compatibility - */ -int -fs_flush_pages( - bhv_desc_t *bdp, - xfs_off_t first, - xfs_off_t last, - uint64_t flags, - int fiopt) -{ - vnode_t *vp = BHV_TO_VNODE(bdp); - struct inode *ip = LINVFS_GET_IP(vp); - - if (VN_CACHED(vp)) { - filemap_fdatawrite(ip->i_mapping); - filemap_fdatawait(ip->i_mapping); - } - - return 0; -} diff --git a/fs/xfs/linux/xfs_fs_subr.h b/fs/xfs/linux/xfs_fs_subr.h deleted file mode 100644 index 198b8dd78..000000000 --- a/fs/xfs/linux/xfs_fs_subr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUBR_H__ -#define __XFS_SUBR_H__ - -/* - * Utilities shared among file system implementations. - */ - -struct cred; - -extern int fs_noerr(void); -extern int fs_nosys(void); -extern int fs_nodev(void); -extern void fs_noval(void); -extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); - -#endif /* __XFS_FS_SUBR_H__ */ diff --git a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c deleted file mode 100644 index 1144a8b9f..000000000 --- a/fs/xfs/linux/xfs_globals.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -/* - * This file contains globals needed by XFS that were normally defined - * somewhere else in IRIX. - */ - -#include "xfs.h" -#include "xfs_cred.h" -#include "xfs_sysctl.h" - -/* - * System memory size - used to scale certain data structures in XFS. - */ -unsigned long xfs_physmem; - -/* - * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n, - * other XFS code uses these values. - */ - -xfs_param_t xfs_params = { - /* MIN DFLT MAX */ - .restrict_chown = { 0, 1, 1 }, - .sgid_inherit = { 0, 0, 1 }, - .symlink_mode = { 0, 0, 1 }, - .panic_mask = { 0, 0, 127 }, - .error_level = { 0, 3, 11 }, - .sync_interval = { USER_HZ, 30*USER_HZ, 7200*USER_HZ }, - .stats_clear = { 0, 0, 1 }, - .inherit_sync = { 0, 1, 1 }, - .inherit_nodump = { 0, 1, 1 }, - .inherit_noatim = { 0, 1, 1 }, - .flush_interval = { USER_HZ/2, USER_HZ, 30*USER_HZ }, - .age_buffer = { 1*USER_HZ, 15*USER_HZ, 7200*USER_HZ }, -}; - -/* - * Global system credential structure. - */ -cred_t sys_cred_val, *sys_cred = &sys_cred_val; - diff --git a/fs/xfs/linux/xfs_globals.h b/fs/xfs/linux/xfs_globals.h deleted file mode 100644 index e81e2f38a..000000000 --- a/fs/xfs/linux/xfs_globals.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_GLOBALS_H__ -#define __XFS_GLOBALS_H__ - -/* - * This file declares globals needed by XFS that were normally defined - * somewhere else in IRIX. - */ - -extern uint64_t xfs_panic_mask; /* set to cause more panics */ -extern unsigned long xfs_physmem; -extern struct cred *sys_cred; - -#endif /* __XFS_GLOBALS_H__ */ diff --git a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c deleted file mode 100644 index d6402d746..000000000 --- a/fs/xfs/linux/xfs_ioctl.c +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" - -#include "xfs_fs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_mount.h" -#include "xfs_alloc_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bit.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_itable.h" -#include "xfs_rw.h" -#include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" -#include "xfs_attr.h" -#include "xfs_buf_item.h" -#include "xfs_utils.h" -#include "xfs_dfrag.h" -#include "xfs_fsops.h" - -#include -#include -#include -#include - -/* - * ioctl commands that are used by Linux filesystems - */ -#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) -#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) -#define XFS_IOC_GETVERSION _IOR('v', 1, long) - - -/* - * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to - * a file or fs handle. - * - * XFS_IOC_PATH_TO_FSHANDLE - * returns fs handle for a mount point or path within that mount point - * XFS_IOC_FD_TO_HANDLE - * returns full handle for a FD opened in user space - * XFS_IOC_PATH_TO_HANDLE - * returns full handle for a path - */ -STATIC int -xfs_find_handle( - unsigned int cmd, - unsigned long arg) -{ - int hsize; - xfs_handle_t handle; - xfs_fsop_handlereq_t hreq; - struct inode *inode; - struct vnode *vp; - - if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq))) - return -XFS_ERROR(EFAULT); - - memset((char *)&handle, 0, sizeof(handle)); - - switch (cmd) { - case XFS_IOC_PATH_TO_FSHANDLE: - case XFS_IOC_PATH_TO_HANDLE: { - struct nameidata nd; - int error; - - error = user_path_walk_link(hreq.path, &nd); - if (error) - return error; - - ASSERT(nd.dentry); - ASSERT(nd.dentry->d_inode); - inode = igrab(nd.dentry->d_inode); - path_release(&nd); - break; - } - - case XFS_IOC_FD_TO_HANDLE: { - struct file *file; - - file = fget(hreq.fd); - if (!file) - return -EBADF; - - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_inode); - inode = igrab(file->f_dentry->d_inode); - fput(file); - break; - } - - default: - ASSERT(0); - return -XFS_ERROR(EINVAL); - } - - if (inode->i_sb->s_magic != XFS_SB_MAGIC) { - /* we're not in XFS anymore, Toto */ - iput(inode); - return -XFS_ERROR(EINVAL); - } - - /* we need the vnode */ - vp = LINVFS_GET_VP(inode); - if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { - iput(inode); - return -XFS_ERROR(EBADF); - } - - /* now we can grab the fsid */ - memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t)); - hsize = sizeof(xfs_fsid_t); - - if (cmd != XFS_IOC_PATH_TO_FSHANDLE) { - xfs_inode_t *ip; - bhv_desc_t *bhv; - int lock_mode; - - /* need to get access to the xfs_inode to read the generation */ - bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops); - ASSERT(bhv); - ip = XFS_BHVTOI(bhv); - ASSERT(ip); - lock_mode = xfs_ilock_map_shared(ip); - - /* fill in fid section of handle from inode */ - handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - - sizeof(handle.ha_fid.xfs_fid_len); - handle.ha_fid.xfs_fid_pad = 0; - handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; - handle.ha_fid.xfs_fid_ino = ip->i_ino; - - xfs_iunlock_map_shared(ip, lock_mode); - - hsize = XFS_HSIZE(handle); - } - - /* now copy our handle into the user buffer & write out the size */ - if (copy_to_user((xfs_handle_t *)hreq.ohandle, &handle, hsize) || - copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) { - iput(inode); - return -XFS_ERROR(EFAULT); - } - - iput(inode); - return 0; -} - - -/* - * Convert userspace handle data into vnode (and inode). - * We [ab]use the fact that all the fsop_handlereq ioctl calls - * have a data structure argument whose first component is always - * a xfs_fsop_handlereq_t, so we can cast to and from this type. - * This allows us to optimise the copy_from_user calls and gives - * a handy, shared routine. - * - * If no error, caller must always VN_RELE the returned vp. - */ -STATIC int -xfs_vget_fsop_handlereq( - xfs_mount_t *mp, - struct inode *parinode, /* parent inode pointer */ - int cap, /* capability level for op */ - unsigned long arg, /* userspace data pointer */ - unsigned long size, /* size of expected struct */ - /* output arguments */ - xfs_fsop_handlereq_t *hreq, - vnode_t **vp, - struct inode **inode) -{ - void *hanp; - size_t hlen; - xfs_fid_t *xfid; - xfs_handle_t *handlep; - xfs_handle_t handle; - xfs_inode_t *ip; - struct inode *inodep; - vnode_t *vpp; - xfs_ino_t ino; - __u32 igen; - int error; - - if (!capable(cap)) - return XFS_ERROR(EPERM); - - /* - * Only allow handle opens under a directory. - */ - if (!S_ISDIR(parinode->i_mode)) - return XFS_ERROR(ENOTDIR); - - /* - * Copy the handle down from the user and validate - * that it looks to be in the correct format. - */ - if (copy_from_user(hreq, (struct xfs_fsop_handlereq *)arg, size)) - return XFS_ERROR(EFAULT); - - hanp = hreq->ihandle; - hlen = hreq->ihandlen; - handlep = &handle; - - if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) - return XFS_ERROR(EINVAL); - if (copy_from_user(handlep, hanp, hlen)) - return XFS_ERROR(EFAULT); - if (hlen < sizeof(*handlep)) - memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); - if (hlen > sizeof(handlep->ha_fsid)) { - if (handlep->ha_fid.xfs_fid_len != - (hlen - sizeof(handlep->ha_fsid) - - sizeof(handlep->ha_fid.xfs_fid_len)) - || handlep->ha_fid.xfs_fid_pad) - return XFS_ERROR(EINVAL); - } - - /* - * Crack the handle, obtain the inode # & generation # - */ - xfid = (struct xfs_fid *)&handlep->ha_fid; - if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { - ino = xfid->xfs_fid_ino; - igen = xfid->xfs_fid_gen; - } else { - return XFS_ERROR(EINVAL); - } - - /* - * Get the XFS inode, building a vnode to go with it. - */ - error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); - if (error) - return error; - if (ip == NULL) - return XFS_ERROR(EIO); - if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { - xfs_iput_new(ip, XFS_ILOCK_SHARED); - return XFS_ERROR(ENOENT); - } - - vpp = XFS_ITOV(ip); - inodep = LINVFS_GET_IP(vpp); - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - *vp = vpp; - *inode = inodep; - return 0; -} - -STATIC int -xfs_open_by_handle( - xfs_mount_t *mp, - unsigned long arg, - struct file *parfilp, - struct inode *parinode) -{ - int error; - int new_fd; - int permflag; - struct file *filp; - struct inode *inode; - struct dentry *dentry; - vnode_t *vp; - xfs_fsop_handlereq_t hreq; - - error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, - sizeof(xfs_fsop_handlereq_t), - &hreq, &vp, &inode); - if (error) - return -error; - - /* Restrict xfs_open_by_handle to directories & regular files. */ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { - iput(inode); - return -XFS_ERROR(EINVAL); - } - -#if BITS_PER_LONG != 32 - hreq.oflags |= O_LARGEFILE; -#endif - /* Put open permission in namei format. */ - permflag = hreq.oflags; - if ((permflag+1) & O_ACCMODE) - permflag++; - if (permflag & O_TRUNC) - permflag |= 2; - - if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && - (permflag & FMODE_WRITE) && IS_APPEND(inode)) { - iput(inode); - return -XFS_ERROR(EPERM); - } - - if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) { - iput(inode); - return -XFS_ERROR(EACCES); - } - - /* Can't write directories. */ - if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { - iput(inode); - return -XFS_ERROR(EISDIR); - } - - if ((new_fd = get_unused_fd()) < 0) { - iput(inode); - return new_fd; - } - - dentry = d_alloc_anon(inode); - if (dentry == NULL) { - iput(inode); - put_unused_fd(new_fd); - return -XFS_ERROR(ENOMEM); - } - - /* Ensure umount returns EBUSY on umounts while this file is open. */ - mntget(parfilp->f_vfsmnt); - - /* Create file pointer. */ - filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); - if (IS_ERR(filp)) { - put_unused_fd(new_fd); - return -XFS_ERROR(-PTR_ERR(filp)); - } - if (inode->i_mode & S_IFREG) - filp->f_op = &linvfs_invis_file_operations; - - fd_install(new_fd, filp); - return new_fd; -} - -STATIC int -xfs_readlink_by_handle( - xfs_mount_t *mp, - unsigned long arg, - struct file *parfilp, - struct inode *parinode) -{ - int error; - struct iovec aiov; - struct uio auio; - struct inode *inode; - xfs_fsop_handlereq_t hreq; - vnode_t *vp; - __u32 olen; - - error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, - sizeof(xfs_fsop_handlereq_t), - &hreq, &vp, &inode); - if (error) - return -error; - - /* Restrict this handle operation to symlinks only. */ - if (vp->v_type != VLNK) { - VN_RELE(vp); - return -XFS_ERROR(EINVAL); - } - - if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) { - VN_RELE(vp); - return -XFS_ERROR(EFAULT); - } - aiov.iov_len = olen; - aiov.iov_base = hreq.ohandle; - - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_resid = olen; - - VOP_READLINK(vp, &auio, IO_INVIS, NULL, error); - - VN_RELE(vp); - return (olen - auio.uio_resid); -} - -STATIC int -xfs_fssetdm_by_handle( - xfs_mount_t *mp, - unsigned long arg, - struct file *parfilp, - struct inode *parinode) -{ - int error; - struct fsdmidata fsd; - xfs_fsop_setdm_handlereq_t dmhreq; - struct inode *inode; - bhv_desc_t *bdp; - vnode_t *vp; - - error = xfs_vget_fsop_handlereq(mp, parinode, CAP_MKNOD, arg, - sizeof(xfs_fsop_setdm_handlereq_t), - (xfs_fsop_handlereq_t *)&dmhreq, - &vp, &inode); - if (error) - return -error; - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - VN_RELE(vp); - return -XFS_ERROR(EPERM); - } - - if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { - VN_RELE(vp); - return -XFS_ERROR(EFAULT); - } - - bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); - error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL); - - VN_RELE(vp); - if (error) - return -error; - return 0; -} - -STATIC int -xfs_attrlist_by_handle( - xfs_mount_t *mp, - unsigned long arg, - struct file *parfilp, - struct inode *parinode) -{ - int error; - attrlist_cursor_kern_t *cursor; - xfs_fsop_attrlist_handlereq_t al_hreq; - struct inode *inode; - vnode_t *vp; - - error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, - sizeof(xfs_fsop_attrlist_handlereq_t), - (xfs_fsop_handlereq_t *)&al_hreq, - &vp, &inode); - if (error) - return -error; - - cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; - VOP_ATTR_LIST(vp, al_hreq.buffer, al_hreq.buflen, al_hreq.flags, - cursor, NULL, error); - VN_RELE(vp); - if (error) - return -error; - return 0; -} - -STATIC int -xfs_attrmulti_by_handle( - xfs_mount_t *mp, - unsigned long arg, - struct file *parfilp, - struct inode *parinode) -{ - int error; - xfs_attr_multiop_t *ops; - xfs_fsop_attrmulti_handlereq_t am_hreq; - struct inode *inode; - vnode_t *vp; - int i, size; - - error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, - sizeof(xfs_fsop_attrmulti_handlereq_t), - (xfs_fsop_handlereq_t *)&am_hreq, - &vp, &inode); - if (error) - return -error; - - size = am_hreq.opcount * sizeof(attr_multiop_t); - ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL); - if (!ops) { - VN_RELE(vp); - return -XFS_ERROR(ENOMEM); - } - - if (copy_from_user(ops, am_hreq.ops, size)) { - kfree(ops); - VN_RELE(vp); - return -XFS_ERROR(EFAULT); - } - - for (i = 0; i < am_hreq.opcount; i++) { - switch(ops[i].am_opcode) { - case ATTR_OP_GET: - VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue, - &ops[i].am_length, ops[i].am_flags, - NULL, ops[i].am_error); - break; - case ATTR_OP_SET: - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - ops[i].am_error = EPERM; - break; - } - VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue, - ops[i].am_length, ops[i].am_flags, - NULL, ops[i].am_error); - break; - case ATTR_OP_REMOVE: - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - ops[i].am_error = EPERM; - break; - } - VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags, - NULL, ops[i].am_error); - break; - default: - ops[i].am_error = EINVAL; - } - } - - if (copy_to_user(am_hreq.ops, ops, size)) - error = -XFS_ERROR(EFAULT); - - kfree(ops); - VN_RELE(vp); - return error; -} - -/* prototypes for a few of the stack-hungry cases that have - * their own functions. Functions are defined after their use - * so gcc doesn't get fancy and inline them with -03 */ - -STATIC int -xfs_ioc_space( - bhv_desc_t *bdp, - vnode_t *vp, - struct file *filp, - int flags, - unsigned int cmd, - unsigned long arg); - -STATIC int -xfs_ioc_bulkstat( - xfs_mount_t *mp, - unsigned int cmd, - unsigned long arg); - -STATIC int -xfs_ioc_fsgeometry_v1( - xfs_mount_t *mp, - unsigned long arg); - -STATIC int -xfs_ioc_fsgeometry( - xfs_mount_t *mp, - unsigned long arg); - -STATIC int -xfs_ioc_xattr( - vnode_t *vp, - xfs_inode_t *ip, - struct file *filp, - unsigned int cmd, - unsigned long arg); - -STATIC int -xfs_ioc_getbmap( - bhv_desc_t *bdp, - struct file *filp, - int flags, - unsigned int cmd, - unsigned long arg); - -STATIC int -xfs_ioc_getbmapx( - bhv_desc_t *bdp, - unsigned long arg); - -int -xfs_ioctl( - bhv_desc_t *bdp, - struct inode *inode, - struct file *filp, - int ioflags, - unsigned int cmd, - unsigned long arg) -{ - int error; - vnode_t *vp; - xfs_inode_t *ip; - xfs_mount_t *mp; - - vp = LINVFS_GET_VP(inode); - - vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address); - - ip = XFS_BHVTOI(bdp); - mp = ip->i_mount; - - switch (cmd) { - - case XFS_IOC_ALLOCSP: - case XFS_IOC_FREESP: - case XFS_IOC_RESVSP: - case XFS_IOC_UNRESVSP: - case XFS_IOC_ALLOCSP64: - case XFS_IOC_FREESP64: - case XFS_IOC_RESVSP64: - case XFS_IOC_UNRESVSP64: - /* - * Only allow the sys admin to reserve space unless - * unwritten extents are enabled. - */ - if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - - return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg); - - case XFS_IOC_DIOINFO: { - struct dioattr da; - xfs_buftarg_t *target = - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? - mp->m_rtdev_targp : mp->m_ddev_targp; - - da.d_mem = da.d_miniosz = 1 << target->pbr_sshift; - /* The size dio will do in one go */ - da.d_maxiosz = 64 * PAGE_CACHE_SIZE; - - if (copy_to_user((struct dioattr *)arg, &da, sizeof(da))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_FSBULKSTAT_SINGLE: - case XFS_IOC_FSBULKSTAT: - case XFS_IOC_FSINUMBERS: - return xfs_ioc_bulkstat(mp, cmd, arg); - - case XFS_IOC_FSGEOMETRY_V1: - return xfs_ioc_fsgeometry_v1(mp, arg); - - case XFS_IOC_FSGEOMETRY: - return xfs_ioc_fsgeometry(mp, arg); - - case XFS_IOC_GETVERSION: - case XFS_IOC_GETXFLAGS: - case XFS_IOC_SETXFLAGS: - case XFS_IOC_FSGETXATTR: - case XFS_IOC_FSSETXATTR: - case XFS_IOC_FSGETXATTRA: - return xfs_ioc_xattr(vp, ip, filp, cmd, arg); - - case XFS_IOC_FSSETDM: { - struct fsdmidata dmi; - - if (copy_from_user(&dmi, (struct fsdmidata *)arg, sizeof(dmi))) - return -XFS_ERROR(EFAULT); - - error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, - NULL); - return -error; - } - - case XFS_IOC_GETBMAP: - case XFS_IOC_GETBMAPA: - return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg); - - case XFS_IOC_GETBMAPX: - return xfs_ioc_getbmapx(bdp, arg); - - case XFS_IOC_FD_TO_HANDLE: - case XFS_IOC_PATH_TO_HANDLE: - case XFS_IOC_PATH_TO_FSHANDLE: - return xfs_find_handle(cmd, arg); - - case XFS_IOC_OPEN_BY_HANDLE: - return xfs_open_by_handle(mp, arg, filp, inode); - - case XFS_IOC_FSSETDM_BY_HANDLE: - return xfs_fssetdm_by_handle(mp, arg, filp, inode); - - case XFS_IOC_READLINK_BY_HANDLE: - return xfs_readlink_by_handle(mp, arg, filp, inode); - - case XFS_IOC_ATTRLIST_BY_HANDLE: - return xfs_attrlist_by_handle(mp, arg, filp, inode); - - case XFS_IOC_ATTRMULTI_BY_HANDLE: - return xfs_attrmulti_by_handle(mp, arg, filp, inode); - - case XFS_IOC_SWAPEXT: { - error = xfs_swapext((struct xfs_swapext *)arg); - return -error; - } - - case XFS_IOC_FSCOUNTS: { - xfs_fsop_counts_t out; - - error = xfs_fs_counts(mp, &out); - if (error) - return -error; - - if (copy_to_user((char *)arg, &out, sizeof(out))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_SET_RESBLKS: { - xfs_fsop_resblks_t inout; - __uint64_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&inout, (char *)arg, sizeof(inout))) - return -XFS_ERROR(EFAULT); - - /* input parameter is passed in resblks field of structure */ - in = inout.resblks; - error = xfs_reserve_blocks(mp, &in, &inout); - if (error) - return -error; - - if (copy_to_user((char *)arg, &inout, sizeof(inout))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_GET_RESBLKS: { - xfs_fsop_resblks_t out; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - error = xfs_reserve_blocks(mp, NULL, &out); - if (error) - return -error; - - if (copy_to_user((char *)arg, &out, sizeof(out))) - return -XFS_ERROR(EFAULT); - - return 0; - } - - case XFS_IOC_FSGROWFSDATA: { - xfs_growfs_data_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&in, (char *)arg, sizeof(in))) - return -XFS_ERROR(EFAULT); - - error = xfs_growfs_data(mp, &in); - return -error; - } - - case XFS_IOC_FSGROWFSLOG: { - xfs_growfs_log_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&in, (char *)arg, sizeof(in))) - return -XFS_ERROR(EFAULT); - - error = xfs_growfs_log(mp, &in); - return -error; - } - - case XFS_IOC_FSGROWFSRT: { - xfs_growfs_rt_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&in, (char *)arg, sizeof(in))) - return -XFS_ERROR(EFAULT); - - error = xfs_growfs_rt(mp, &in); - return -error; - } - - case XFS_IOC_FREEZE: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - freeze_bdev(inode->i_sb->s_bdev); - return 0; - - case XFS_IOC_THAW: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - thaw_bdev(inode->i_sb->s_bdev, inode->i_sb); - return 0; - - case XFS_IOC_GOINGDOWN: { - __uint32_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (get_user(in, (__uint32_t *)arg)) - return -XFS_ERROR(EFAULT); - - error = xfs_fs_goingdown(mp, in); - return -error; - } - - case XFS_IOC_ERROR_INJECTION: { - xfs_error_injection_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&in, (char *)arg, sizeof(in))) - return -XFS_ERROR(EFAULT); - - error = xfs_errortag_add(in.errtag, mp); - return -error; - } - - case XFS_IOC_ERROR_CLEARALL: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - error = xfs_errortag_clearall(mp); - return -error; - - default: - return -ENOTTY; - } -} - -STATIC int -xfs_ioc_space( - bhv_desc_t *bdp, - vnode_t *vp, - struct file *filp, - int ioflags, - unsigned int cmd, - unsigned long arg) -{ - xfs_flock64_t bf; - int attr_flags = 0; - int error; - - if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) - return -XFS_ERROR(EPERM); - - if (!(filp->f_flags & FMODE_WRITE)) - return -XFS_ERROR(EBADF); - - if (vp->v_type != VREG) - return -XFS_ERROR(EINVAL); - - if (copy_from_user(&bf, (xfs_flock64_t *)arg, sizeof(bf))) - return -XFS_ERROR(EFAULT); - - if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) - attr_flags |= ATTR_NONBLOCK; - if (ioflags & IO_INVIS) - attr_flags |= ATTR_DMI; - - error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos, - NULL, attr_flags); - return -error; -} - -STATIC int -xfs_ioc_bulkstat( - xfs_mount_t *mp, - unsigned int cmd, - unsigned long arg) -{ - xfs_fsop_bulkreq_t bulkreq; - int count; /* # of records returned */ - xfs_ino_t inlast; /* last inode number */ - int done; - int error; - - /* done = 1 if there are more stats to get and if bulkstat */ - /* should be called again (unused here, but used in dmapi) */ - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -XFS_ERROR(EIO); - - if (copy_from_user(&bulkreq, (xfs_fsop_bulkreq_t *)arg, - sizeof(xfs_fsop_bulkreq_t))) - return -XFS_ERROR(EFAULT); - - if (copy_from_user(&inlast, (__s64 *)bulkreq.lastip, - sizeof(__s64))) - return -XFS_ERROR(EFAULT); - - if ((count = bulkreq.icount) <= 0) - return -XFS_ERROR(EINVAL); - - if (cmd == XFS_IOC_FSINUMBERS) - error = xfs_inumbers(mp, NULL, &inlast, &count, - bulkreq.ubuffer); - else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) - error = xfs_bulkstat_single(mp, &inlast, - bulkreq.ubuffer, &done); - else { /* XFS_IOC_FSBULKSTAT */ - if (count == 1 && inlast != 0) { - inlast++; - error = xfs_bulkstat_single(mp, &inlast, - bulkreq.ubuffer, &done); - } else { - error = xfs_bulkstat(mp, NULL, &inlast, &count, - (bulkstat_one_pf)xfs_bulkstat_one, NULL, - sizeof(xfs_bstat_t), bulkreq.ubuffer, - BULKSTAT_FG_QUICK, &done); - } - } - - if (error) - return -error; - - if (bulkreq.ocount != NULL) { - if (copy_to_user((xfs_ino_t *)bulkreq.lastip, &inlast, - sizeof(xfs_ino_t))) - return -XFS_ERROR(EFAULT); - - if (copy_to_user((__s32 *)bulkreq.ocount, &count, - sizeof(count))) - return -XFS_ERROR(EFAULT); - } - - return 0; -} - -STATIC int -xfs_ioc_fsgeometry_v1( - xfs_mount_t *mp, - unsigned long arg) -{ - xfs_fsop_geom_v1_t fsgeo; - int error; - - error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3); - if (error) - return -error; - - if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo))) - return -XFS_ERROR(EFAULT); - return 0; -} - -STATIC int -xfs_ioc_fsgeometry( - xfs_mount_t *mp, - unsigned long arg) -{ - xfs_fsop_geom_t fsgeo; - int error; - - error = xfs_fs_geometry(mp, &fsgeo, 4); - if (error) - return -error; - - if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, sizeof(fsgeo))) - return -XFS_ERROR(EFAULT); - return 0; -} - -/* - * Linux extended inode flags interface. - */ -#define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */ -#define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */ -#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */ -#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */ -#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */ - -STATIC unsigned int -xfs_merge_ioc_xflags( - unsigned int flags, - unsigned int start) -{ - unsigned int xflags = start; - - if (flags & LINUX_XFLAG_IMMUTABLE) - xflags |= XFS_XFLAG_IMMUTABLE; - else - xflags &= ~XFS_XFLAG_IMMUTABLE; - if (flags & LINUX_XFLAG_APPEND) - xflags |= XFS_XFLAG_APPEND; - else - xflags &= ~XFS_XFLAG_APPEND; - if (flags & LINUX_XFLAG_SYNC) - xflags |= XFS_XFLAG_SYNC; - else - xflags &= ~XFS_XFLAG_SYNC; - if (flags & LINUX_XFLAG_NOATIME) - xflags |= XFS_XFLAG_NOATIME; - else - xflags &= ~XFS_XFLAG_NOATIME; - if (flags & LINUX_XFLAG_NODUMP) - xflags |= XFS_XFLAG_NODUMP; - else - xflags &= ~XFS_XFLAG_NODUMP; - - return xflags; -} - -STATIC int -xfs_ioc_xattr( - vnode_t *vp, - xfs_inode_t *ip, - struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - struct fsxattr fa; - vattr_t va; - int error; - int attr_flags; - unsigned int flags; - - switch (cmd) { - case XFS_IOC_FSGETXATTR: { - va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (error) - return -error; - - fa.fsx_xflags = va.va_xflags; - fa.fsx_extsize = va.va_extsize; - fa.fsx_nextents = va.va_nextents; - - if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_FSSETXATTR: { - if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) - return -XFS_ERROR(EFAULT); - - attr_flags = 0; - if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) - attr_flags |= ATTR_NONBLOCK; - - va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; - va.va_xflags = fa.fsx_xflags; - va.va_extsize = fa.fsx_extsize; - - VOP_SETATTR(vp, &va, attr_flags, NULL, error); - if (!error) - vn_revalidate(vp); /* update Linux inode flags */ - return -error; - } - - case XFS_IOC_FSGETXATTRA: { - va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (error) - return -error; - - fa.fsx_xflags = va.va_xflags; - fa.fsx_extsize = va.va_extsize; - fa.fsx_nextents = va.va_anextents; - - if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_GETXFLAGS: { - flags = 0; - if (ip->i_d.di_flags & XFS_XFLAG_IMMUTABLE) - flags |= LINUX_XFLAG_IMMUTABLE; - if (ip->i_d.di_flags & XFS_XFLAG_APPEND) - flags |= LINUX_XFLAG_APPEND; - if (ip->i_d.di_flags & XFS_XFLAG_SYNC) - flags |= LINUX_XFLAG_SYNC; - if (ip->i_d.di_flags & XFS_XFLAG_NOATIME) - flags |= LINUX_XFLAG_NOATIME; - if (ip->i_d.di_flags & XFS_XFLAG_NODUMP) - flags |= LINUX_XFLAG_NODUMP; - if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_SETXFLAGS: { - if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags))) - return -XFS_ERROR(EFAULT); - - if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ - LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ - LINUX_XFLAG_SYNC)) - return -XFS_ERROR(EOPNOTSUPP); - - attr_flags = 0; - if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) - attr_flags |= ATTR_NONBLOCK; - - va.va_mask = XFS_AT_XFLAGS; - va.va_xflags = xfs_merge_ioc_xflags(flags, ip->i_d.di_flags); - - VOP_SETATTR(vp, &va, attr_flags, NULL, error); - if (!error) - vn_revalidate(vp); /* update Linux inode flags */ - return -error; - } - - case XFS_IOC_GETVERSION: { - flags = LINVFS_GET_IP(vp)->i_generation; - if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) - return -XFS_ERROR(EFAULT); - return 0; - } - - default: - return -ENOTTY; - } -} - -STATIC int -xfs_ioc_getbmap( - bhv_desc_t *bdp, - struct file *filp, - int ioflags, - unsigned int cmd, - unsigned long arg) -{ - struct getbmap bm; - int iflags; - int error; - - if (copy_from_user(&bm, (struct getbmap *)arg, sizeof(bm))) - return -XFS_ERROR(EFAULT); - - if (bm.bmv_count < 2) - return -XFS_ERROR(EINVAL); - - iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); - if (ioflags & IO_INVIS) - iflags |= BMV_IF_NO_DMAPI_READ; - - error = xfs_getbmap(bdp, &bm, (struct getbmap *)arg+1, iflags); - if (error) - return -error; - - if (copy_to_user((struct getbmap *)arg, &bm, sizeof(bm))) - return -XFS_ERROR(EFAULT); - return 0; -} - -STATIC int -xfs_ioc_getbmapx( - bhv_desc_t *bdp, - unsigned long arg) -{ - struct getbmapx bmx; - struct getbmap bm; - int iflags; - int error; - - if (copy_from_user(&bmx, (struct getbmapx *)arg, sizeof(bmx))) - return -XFS_ERROR(EFAULT); - - if (bmx.bmv_count < 2) - return -XFS_ERROR(EINVAL); - - /* - * Map input getbmapx structure to a getbmap - * structure for xfs_getbmap. - */ - GETBMAP_CONVERT(bmx, bm); - - iflags = bmx.bmv_iflags; - - if (iflags & (~BMV_IF_VALID)) - return -XFS_ERROR(EINVAL); - - iflags |= BMV_IF_EXTENDED; - - error = xfs_getbmap(bdp, &bm, (struct getbmapx *)arg+1, iflags); - if (error) - return -error; - - GETBMAP_CONVERT(bm, bmx); - - if (copy_to_user((struct getbmapx *)arg, &bmx, sizeof(bmx))) - return -XFS_ERROR(EFAULT); - - return 0; -} diff --git a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c deleted file mode 100644 index 4b3e61d6c..000000000 --- a/fs/xfs/linux/xfs_iops.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_ag.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_quota.h" -#include "xfs_mount.h" -#include "xfs_alloc_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bit.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_itable.h" -#include "xfs_rw.h" -#include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" -#include "xfs_attr.h" -#include "xfs_buf_item.h" -#include "xfs_utils.h" - -#include - - -/* - * Pull the link count and size up from the xfs inode to the linux inode - */ -STATIC void -validate_fields( - struct inode *ip) -{ - vnode_t *vp = LINVFS_GET_VP(ip); - vattr_t va; - int error; - - va.va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; - VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error); - if (likely(!error)) { - ip->i_nlink = va.va_nlink; - ip->i_blocks = va.va_nblocks; - - /* we're under i_sem so i_size can't change under us */ - if (i_size_read(ip) != va.va_size) - i_size_write(ip, va.va_size); - } -} - -/* - * Determine whether a process has a valid fs_struct (kernel daemons - * like knfsd don't have an fs_struct). - * - * XXX(hch): nfsd is broken, better fix it instead. - */ -STATIC inline int -has_fs_struct(struct task_struct *task) -{ - return (task->fs != init_task.fs); -} - -STATIC int -linvfs_mknod( - struct inode *dir, - struct dentry *dentry, - int mode, - dev_t rdev) -{ - struct inode *ip; - vattr_t va; - vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); - xfs_acl_t *default_acl = NULL; - attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; - int error; - - /* - * Irix uses Missed'em'V split, but doesn't want to see - * the upper 5 bits of (14bit) major. - */ - if (!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff) - return -EINVAL; - - if (test_default_acl && test_default_acl(dvp)) { - if (!_ACL_ALLOC(default_acl)) - return -ENOMEM; - if (!_ACL_GET_DEFAULT(dvp, default_acl)) { - _ACL_FREE(default_acl); - default_acl = NULL; - } - } - - if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current)) - mode &= ~current->fs->umask; - - memset(&va, 0, sizeof(va)); - va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; - va.va_type = IFTOVT(mode); - va.va_mode = mode; - - switch (mode & S_IFMT) { - case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - va.va_rdev = sysv_encode_dev(rdev); - va.va_mask |= XFS_AT_RDEV; - /*FALLTHROUGH*/ - case S_IFREG: - VOP_CREATE(dvp, dentry, &va, &vp, NULL, error); - break; - case S_IFDIR: - VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error); - break; - default: - error = EINVAL; - break; - } - - if (default_acl) { - if (!error) { - error = _ACL_INHERIT(vp, &va, default_acl); - if (!error) { - VMODIFY(vp); - } else { - struct dentry teardown = {}; - int err2; - - /* Oh, the horror. - * If we can't add the ACL we must back out. - * ENOSPC can hit here, among other things. - */ - teardown.d_inode = ip = LINVFS_GET_IP(vp); - teardown.d_name = dentry->d_name; - remove_inode_hash(ip); - make_bad_inode(ip); - if (S_ISDIR(mode)) - VOP_RMDIR(dvp, &teardown, NULL, err2); - else - VOP_REMOVE(dvp, &teardown, NULL, err2); - VN_RELE(vp); - } - } - _ACL_FREE(default_acl); - } - - if (!error) { - ASSERT(vp); - ip = LINVFS_GET_IP(vp); - - if (S_ISCHR(mode) || S_ISBLK(mode)) - ip->i_rdev = rdev; - else if (S_ISDIR(mode)) - validate_fields(ip); - d_instantiate(dentry, ip); - validate_fields(dir); - } - return -error; -} - -STATIC int -linvfs_create( - struct inode *dir, - struct dentry *dentry, - int mode, - struct nameidata *nd) -{ - return linvfs_mknod(dir, dentry, mode, 0); -} - -STATIC int -linvfs_mkdir( - struct inode *dir, - struct dentry *dentry, - int mode) -{ - return linvfs_mknod(dir, dentry, mode|S_IFDIR, 0); -} - -STATIC struct dentry * -linvfs_lookup( - struct inode *dir, - struct dentry *dentry, - struct nameidata *nd) -{ - struct inode *ip = NULL; - vnode_t *vp, *cvp = NULL; - int error; - - if (dentry->d_name.len >= MAXNAMELEN) - return ERR_PTR(-ENAMETOOLONG); - - vp = LINVFS_GET_VP(dir); - VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error); - if (!error) { - ASSERT(cvp); - ip = LINVFS_GET_IP(cvp); - if (!ip) { - VN_RELE(cvp); - return ERR_PTR(-EACCES); - } - } - if (error && (error != ENOENT)) - return ERR_PTR(-error); - return d_splice_alias(ip, dentry); -} - -STATIC int -linvfs_link( - struct dentry *old_dentry, - struct inode *dir, - struct dentry *dentry) -{ - struct inode *ip; /* inode of guy being linked to */ - vnode_t *tdvp; /* target directory for new name/link */ - vnode_t *vp; /* vp of name being linked */ - int error; - - ip = old_dentry->d_inode; /* inode being linked to */ - if (S_ISDIR(ip->i_mode)) - return -EPERM; - - tdvp = LINVFS_GET_VP(dir); - vp = LINVFS_GET_VP(ip); - - VOP_LINK(tdvp, vp, dentry, NULL, error); - if (!error) { - VMODIFY(tdvp); - VN_HOLD(vp); - validate_fields(ip); - d_instantiate(dentry, ip); - } - return -error; -} - -STATIC int -linvfs_unlink( - struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode; - vnode_t *dvp; /* directory containing name to remove */ - int error; - - inode = dentry->d_inode; - dvp = LINVFS_GET_VP(dir); - - VOP_REMOVE(dvp, dentry, NULL, error); - if (!error) { - validate_fields(dir); /* For size only */ - validate_fields(inode); - } - - return -error; -} - -STATIC int -linvfs_symlink( - struct inode *dir, - struct dentry *dentry, - const char *symname) -{ - struct inode *ip; - vattr_t va; - vnode_t *dvp; /* directory containing name to remove */ - vnode_t *cvp; /* used to lookup symlink to put in dentry */ - int error; - - dvp = LINVFS_GET_VP(dir); - cvp = NULL; - - memset(&va, 0, sizeof(va)); - va.va_type = VLNK; - va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO; - va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; - - error = 0; - VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); - if (!error && cvp) { - ASSERT(cvp->v_type == VLNK); - ip = LINVFS_GET_IP(cvp); - d_instantiate(dentry, ip); - validate_fields(dir); - validate_fields(ip); /* size needs update */ - } - return -error; -} - -STATIC int -linvfs_rmdir( - struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - vnode_t *dvp = LINVFS_GET_VP(dir); - int error; - - VOP_RMDIR(dvp, dentry, NULL, error); - if (!error) { - validate_fields(inode); - validate_fields(dir); - } - return -error; -} - -STATIC int -linvfs_rename( - struct inode *odir, - struct dentry *odentry, - struct inode *ndir, - struct dentry *ndentry) -{ - struct inode *new_inode = ndentry->d_inode; - vnode_t *fvp; /* from directory */ - vnode_t *tvp; /* target directory */ - int error; - - fvp = LINVFS_GET_VP(odir); - tvp = LINVFS_GET_VP(ndir); - - VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error); - if (error) - return -error; - - if (new_inode) - validate_fields(new_inode); - - validate_fields(odir); - if (ndir != odir) - validate_fields(ndir); - return 0; -} - -STATIC int -linvfs_readlink( - struct dentry *dentry, - char *buf, - int size) -{ - vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); - uio_t uio; - iovec_t iov; - int error; - - iov.iov_base = buf; - iov.iov_len = size; - - uio.uio_iov = &iov; - uio.uio_offset = 0; - uio.uio_segflg = UIO_USERSPACE; - uio.uio_resid = size; - uio.uio_iovcnt = 1; - - VOP_READLINK(vp, &uio, 0, NULL, error); - if (error) - return -error; - - return (size - uio.uio_resid); -} - -/* - * careful here - this function can get called recursively, so - * we need to be very careful about how much stack we use. - * uio is kmalloced for this reason... - */ -STATIC int -linvfs_follow_link( - struct dentry *dentry, - struct nameidata *nd) -{ - vnode_t *vp; - uio_t *uio; - iovec_t iov; - int error; - char *link; - - ASSERT(dentry); - ASSERT(nd); - - link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); - if (!link) - return -ENOMEM; - - uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); - if (!uio) { - kfree(link); - return -ENOMEM; - } - - vp = LINVFS_GET_VP(dentry->d_inode); - - iov.iov_base = link; - iov.iov_len = MAXNAMELEN; - - uio->uio_iov = &iov; - uio->uio_offset = 0; - uio->uio_segflg = UIO_SYSSPACE; - uio->uio_resid = MAXNAMELEN; - uio->uio_iovcnt = 1; - - VOP_READLINK(vp, uio, 0, NULL, error); - if (error) { - kfree(uio); - kfree(link); - return -error; - } - - link[MAXNAMELEN - uio->uio_resid] = '\0'; - kfree(uio); - - /* vfs_follow_link returns (-) errors */ - error = vfs_follow_link(nd, link); - kfree(link); - return error; -} - -#ifdef CONFIG_XFS_POSIX_ACL -STATIC int -linvfs_permission( - struct inode *inode, - int mode, - struct nameidata *nd) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - int error; - - mode <<= 6; /* convert from linux to vnode access bits */ - VOP_ACCESS(vp, mode, NULL, error); - return -error; -} -#else -#define linvfs_permission NULL -#endif - -STATIC int -linvfs_getattr( - struct vfsmount *mnt, - struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = dentry->d_inode; - vnode_t *vp = LINVFS_GET_VP(inode); - int error = 0; - - if (unlikely(vp->v_flag & VMODIFIED)) - error = vn_revalidate(vp); - if (!error) - generic_fillattr(inode, stat); - return 0; -} - -STATIC int -linvfs_setattr( - struct dentry *dentry, - struct iattr *attr) -{ - struct inode *inode = dentry->d_inode; - unsigned int ia_valid = attr->ia_valid; - vnode_t *vp = LINVFS_GET_VP(inode); - vattr_t vattr; - int flags = 0; - int error; - - memset(&vattr, 0, sizeof(vattr_t)); - if (ia_valid & ATTR_UID) { - vattr.va_mask |= XFS_AT_UID; - vattr.va_uid = attr->ia_uid; - } - if (ia_valid & ATTR_GID) { - vattr.va_mask |= XFS_AT_GID; - vattr.va_gid = attr->ia_gid; - } - if (ia_valid & ATTR_SIZE) { - vattr.va_mask |= XFS_AT_SIZE; - vattr.va_size = attr->ia_size; - } - if (ia_valid & ATTR_ATIME) { - vattr.va_mask |= XFS_AT_ATIME; - vattr.va_atime = attr->ia_atime; - } - if (ia_valid & ATTR_MTIME) { - vattr.va_mask |= XFS_AT_MTIME; - vattr.va_mtime = attr->ia_mtime; - } - if (ia_valid & ATTR_CTIME) { - vattr.va_mask |= XFS_AT_CTIME; - vattr.va_ctime = attr->ia_ctime; - } - if (ia_valid & ATTR_MODE) { - vattr.va_mask |= XFS_AT_MODE; - vattr.va_mode = attr->ia_mode; - if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) - inode->i_mode &= ~S_ISGID; - } - - if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) - flags = ATTR_UTIME; -#ifdef ATTR_NO_BLOCK - if ((ia_valid & ATTR_NO_BLOCK)) - flags |= ATTR_NONBLOCK; -#endif - - VOP_SETATTR(vp, &vattr, flags, NULL, error); - if (error) - return(-error); /* Positive error up from XFS */ - if (ia_valid & ATTR_SIZE) { - error = vmtruncate(inode, attr->ia_size); - } - - if (!error) { - vn_revalidate(vp); - } - return error; -} - -STATIC void -linvfs_truncate( - struct inode *inode) -{ - block_truncate_page(inode->i_mapping, inode->i_size, linvfs_get_block); -} - -STATIC int -linvfs_setxattr( - struct dentry *dentry, - const char *name, - const void *data, - size_t size, - int flags) -{ - vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - int error; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (flags & XATTR_CREATE) - xflags |= ATTR_CREATE; - if (flags & XATTR_REPLACE) - xflags |= ATTR_REPLACE; - xflags |= namesp->attr_flag; - return namesp->attr_set(vp, attr, (void *)data, size, xflags); -} - -STATIC ssize_t -linvfs_getxattr( - struct dentry *dentry, - const char *name, - void *data, - size_t size) -{ - vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - ssize_t error; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (!size) { - xflags |= ATTR_KERNOVAL; - data = NULL; - } - xflags |= namesp->attr_flag; - return namesp->attr_get(vp, attr, (void *)data, size, xflags); -} - -STATIC ssize_t -linvfs_listxattr( - struct dentry *dentry, - char *data, - size_t size) -{ - vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); - int error, xflags = ATTR_KERNAMELS; - ssize_t result; - - if (!size) - xflags |= ATTR_KERNOVAL; - xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS; - - error = attr_generic_list(vp, data, size, xflags, &result); - if (error < 0) - return error; - return result; -} - -STATIC int -linvfs_removexattr( - struct dentry *dentry, - const char *name) -{ - vnode_t *vp = LINVFS_GET_VP(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - int error; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; - xflags |= namesp->attr_flag; - return namesp->attr_remove(vp, attr, xflags); -} - - -struct inode_operations linvfs_file_inode_operations = { - .permission = linvfs_permission, - .truncate = linvfs_truncate, - .getattr = linvfs_getattr, - .setattr = linvfs_setattr, - .setxattr = linvfs_setxattr, - .getxattr = linvfs_getxattr, - .listxattr = linvfs_listxattr, - .removexattr = linvfs_removexattr, -}; - -struct inode_operations linvfs_dir_inode_operations = { - .create = linvfs_create, - .lookup = linvfs_lookup, - .link = linvfs_link, - .unlink = linvfs_unlink, - .symlink = linvfs_symlink, - .mkdir = linvfs_mkdir, - .rmdir = linvfs_rmdir, - .mknod = linvfs_mknod, - .rename = linvfs_rename, - .permission = linvfs_permission, - .getattr = linvfs_getattr, - .setattr = linvfs_setattr, - .setxattr = linvfs_setxattr, - .getxattr = linvfs_getxattr, - .listxattr = linvfs_listxattr, - .removexattr = linvfs_removexattr, -}; - -struct inode_operations linvfs_symlink_inode_operations = { - .readlink = linvfs_readlink, - .follow_link = linvfs_follow_link, - .permission = linvfs_permission, - .getattr = linvfs_getattr, - .setattr = linvfs_setattr, - .setxattr = linvfs_setxattr, - .getxattr = linvfs_getxattr, - .listxattr = linvfs_listxattr, - .removexattr = linvfs_removexattr, -}; diff --git a/fs/xfs/linux/xfs_iops.h b/fs/xfs/linux/xfs_iops.h deleted file mode 100644 index f0f5c870f..000000000 --- a/fs/xfs/linux/xfs_iops.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_IOPS_H__ -#define __XFS_IOPS_H__ - -extern struct inode_operations linvfs_file_inode_operations; -extern struct inode_operations linvfs_dir_inode_operations; -extern struct inode_operations linvfs_symlink_inode_operations; - -extern struct file_operations linvfs_file_operations; -extern struct file_operations linvfs_invis_file_operations; -extern struct file_operations linvfs_dir_operations; - -extern struct address_space_operations linvfs_aops; - -extern int linvfs_get_block(struct inode *, sector_t, struct buffer_head *, int); -extern void linvfs_unwritten_done(struct buffer_head *, int); - -extern int xfs_ioctl(struct bhv_desc *, struct inode *, struct file *, - int, unsigned int, unsigned long); - -#endif /* __XFS_IOPS_H__ */ diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h deleted file mode 100644 index 70481f85f..000000000 --- a/fs/xfs/linux/xfs_linux.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_LINUX__ -#define __XFS_LINUX__ - -#include -#include - -/* - * Some types are conditional depending on the target system. - * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. - * XFS_BIG_INUMS needs the VFS inode number to be 64 bits, as well - * as requiring XFS_BIG_BLKNOS to be set. - */ -#if defined(CONFIG_LBD) || (BITS_PER_LONG == 64) -# define XFS_BIG_BLKNOS 1 -# if BITS_PER_LONG == 64 -# define XFS_BIG_INUMS 1 -# else -# define XFS_BIG_INUMS 0 -# endif -#else -# define XFS_BIG_BLKNOS 0 -# define XFS_BIG_INUMS 0 -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Feature macros (disable/enable) - */ -#undef HAVE_REFCACHE /* reference cache not needed for NFS in 2.6 */ -#define HAVE_SENDFILE /* sendfile(2) exists in 2.6, but not in 2.4 */ - -/* - * State flag for unwritten extent buffers. - * - * We need to be able to distinguish between these and delayed - * allocate buffers within XFS. The generic IO path code does - * not need to distinguish - we use the BH_Delay flag for both - * delalloc and these ondisk-uninitialised buffers. - */ -BUFFER_FNS(PrivateStart, unwritten); -static inline void set_buffer_unwritten_io(struct buffer_head *bh) -{ - bh->b_end_io = linvfs_unwritten_done; -} - -#define xfs_refcache_size xfs_params.refcache_size.val -#define xfs_refcache_purge_count xfs_params.refcache_purge.val -#define restricted_chown xfs_params.restrict_chown.val -#define irix_sgid_inherit xfs_params.sgid_inherit.val -#define irix_symlink_mode xfs_params.symlink_mode.val -#define xfs_panic_mask xfs_params.panic_mask.val -#define xfs_error_level xfs_params.error_level.val -#define xfs_syncd_interval (xfs_params.sync_interval.val * HZ / USER_HZ) -#define xfs_stats_clear xfs_params.stats_clear.val -#define xfs_inherit_sync xfs_params.inherit_sync.val -#define xfs_inherit_nodump xfs_params.inherit_nodump.val -#define xfs_inherit_noatime xfs_params.inherit_noatim.val -#define xfs_flush_interval (xfs_params.flush_interval.val * HZ / USER_HZ) -#define xfs_age_buffer (xfs_params.age_buffer.val * HZ / USER_HZ) - -#define current_cpu() smp_processor_id() -#define current_pid() (current->pid) -#define current_fsuid(cred) (current->fsuid) -#define current_fsgid(cred) (current->fsgid) - -#define NBPP PAGE_SIZE -#define DPPSHFT (PAGE_SHIFT - 9) -#define NDPP (1 << (PAGE_SHIFT - 9)) -#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT) -#define dtopt(DD) ((DD) >> DPPSHFT) -#define dpoff(DD) ((DD) & (NDPP-1)) - -#define NBBY 8 /* number of bits per byte */ -#define NBPC PAGE_SIZE /* Number of bytes per click */ -#define BPCSHIFT PAGE_SHIFT /* LOG2(NBPC) if exact */ - -/* - * Size of block device i/o is parameterized here. - * Currently the system supports page-sized i/o. - */ -#define BLKDEV_IOSHIFT BPCSHIFT -#define BLKDEV_IOSIZE (1<>BPCSHIFT) -#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT) -#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) -#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT) -#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT) -#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT) - -/* off_t bytes to clicks */ -#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) -#define offtoct(x) ((xfs_off_t)(x)>>BPCSHIFT) - -/* clicks to off_t bytes */ -#define ctooff(x) ((xfs_off_t)(x)<>BPCSHIFT) -#define ctob64(x) ((__uint64_t)(x)<>BPCSHIFT) - -#ifndef CELL_CAPABLE -#define FSC_NOTIFY_NAME_CHANGED(vp) -#endif - -#ifndef ENOATTR -#define ENOATTR ENODATA /* Attribute not found */ -#endif - -/* Note: EWRONGFS never visible outside the kernel */ -#define EWRONGFS EINVAL /* Mount with wrong filesystem type */ - -/* - * XXX EFSCORRUPTED needs a real value in errno.h. asm-i386/errno.h won't - * return codes out of its known range in errno. - * XXX Also note: needs to be < 1000 and fairly unique on Linux (mustn't - * conflict with any code we use already or any code a driver may use) - * XXX Some options (currently we do #2): - * 1/ New error code ["Filesystem is corrupted", _after_ glibc updated] - * 2/ 990 ["Unknown error 990"] - * 3/ EUCLEAN ["Structure needs cleaning"] - * 4/ Convert EFSCORRUPTED to EIO [just prior to return into userspace] - */ -#define EFSCORRUPTED 990 /* Filesystem is corrupted */ - -#define SYNCHRONIZE() barrier() -#define __return_address __builtin_return_address(0) - -/* - * IRIX (BSD) quotactl makes use of separate commands for user/group, - * whereas on Linux the syscall encodes this information into the cmd - * field (see the QCMD macro in quota.h). These macros help keep the - * code portable - they are not visible from the syscall interface. - */ -#define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */ -#define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */ - -/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ -/* we may well need to fine-tune this if it ever becomes an issue. */ -#define DQUOT_MAX_HEURISTIC 1024 /* NR_DQUOTS */ -#define ndquot DQUOT_MAX_HEURISTIC - -/* IRIX uses the current size of the name cache to guess a good value */ -/* - this isn't the same but is a good enough starting point for now. */ -#define DQUOT_HASH_HEURISTIC files_stat.nr_files - -/* IRIX inodes maintain the project ID also, zero this field on Linux */ -#define DEFAULT_PROJID 0 -#define dfltprid DEFAULT_PROJID - -#define MAXPATHLEN 1024 - -#define MIN(a,b) (min(a,b)) -#define MAX(a,b) (max(a,b)) -#define howmany(x, y) (((x)+((y)-1))/(y)) -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) - -#define xfs_stack_trace() dump_stack() - -#define xfs_itruncate_data(ip, off) \ - (-vmtruncate(LINVFS_GET_IP(XFS_ITOV(ip)), (off))) - - -/* Move the kernel do_div definition off to one side */ - -#if defined __i386__ -/* For ia32 we need to pull some tricks to get past various versions - * of the compiler which do not like us using do_div in the middle - * of large functions. - */ -static inline __u32 xfs_do_div(void *a, __u32 b, int n) -{ - __u32 mod; - - switch (n) { - case 4: - mod = *(__u32 *)a % b; - *(__u32 *)a = *(__u32 *)a / b; - return mod; - case 8: - { - unsigned long __upper, __low, __high, __mod; - __u64 c = *(__u64 *)a; - __upper = __high = c >> 32; - __low = c; - if (__high) { - __upper = __high % (b); - __high = __high / (b); - } - asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); - asm("":"=A" (c):"a" (__low),"d" (__high)); - *(__u64 *)a = c; - return __mod; - } - } - - /* NOTREACHED */ - return 0; -} - -/* Side effect free 64 bit mod operation */ -static inline __u32 xfs_do_mod(void *a, __u32 b, int n) -{ - switch (n) { - case 4: - return *(__u32 *)a % b; - case 8: - { - unsigned long __upper, __low, __high, __mod; - __u64 c = *(__u64 *)a; - __upper = __high = c >> 32; - __low = c; - if (__high) { - __upper = __high % (b); - __high = __high / (b); - } - asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); - asm("":"=A" (c):"a" (__low),"d" (__high)); - return __mod; - } - } - - /* NOTREACHED */ - return 0; -} -#else -static inline __u32 xfs_do_div(void *a, __u32 b, int n) -{ - __u32 mod; - - switch (n) { - case 4: - mod = *(__u32 *)a % b; - *(__u32 *)a = *(__u32 *)a / b; - return mod; - case 8: - mod = do_div(*(__u64 *)a, b); - return mod; - } - - /* NOTREACHED */ - return 0; -} - -/* Side effect free 64 bit mod operation */ -static inline __u32 xfs_do_mod(void *a, __u32 b, int n) -{ - switch (n) { - case 4: - return *(__u32 *)a % b; - case 8: - { - __u64 c = *(__u64 *)a; - return do_div(c, b); - } - } - - /* NOTREACHED */ - return 0; -} -#endif - -#undef do_div -#define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) -#define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) - -static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) -{ - x += y - 1; - do_div(x, y); - return(x * y); -} - -#endif /* __XFS_LINUX__ */ diff --git a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c deleted file mode 100644 index 4bacdb76a..000000000 --- a/fs/xfs/linux/xfs_lrw.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -/* - * fs/xfs/linux/xfs_lrw.c (Linux Read Write stuff) - * - */ - -#include "xfs.h" - -#include "xfs_fs.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_ag.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_quota.h" -#include "xfs_mount.h" -#include "xfs_alloc_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bit.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_itable.h" -#include "xfs_rw.h" -#include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" -#include "xfs_attr.h" -#include "xfs_inode_item.h" -#include "xfs_buf_item.h" -#include "xfs_utils.h" -#include "xfs_iomap.h" - -#include - - -#if defined(XFS_RW_TRACE) -void -xfs_rw_enter_trace( - int tag, - xfs_iocore_t *io, - const struct iovec *iovp, - size_t segs, - loff_t offset, - int ioflags) -{ - xfs_inode_t *ip = XFS_IO_INODE(io); - - if (ip->i_rwtrace == NULL) - return; - ktrace_enter(ip->i_rwtrace, - (void *)(unsigned long)tag, - (void *)ip, - (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), - (void *)(__psint_t)iovp, - (void *)((unsigned long)segs), - (void *)((unsigned long)((offset >> 32) & 0xffffffff)), - (void *)((unsigned long)(offset & 0xffffffff)), - (void *)((unsigned long)ioflags), - (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(io->io_new_size & 0xffffffff)), - (void *)NULL, - (void *)NULL, - (void *)NULL, - (void *)NULL, - (void *)NULL); -} - -void -xfs_inval_cached_trace( - xfs_iocore_t *io, - xfs_off_t offset, - xfs_off_t len, - xfs_off_t first, - xfs_off_t last) -{ - xfs_inode_t *ip = XFS_IO_INODE(io); - - if (ip->i_rwtrace == NULL) - return; - ktrace_enter(ip->i_rwtrace, - (void *)(__psint_t)XFS_INVAL_CACHED, - (void *)ip, - (void *)((unsigned long)((offset >> 32) & 0xffffffff)), - (void *)((unsigned long)(offset & 0xffffffff)), - (void *)((unsigned long)((len >> 32) & 0xffffffff)), - (void *)((unsigned long)(len & 0xffffffff)), - (void *)((unsigned long)((first >> 32) & 0xffffffff)), - (void *)((unsigned long)(first & 0xffffffff)), - (void *)((unsigned long)((last >> 32) & 0xffffffff)), - (void *)((unsigned long)(last & 0xffffffff)), - (void *)NULL, - (void *)NULL, - (void *)NULL, - (void *)NULL, - (void *)NULL, - (void *)NULL); -} -#endif - -/* - * xfs_iozero - * - * xfs_iozero clears the specified range of buffer supplied, - * and marks all the affected blocks as valid and modified. If - * an affected block is not allocated, it will be allocated. If - * an affected block is not completely overwritten, and is not - * valid before the operation, it will be read from disk before - * being partially zeroed. - */ -STATIC int -xfs_iozero( - struct inode *ip, /* inode */ - loff_t pos, /* offset in file */ - size_t count, /* size of data to zero */ - loff_t end_size) /* max file size to set */ -{ - unsigned bytes; - struct page *page; - struct address_space *mapping; - char *kaddr; - int status; - - mapping = ip->i_mapping; - do { - unsigned long index, offset; - - offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ - index = pos >> PAGE_CACHE_SHIFT; - bytes = PAGE_CACHE_SIZE - offset; - if (bytes > count) - bytes = count; - - status = -ENOMEM; - page = grab_cache_page(mapping, index); - if (!page) - break; - - kaddr = kmap(page); - status = mapping->a_ops->prepare_write(NULL, page, offset, - offset + bytes); - if (status) { - goto unlock; - } - - memset((void *) (kaddr + offset), 0, bytes); - flush_dcache_page(page); - status = mapping->a_ops->commit_write(NULL, page, offset, - offset + bytes); - if (!status) { - pos += bytes; - count -= bytes; - if (pos > i_size_read(ip)) - i_size_write(ip, pos < end_size ? pos : end_size); - } - -unlock: - kunmap(page); - unlock_page(page); - page_cache_release(page); - if (status) - break; - } while (count); - - return (-status); -} - -/* - * xfs_inval_cached_pages - * - * This routine is responsible for keeping direct I/O and buffered I/O - * somewhat coherent. From here we make sure that we're at least - * temporarily holding the inode I/O lock exclusively and then call - * the page cache to flush and invalidate any cached pages. If there - * are no cached pages this routine will be very quick. - */ -void -xfs_inval_cached_pages( - vnode_t *vp, - xfs_iocore_t *io, - xfs_off_t offset, - int write, - int relock) -{ - xfs_mount_t *mp; - - if (!VN_CACHED(vp)) { - return; - } - - mp = io->io_mount; - - /* - * We need to get the I/O lock exclusively in order - * to safely invalidate pages and mappings. - */ - if (relock) { - XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); - XFS_ILOCK(mp, io, XFS_IOLOCK_EXCL); - } - - /* Writing beyond EOF creates a hole that must be zeroed */ - if (write && (offset > XFS_SIZE(mp, io))) { - xfs_fsize_t isize; - - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - isize = XFS_SIZE(mp, io); - if (offset > isize) { - xfs_zero_eof(vp, io, offset, isize, offset); - } - XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - } - - xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1); - VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); - if (relock) { - XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL); - } -} - -ssize_t /* bytes read, or (-) error */ -xfs_read( - bhv_desc_t *bdp, - struct kiocb *iocb, - const struct iovec *iovp, - unsigned int segs, - loff_t *offset, - int ioflags, - cred_t *credp) -{ - struct file *file = iocb->ki_filp; - size_t size = 0; - ssize_t ret; - xfs_fsize_t n; - xfs_inode_t *ip; - xfs_mount_t *mp; - vnode_t *vp; - unsigned long seg; - - ip = XFS_BHVTOI(bdp); - vp = BHV_TO_VNODE(bdp); - mp = ip->i_mount; - - XFS_STATS_INC(xs_read_calls); - - /* START copy & waste from filemap.c */ - for (seg = 0; seg < segs; seg++) { - const struct iovec *iv = &iovp[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - size += iv->iov_len; - if (unlikely((ssize_t)(size|iv->iov_len) < 0)) - return XFS_ERROR(-EINVAL); - } - /* END copy & waste from filemap.c */ - - if (ioflags & IO_ISDIRECT) { - xfs_buftarg_t *target = - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? - mp->m_rtdev_targp : mp->m_ddev_targp; - if ((*offset & target->pbr_smask) || - (size & target->pbr_smask)) { - if (*offset == ip->i_d.di_size) { - return (0); - } - return -XFS_ERROR(EINVAL); - } - } - - n = XFS_MAXIOFFSET(mp) - *offset; - if ((n <= 0) || (size == 0)) - return 0; - - if (n < size) - size = n; - - if (XFS_FORCED_SHUTDOWN(mp)) { - return -EIO; - } - - /* OK so we are holding the I/O lock for the duration - * of the submission, then what happens if the I/O - * does not really happen here, but is scheduled - * later? - */ - xfs_ilock(ip, XFS_IOLOCK_SHARED); - - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && - !(ioflags & IO_INVIS)) { - vrwlock_t locktype = VRWLOCK_READ; - - ret = XFS_SEND_DATA(mp, DM_EVENT_READ, - BHV_TO_VNODE(bdp), *offset, size, - FILP_DELAY_FLAG(file), &locktype); - if (ret) { - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - return -ret; - } - } - - xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, - iovp, segs, *offset, ioflags); - ret = __generic_file_aio_read(iocb, iovp, segs, offset); - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - - if (ret > 0) - XFS_STATS_ADD(xs_read_bytes, ret); - - if (likely(!(ioflags & IO_INVIS))) - xfs_ichgtime(ip, XFS_ICHGTIME_ACC); - - return ret; -} - -ssize_t -xfs_sendfile( - bhv_desc_t *bdp, - struct file *filp, - loff_t *offset, - int ioflags, - size_t count, - read_actor_t actor, - void *target, - cred_t *credp) -{ - ssize_t ret; - xfs_fsize_t n; - xfs_inode_t *ip; - xfs_mount_t *mp; - vnode_t *vp; - - ip = XFS_BHVTOI(bdp); - vp = BHV_TO_VNODE(bdp); - mp = ip->i_mount; - - XFS_STATS_INC(xs_read_calls); - - n = XFS_MAXIOFFSET(mp) - *offset; - if ((n <= 0) || (count == 0)) - return 0; - - if (n < count) - count = n; - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EIO; - - xfs_ilock(ip, XFS_IOLOCK_SHARED); - - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && - (!(ioflags & IO_INVIS))) { - vrwlock_t locktype = VRWLOCK_READ; - int error; - - error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, count, - FILP_DELAY_FLAG(filp), &locktype); - if (error) { - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - return -error; - } - } - xfs_rw_enter_trace(XFS_SENDFILE_ENTER, &ip->i_iocore, - target, count, *offset, ioflags); - ret = generic_file_sendfile(filp, offset, count, actor, target); - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - - XFS_STATS_ADD(xs_read_bytes, ret); - xfs_ichgtime(ip, XFS_ICHGTIME_ACC); - return ret; -} - -/* - * This routine is called to handle zeroing any space in the last - * block of the file that is beyond the EOF. We do this since the - * size is being increased without writing anything to that block - * and we don't want anyone to read the garbage on the disk. - */ -STATIC int /* error (positive) */ -xfs_zero_last_block( - struct inode *ip, - xfs_iocore_t *io, - xfs_off_t offset, - xfs_fsize_t isize, - xfs_fsize_t end_size) -{ - xfs_fileoff_t last_fsb; - xfs_mount_t *mp; - int nimaps; - int zero_offset; - int zero_len; - int isize_fsb_offset; - int error = 0; - xfs_bmbt_irec_t imap; - loff_t loff; - size_t lsize; - - ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); - ASSERT(offset > isize); - - mp = io->io_mount; - - isize_fsb_offset = XFS_B_FSB_OFFSET(mp, isize); - if (isize_fsb_offset == 0) { - /* - * There are no extra bytes in the last block on disk to - * zero, so return. - */ - return 0; - } - - last_fsb = XFS_B_TO_FSBT(mp, isize); - nimaps = 1; - error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, - &nimaps, NULL); - if (error) { - return error; - } - ASSERT(nimaps > 0); - /* - * If the block underlying isize is just a hole, then there - * is nothing to zero. - */ - if (imap.br_startblock == HOLESTARTBLOCK) { - return 0; - } - /* - * Zero the part of the last block beyond the EOF, and write it - * out sync. We need to drop the ilock while we do this so we - * don't deadlock when the buffer cache calls back to us. - */ - XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); - loff = XFS_FSB_TO_B(mp, last_fsb); - lsize = XFS_FSB_TO_B(mp, 1); - - zero_offset = isize_fsb_offset; - zero_len = mp->m_sb.sb_blocksize - isize_fsb_offset; - - error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size); - - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - ASSERT(error >= 0); - return error; -} - -/* - * Zero any on disk space between the current EOF and the new, - * larger EOF. This handles the normal case of zeroing the remainder - * of the last block in the file and the unusual case of zeroing blocks - * out beyond the size of the file. This second case only happens - * with fixed size extents and when the system crashes before the inode - * size was updated but after blocks were allocated. If fill is set, - * then any holes in the range are filled and zeroed. If not, the holes - * are left alone as holes. - */ - -int /* error (positive) */ -xfs_zero_eof( - vnode_t *vp, - xfs_iocore_t *io, - xfs_off_t offset, /* starting I/O offset */ - xfs_fsize_t isize, /* current inode size */ - xfs_fsize_t end_size) /* terminal inode size */ -{ - struct inode *ip = LINVFS_GET_IP(vp); - xfs_fileoff_t start_zero_fsb; - xfs_fileoff_t end_zero_fsb; - xfs_fileoff_t prev_zero_fsb; - xfs_fileoff_t zero_count_fsb; - xfs_fileoff_t last_fsb; - xfs_extlen_t buf_len_fsb; - xfs_extlen_t prev_zero_count; - xfs_mount_t *mp; - int nimaps; - int error = 0; - xfs_bmbt_irec_t imap; - loff_t loff; - size_t lsize; - - ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); - - mp = io->io_mount; - - /* - * First handle zeroing the block on which isize resides. - * We only zero a part of that block so it is handled specially. - */ - error = xfs_zero_last_block(ip, io, offset, isize, end_size); - if (error) { - ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); - return error; - } - - /* - * Calculate the range between the new size and the old - * where blocks needing to be zeroed may exist. To get the - * block where the last byte in the file currently resides, - * we need to subtract one from the size and truncate back - * to a block boundary. We subtract 1 in case the size is - * exactly on a block boundary. - */ - last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1; - start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); - end_zero_fsb = XFS_B_TO_FSBT(mp, offset - 1); - ASSERT((xfs_sfiloff_t)last_fsb < (xfs_sfiloff_t)start_zero_fsb); - if (last_fsb == end_zero_fsb) { - /* - * The size was only incremented on its last block. - * We took care of that above, so just return. - */ - return 0; - } - - ASSERT(start_zero_fsb <= end_zero_fsb); - prev_zero_fsb = NULLFILEOFF; - prev_zero_count = 0; - while (start_zero_fsb <= end_zero_fsb) { - nimaps = 1; - zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; - error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, - 0, NULL, 0, &imap, &nimaps, NULL); - if (error) { - ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); - return error; - } - ASSERT(nimaps > 0); - - if (imap.br_state == XFS_EXT_UNWRITTEN || - imap.br_startblock == HOLESTARTBLOCK) { - /* - * This loop handles initializing pages that were - * partially initialized by the code below this - * loop. It basically zeroes the part of the page - * that sits on a hole and sets the page as P_HOLE - * and calls remapf if it is a mapped file. - */ - prev_zero_fsb = NULLFILEOFF; - prev_zero_count = 0; - start_zero_fsb = imap.br_startoff + - imap.br_blockcount; - ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); - continue; - } - - /* - * There are blocks in the range requested. - * Zero them a single write at a time. We actually - * don't zero the entire range returned if it is - * too big and simply loop around to get the rest. - * That is not the most efficient thing to do, but it - * is simple and this path should not be exercised often. - */ - buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount, - mp->m_writeio_blocks << 8); - /* - * Drop the inode lock while we're doing the I/O. - * We'll still have the iolock to protect us. - */ - XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - - loff = XFS_FSB_TO_B(mp, start_zero_fsb); - lsize = XFS_FSB_TO_B(mp, buf_len_fsb); - - error = xfs_iozero(ip, loff, lsize, end_size); - - if (error) { - goto out_lock; - } - - prev_zero_fsb = start_zero_fsb; - prev_zero_count = buf_len_fsb; - start_zero_fsb = imap.br_startoff + buf_len_fsb; - ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); - - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - } - - return 0; - -out_lock: - - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - ASSERT(error >= 0); - return error; -} - -ssize_t /* bytes written, or (-) error */ -xfs_write( - bhv_desc_t *bdp, - struct kiocb *iocb, - const struct iovec *iovp, - unsigned int segs, - loff_t *offset, - int ioflags, - cred_t *credp) -{ - struct file *file = iocb->ki_filp; - size_t size = 0; - xfs_inode_t *xip; - xfs_mount_t *mp; - ssize_t ret; - int error = 0; - xfs_fsize_t isize, new_size; - xfs_fsize_t n, limit; - xfs_iocore_t *io; - vnode_t *vp; - unsigned long seg; - int iolock; - int eventsent = 0; - vrwlock_t locktype; - - XFS_STATS_INC(xs_write_calls); - - vp = BHV_TO_VNODE(bdp); - xip = XFS_BHVTOI(bdp); - - /* START copy & waste from filemap.c */ - for (seg = 0; seg < segs; seg++) { - const struct iovec *iv = &iovp[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - size += iv->iov_len; - if (unlikely((ssize_t)(size|iv->iov_len) < 0)) - return XFS_ERROR(-EINVAL); - } - /* END copy & waste from filemap.c */ - - if (size == 0) - return 0; - - io = &xip->i_iocore; - mp = io->io_mount; - - if (XFS_FORCED_SHUTDOWN(mp)) { - return -EIO; - } - - if (ioflags & IO_ISDIRECT) { - xfs_buftarg_t *target = - (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? - mp->m_rtdev_targp : mp->m_ddev_targp; - - if ((*offset & target->pbr_smask) || - (size & target->pbr_smask)) { - return XFS_ERROR(-EINVAL); - } - iolock = XFS_IOLOCK_SHARED; - locktype = VRWLOCK_WRITE_DIRECT; - } else { - iolock = XFS_IOLOCK_EXCL; - locktype = VRWLOCK_WRITE; - } - - xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); - - isize = xip->i_d.di_size; - limit = XFS_MAXIOFFSET(mp); - - if (file->f_flags & O_APPEND) - *offset = isize; - -start: - n = limit - *offset; - if (n <= 0) { - xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); - return -EFBIG; - } - - if (n < size) - size = n; - - new_size = *offset + size; - if (new_size > isize) { - io->io_new_size = new_size; - } - - if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && - !(ioflags & IO_INVIS) && !eventsent)) { - loff_t savedsize = *offset; - int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); - - xfs_iunlock(xip, XFS_ILOCK_EXCL); - error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp, - *offset, size, - dmflags, &locktype); - if (error) { - xfs_iunlock(xip, iolock); - return -error; - } - xfs_ilock(xip, XFS_ILOCK_EXCL); - eventsent = 1; - - /* - * The iolock was dropped and reaquired in XFS_SEND_DATA - * so we have to recheck the size when appending. - * We will only "goto start;" once, since having sent the - * event prevents another call to XFS_SEND_DATA, which is - * what allows the size to change in the first place. - */ - if ((file->f_flags & O_APPEND) && - savedsize != xip->i_d.di_size) { - *offset = isize = xip->i_d.di_size; - goto start; - } - } - - /* - * On Linux, generic_file_write updates the times even if - * no data is copied in so long as the write had a size. - * - * We must update xfs' times since revalidate will overcopy xfs. - */ - if (size && !(ioflags & IO_INVIS)) - xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - - /* - * If the offset is beyond the size of the file, we have a couple - * of things to do. First, if there is already space allocated - * we need to either create holes or zero the disk or ... - * - * If there is a page where the previous size lands, we need - * to zero it out up to the new size. - */ - - if (!(ioflags & IO_ISDIRECT) && (*offset > isize && isize)) { - error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset, - isize, *offset + size); - if (error) { - xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); - return(-error); - } - } - xfs_iunlock(xip, XFS_ILOCK_EXCL); - - /* - * If we're writing the file then make sure to clear the - * setuid and setgid bits if the process is not being run - * by root. This keeps people from modifying setuid and - * setgid binaries. - */ - - if (((xip->i_d.di_mode & S_ISUID) || - ((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) == - (S_ISGID | S_IXGRP))) && - !capable(CAP_FSETID)) { - error = xfs_write_clear_setuid(xip); - if (error) { - xfs_iunlock(xip, iolock); - return -error; - } - } - -retry: - if (ioflags & IO_ISDIRECT) { - xfs_inval_cached_pages(vp, io, *offset, 1, 1); - xfs_rw_enter_trace(XFS_DIOWR_ENTER, - io, iovp, segs, *offset, ioflags); - } else { - xfs_rw_enter_trace(XFS_WRITE_ENTER, - io, iovp, segs, *offset, ioflags); - } - ret = generic_file_aio_write_nolock(iocb, iovp, segs, offset); - - if ((ret == -ENOSPC) && - DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && - !(ioflags & IO_INVIS)) { - - xfs_rwunlock(bdp, locktype); - error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, - DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, - 0, 0, 0); /* Delay flag intentionally unused */ - if (error) - return -error; - xfs_rwlock(bdp, locktype); - *offset = xip->i_d.di_size; - goto retry; - } - - if (*offset > xip->i_d.di_size) { - xfs_ilock(xip, XFS_ILOCK_EXCL); - if (*offset > xip->i_d.di_size) { - struct inode *inode = LINVFS_GET_IP(vp); - - xip->i_d.di_size = *offset; - i_size_write(inode, *offset); - xip->i_update_core = 1; - xip->i_update_size = 1; - } - xfs_iunlock(xip, XFS_ILOCK_EXCL); - } - - if (ret <= 0) { - xfs_rwunlock(bdp, locktype); - return ret; - } - - XFS_STATS_ADD(xs_write_bytes, ret); - - /* Handle various SYNC-type writes */ - if ((file->f_flags & O_SYNC) || IS_SYNC(file->f_dentry->d_inode)) { - - /* - * If we're treating this as O_DSYNC and we have not updated the - * size, force the log. - */ - - if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) - && !(xip->i_update_size)) { - /* - * If an allocation transaction occurred - * without extending the size, then we have to force - * the log up the proper point to ensure that the - * allocation is permanent. We can't count on - * the fact that buffered writes lock out direct I/O - * writes - the direct I/O write could have extended - * the size nontransactionally, then finished before - * we started. xfs_write_file will think that the file - * didn't grow but the update isn't safe unless the - * size change is logged. - * - * Force the log if we've committed a transaction - * against the inode or if someone else has and - * the commit record hasn't gone to disk (e.g. - * the inode is pinned). This guarantees that - * all changes affecting the inode are permanent - * when we return. - */ - - xfs_inode_log_item_t *iip; - xfs_lsn_t lsn; - - iip = xip->i_itemp; - if (iip && iip->ili_last_lsn) { - lsn = iip->ili_last_lsn; - xfs_log_force(mp, lsn, - XFS_LOG_FORCE | XFS_LOG_SYNC); - } else if (xfs_ipincount(xip) > 0) { - xfs_log_force(mp, (xfs_lsn_t)0, - XFS_LOG_FORCE | XFS_LOG_SYNC); - } - - } else { - xfs_trans_t *tp; - - /* - * O_SYNC or O_DSYNC _with_ a size update are handled - * the same way. - * - * If the write was synchronous then we need to make - * sure that the inode modification time is permanent. - * We'll have updated the timestamp above, so here - * we use a synchronous transaction to log the inode. - * It's not fast, but it's necessary. - * - * If this a dsync write and the size got changed - * non-transactionally, then we need to ensure that - * the size change gets logged in a synchronous - * transaction. - */ - - tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); - if ((error = xfs_trans_reserve(tp, 0, - XFS_SWRITE_LOG_RES(mp), - 0, 0, 0))) { - /* Transaction reserve failed */ - xfs_trans_cancel(tp, 0); - } else { - /* Transaction reserve successful */ - xfs_ilock(xip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL); - xfs_trans_ihold(tp, xip); - xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE); - xfs_trans_set_sync(tp); - error = xfs_trans_commit(tp, 0, (xfs_lsn_t)0); - xfs_iunlock(xip, XFS_ILOCK_EXCL); - } - } - } /* (ioflags & O_SYNC) */ - - xfs_rwunlock(bdp, locktype); - return(ret); -} - -/* - * All xfs metadata buffers except log state machine buffers - * get this attached as their b_bdstrat callback function. - * This is so that we can catch a buffer - * after prematurely unpinning it to forcibly shutdown the filesystem. - */ -int -xfs_bdstrat_cb(struct xfs_buf *bp) -{ - xfs_mount_t *mp; - - mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); - if (!XFS_FORCED_SHUTDOWN(mp)) { - pagebuf_iorequest(bp); - return 0; - } else { - xfs_buftrace("XFS__BDSTRAT IOERROR", bp); - /* - * Metadata write that didn't get logged but - * written delayed anyway. These aren't associated - * with a transaction, and can be ignored. - */ - if (XFS_BUF_IODONE_FUNC(bp) == NULL && - (XFS_BUF_ISREAD(bp)) == 0) - return (xfs_bioerror_relse(bp)); - else - return (xfs_bioerror(bp)); - } -} - - -int -xfs_bmap(bhv_desc_t *bdp, - xfs_off_t offset, - ssize_t count, - int flags, - xfs_iomap_t *iomapp, - int *niomaps) -{ - xfs_inode_t *ip = XFS_BHVTOI(bdp); - xfs_iocore_t *io = &ip->i_iocore; - - ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); - ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == - ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); - - return xfs_iomap(io, offset, count, flags, iomapp, niomaps); -} - -/* - * Wrapper around bdstrat so that we can stop data - * from going to disk in case we are shutting down the filesystem. - * Typically user data goes thru this path; one of the exceptions - * is the superblock. - */ -int -xfsbdstrat( - struct xfs_mount *mp, - struct xfs_buf *bp) -{ - ASSERT(mp); - if (!XFS_FORCED_SHUTDOWN(mp)) { - /* Grio redirection would go here - * if (XFS_BUF_IS_GRIO(bp)) { - */ - - pagebuf_iorequest(bp); - return 0; - } - - xfs_buftrace("XFSBDSTRAT IOERROR", bp); - return (xfs_bioerror_relse(bp)); -} - -/* - * If the underlying (data/log/rt) device is readonly, there are some - * operations that cannot proceed. - */ -int -xfs_dev_is_read_only( - xfs_mount_t *mp, - char *message) -{ - if (xfs_readonly_buftarg(mp->m_ddev_targp) || - xfs_readonly_buftarg(mp->m_logdev_targp) || - (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) { - cmn_err(CE_NOTE, - "XFS: %s required on read-only device.", message); - cmn_err(CE_NOTE, - "XFS: write access unavailable, cannot proceed."); - return EROFS; - } - return 0; -} diff --git a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h deleted file mode 100644 index faf0afc70..000000000 --- a/fs/xfs/linux/xfs_lrw.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_LRW_H__ -#define __XFS_LRW_H__ - -struct vnode; -struct bhv_desc; -struct xfs_mount; -struct xfs_iocore; -struct xfs_inode; -struct xfs_bmbt_irec; -struct xfs_buf; -struct xfs_iomap; - -#if defined(XFS_RW_TRACE) -/* - * Defines for the trace mechanisms in xfs_lrw.c. - */ -#define XFS_RW_KTRACE_SIZE 128 - -#define XFS_READ_ENTER 1 -#define XFS_WRITE_ENTER 2 -#define XFS_IOMAP_READ_ENTER 3 -#define XFS_IOMAP_WRITE_ENTER 4 -#define XFS_IOMAP_READ_MAP 5 -#define XFS_IOMAP_WRITE_MAP 6 -#define XFS_IOMAP_WRITE_NOSPACE 7 -#define XFS_ITRUNC_START 8 -#define XFS_ITRUNC_FINISH1 9 -#define XFS_ITRUNC_FINISH2 10 -#define XFS_CTRUNC1 11 -#define XFS_CTRUNC2 12 -#define XFS_CTRUNC3 13 -#define XFS_CTRUNC4 14 -#define XFS_CTRUNC5 15 -#define XFS_CTRUNC6 16 -#define XFS_BUNMAPI 17 -#define XFS_INVAL_CACHED 18 -#define XFS_DIORD_ENTER 19 -#define XFS_DIOWR_ENTER 20 -#define XFS_SENDFILE_ENTER 21 -#define XFS_WRITEPAGE_ENTER 22 -#define XFS_RELEASEPAGE_ENTER 23 -#define XFS_IOMAP_ALLOC_ENTER 24 -#define XFS_IOMAP_ALLOC_MAP 25 -#define XFS_IOMAP_UNWRITTEN 26 -extern void xfs_rw_enter_trace(int, struct xfs_iocore *, - const struct iovec *, size_t, loff_t, int); -extern void xfs_inval_cached_trace(struct xfs_iocore *, - xfs_off_t, xfs_off_t, xfs_off_t, xfs_off_t); -#else -#define xfs_rw_enter_trace(tag, io, iovec, segs, offset, ioflags) -#define xfs_inval_cached_trace(io, offset, len, first, last) -#endif - -/* - * Maximum count of bmaps used by read and write paths. - */ -#define XFS_MAX_RW_NBMAPS 4 - -extern int xfs_bmap(struct bhv_desc *, xfs_off_t, ssize_t, int, - struct xfs_iomap *, int *); -extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *); -extern int xfs_bdstrat_cb(struct xfs_buf *); - -extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t, - xfs_fsize_t, xfs_fsize_t); -extern void xfs_inval_cached_pages(struct vnode *, struct xfs_iocore *, - xfs_off_t, int, int); -extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, - loff_t *, int, size_t, read_actor_t, - void *, struct cred *); - -extern int xfs_dev_is_read_only(struct xfs_mount *, char *); - -#define XFS_FSB_TO_DB_IO(io,fsb) \ - (((io)->io_flags & XFS_IOCORE_RT) ? \ - XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ - XFS_FSB_TO_DADDR((io)->io_mount, (fsb))) - -#endif /* __XFS_LRW_H__ */ diff --git a/fs/xfs/linux/xfs_stats.c b/fs/xfs/linux/xfs_stats.c deleted file mode 100644 index b7de296e1..000000000 --- a/fs/xfs/linux/xfs_stats.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include - -DEFINE_PER_CPU(struct xfsstats, xfsstats); - -STATIC int -xfs_read_xfsstats( - char *buffer, - char **start, - off_t offset, - int count, - int *eof, - void *data) -{ - int c, i, j, len, val; - __uint64_t xs_xstrat_bytes = 0; - __uint64_t xs_write_bytes = 0; - __uint64_t xs_read_bytes = 0; - - static struct xstats_entry { - char *desc; - int endpoint; - } xstats[] = { - { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC }, - { "abt", XFSSTAT_END_ALLOC_BTREE }, - { "blk_map", XFSSTAT_END_BLOCK_MAPPING }, - { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE }, - { "dir", XFSSTAT_END_DIRECTORY_OPS }, - { "trans", XFSSTAT_END_TRANSACTIONS }, - { "ig", XFSSTAT_END_INODE_OPS }, - { "log", XFSSTAT_END_LOG_OPS }, - { "push_ail", XFSSTAT_END_TAIL_PUSHING }, - { "xstrat", XFSSTAT_END_WRITE_CONVERT }, - { "rw", XFSSTAT_END_READ_WRITE_OPS }, - { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, - { "icluster", XFSSTAT_END_INODE_CLUSTER }, - { "vnodes", XFSSTAT_END_VNODE_OPS }, - { "buf", XFSSTAT_END_BUF }, - }; - - /* Loop over all stats groups */ - for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) { - len += sprintf(buffer + len, xstats[i].desc); - /* inner loop does each group */ - while (j < xstats[i].endpoint) { - val = 0; - /* sum over all cpus */ - for (c = 0; c < NR_CPUS; c++) { - if (!cpu_possible(c)) continue; - val += *(((__u32*)&per_cpu(xfsstats, c) + j)); - } - len += sprintf(buffer + len, " %u", val); - j++; - } - buffer[len++] = '\n'; - } - /* extra precision counters */ - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) continue; - xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes; - xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes; - xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes; - } - - len += sprintf(buffer + len, "xpc %Lu %Lu %Lu\n", - xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); - len += sprintf(buffer + len, "debug %u\n", -#if defined(XFSDEBUG) - 1); -#else - 0); -#endif - - if (offset >= len) { - *start = buffer; - *eof = 1; - return 0; - } - *start = buffer + offset; - if ((len -= offset) > count) - return count; - *eof = 1; - - return len; -} - -void -xfs_init_procfs(void) -{ - if (!proc_mkdir("fs/xfs", 0)) - return; - create_proc_read_entry("fs/xfs/stat", 0, 0, xfs_read_xfsstats, NULL); -} - -void -xfs_cleanup_procfs(void) -{ - remove_proc_entry("fs/xfs/stat", NULL); - remove_proc_entry("fs/xfs", NULL); -} diff --git a/fs/xfs/linux/xfs_stats.h b/fs/xfs/linux/xfs_stats.h deleted file mode 100644 index 04566006f..000000000 --- a/fs/xfs/linux/xfs_stats.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_STATS_H__ -#define __XFS_STATS_H__ - - -#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF) - -#include - -/* - * XFS global statistics - */ -struct xfsstats { -# define XFSSTAT_END_EXTENT_ALLOC 4 - __uint32_t xs_allocx; - __uint32_t xs_allocb; - __uint32_t xs_freex; - __uint32_t xs_freeb; -# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) - __uint32_t xs_abt_lookup; - __uint32_t xs_abt_compare; - __uint32_t xs_abt_insrec; - __uint32_t xs_abt_delrec; -# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) - __uint32_t xs_blk_mapr; - __uint32_t xs_blk_mapw; - __uint32_t xs_blk_unmap; - __uint32_t xs_add_exlist; - __uint32_t xs_del_exlist; - __uint32_t xs_look_exlist; - __uint32_t xs_cmp_exlist; -# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) - __uint32_t xs_bmbt_lookup; - __uint32_t xs_bmbt_compare; - __uint32_t xs_bmbt_insrec; - __uint32_t xs_bmbt_delrec; -# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) - __uint32_t xs_dir_lookup; - __uint32_t xs_dir_create; - __uint32_t xs_dir_remove; - __uint32_t xs_dir_getdents; -# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) - __uint32_t xs_trans_sync; - __uint32_t xs_trans_async; - __uint32_t xs_trans_empty; -# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) - __uint32_t xs_ig_attempts; - __uint32_t xs_ig_found; - __uint32_t xs_ig_frecycle; - __uint32_t xs_ig_missed; - __uint32_t xs_ig_dup; - __uint32_t xs_ig_reclaims; - __uint32_t xs_ig_attrchg; -# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) - __uint32_t xs_log_writes; - __uint32_t xs_log_blocks; - __uint32_t xs_log_noiclogs; - __uint32_t xs_log_force; - __uint32_t xs_log_force_sleep; -# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) - __uint32_t xs_try_logspace; - __uint32_t xs_sleep_logspace; - __uint32_t xs_push_ail; - __uint32_t xs_push_ail_success; - __uint32_t xs_push_ail_pushbuf; - __uint32_t xs_push_ail_pinned; - __uint32_t xs_push_ail_locked; - __uint32_t xs_push_ail_flushing; - __uint32_t xs_push_ail_restarts; - __uint32_t xs_push_ail_flush; -# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) - __uint32_t xs_xstrat_quick; - __uint32_t xs_xstrat_split; -# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) - __uint32_t xs_write_calls; - __uint32_t xs_read_calls; -# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) - __uint32_t xs_attr_get; - __uint32_t xs_attr_set; - __uint32_t xs_attr_remove; - __uint32_t xs_attr_list; -# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_ATTRIBUTE_OPS+3) - __uint32_t xs_iflush_count; - __uint32_t xs_icluster_flushcnt; - __uint32_t xs_icluster_flushinode; -# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) - __uint32_t vn_active; /* # vnodes not on free lists */ - __uint32_t vn_alloc; /* # times vn_alloc called */ - __uint32_t vn_get; /* # times vn_get called */ - __uint32_t vn_hold; /* # times vn_hold called */ - __uint32_t vn_rele; /* # times vn_rele called */ - __uint32_t vn_reclaim; /* # times vn_reclaim called */ - __uint32_t vn_remove; /* # times vn_remove called */ - __uint32_t vn_free; /* # times vn_free called */ -#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9) - __uint32_t pb_get; - __uint32_t pb_create; - __uint32_t pb_get_locked; - __uint32_t pb_get_locked_waited; - __uint32_t pb_busy_locked; - __uint32_t pb_miss_locked; - __uint32_t pb_page_retries; - __uint32_t pb_page_found; - __uint32_t pb_get_read; -/* Extra precision counters */ - __uint64_t xs_xstrat_bytes; - __uint64_t xs_write_bytes; - __uint64_t xs_read_bytes; -}; - -DECLARE_PER_CPU(struct xfsstats, xfsstats); - -/* We don't disable preempt, not too worried about poking the - * wrong cpu's stat for now */ -#define XFS_STATS_INC(count) (__get_cpu_var(xfsstats).count++) -#define XFS_STATS_DEC(count) (__get_cpu_var(xfsstats).count--) -#define XFS_STATS_ADD(count, inc) (__get_cpu_var(xfsstats).count += (inc)) - -extern void xfs_init_procfs(void); -extern void xfs_cleanup_procfs(void); - - -#else /* !CONFIG_PROC_FS */ - -# define XFS_STATS_INC(count) -# define XFS_STATS_DEC(count) -# define XFS_STATS_ADD(count, inc) - -static __inline void xfs_init_procfs(void) { }; -static __inline void xfs_cleanup_procfs(void) { }; - -#endif /* !CONFIG_PROC_FS */ - -#endif /* __XFS_STATS_H__ */ diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c deleted file mode 100644 index bbaf61bee..000000000 --- a/fs/xfs/linux/xfs_super.c +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" - -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_clnt.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_quota.h" -#include "xfs_mount.h" -#include "xfs_alloc_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_attr_sf.h" -#include "xfs_dir_sf.h" -#include "xfs_dir2_sf.h" -#include "xfs_dinode.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bit.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_itable.h" -#include "xfs_rw.h" -#include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" -#include "xfs_attr.h" -#include "xfs_buf_item.h" -#include "xfs_utils.h" -#include "xfs_version.h" - -#include -#include -#include -#include - -STATIC struct quotactl_ops linvfs_qops; -STATIC struct super_operations linvfs_sops; -STATIC struct export_operations linvfs_export_ops; -STATIC kmem_cache_t * linvfs_inode_cachep; - -STATIC struct xfs_mount_args * -xfs_args_allocate( - struct super_block *sb) -{ - struct xfs_mount_args *args; - - args = kmem_zalloc(sizeof(struct xfs_mount_args), KM_SLEEP); - args->logbufs = args->logbufsize = -1; - strncpy(args->fsname, sb->s_id, MAXNAMELEN); - - /* Copy the already-parsed mount(2) flags we're interested in */ - if (sb->s_flags & MS_NOATIME) - args->flags |= XFSMNT_NOATIME; - - /* Default to 32 bit inodes on Linux all the time */ - args->flags |= XFSMNT_32BITINODES; - - return args; -} - -__uint64_t -xfs_max_file_offset( - unsigned int blockshift) -{ - unsigned int pagefactor = 1; - unsigned int bitshift = BITS_PER_LONG - 1; - - /* Figure out maximum filesize, on Linux this can depend on - * the filesystem blocksize (on 32 bit platforms). - * __block_prepare_write does this in an [unsigned] long... - * page->index << (PAGE_CACHE_SHIFT - bbits) - * So, for page sized blocks (4K on 32 bit platforms), - * this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is - * (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) - * but for smaller blocksizes it is less (bbits = log2 bsize). - * Note1: get_block_t takes a long (implicit cast from above) - * Note2: The Large Block Device (LBD and HAVE_SECTOR_T) patch - * can optionally convert the [unsigned] long from above into - * an [unsigned] long long. - */ - -#if BITS_PER_LONG == 32 -# if defined(CONFIG_LBD) - ASSERT(sizeof(sector_t) == 8); - pagefactor = PAGE_CACHE_SIZE; - bitshift = BITS_PER_LONG; -# else - pagefactor = PAGE_CACHE_SIZE >> (PAGE_CACHE_SHIFT - blockshift); -# endif -#endif - - return (((__uint64_t)pagefactor) << bitshift) - 1; -} - -STATIC __inline__ void -xfs_set_inodeops( - struct inode *inode) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - - if (vp->v_type == VNON) { - make_bad_inode(inode); - } else if (S_ISREG(inode->i_mode)) { - inode->i_op = &linvfs_file_inode_operations; - inode->i_fop = &linvfs_file_operations; - inode->i_mapping->a_ops = &linvfs_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &linvfs_dir_inode_operations; - inode->i_fop = &linvfs_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &linvfs_symlink_inode_operations; - if (inode->i_blocks) - inode->i_mapping->a_ops = &linvfs_aops; - } else { - inode->i_op = &linvfs_file_inode_operations; - init_special_inode(inode, inode->i_mode, inode->i_rdev); - } -} - -STATIC __inline__ void -xfs_revalidate_inode( - xfs_mount_t *mp, - vnode_t *vp, - xfs_inode_t *ip) -{ - struct inode *inode = LINVFS_GET_IP(vp); - - inode->i_mode = (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type); - inode->i_nlink = ip->i_d.di_nlink; - inode->i_uid = ip->i_d.di_uid; - inode->i_gid = ip->i_d.di_gid; - if (((1 << vp->v_type) & ((1<i_rdev = 0; - } else { - xfs_dev_t dev = ip->i_df.if_u2.if_rdev; - inode->i_rdev = MKDEV(sysv_major(dev) & 0x1ff, sysv_minor(dev)); - } - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_generation = ip->i_d.di_gen; - i_size_write(inode, ip->i_d.di_size); - inode->i_blocks = - XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); - inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; - inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; - inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; - inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; - inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; - inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; - if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (ip->i_d.di_flags & XFS_DIFLAG_SYNC) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; - vp->v_flag &= ~VMODIFIED; -} - -void -xfs_initialize_vnode( - bhv_desc_t *bdp, - vnode_t *vp, - bhv_desc_t *inode_bhv, - int unlock) -{ - xfs_inode_t *ip = XFS_BHVTOI(inode_bhv); - struct inode *inode = LINVFS_GET_IP(vp); - - if (!inode_bhv->bd_vobj) { - vp->v_vfsp = bhvtovfs(bdp); - bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops); - bhv_insert(VN_BHV_HEAD(vp), inode_bhv); - } - - vp->v_type = IFTOVT(ip->i_d.di_mode); - - /* Have we been called during the new inode create process, - * in which case we are too early to fill in the Linux inode. - */ - if (vp->v_type == VNON) - return; - - xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip); - - /* For new inodes we need to set the ops vectors, - * and unlock the inode. - */ - if (unlock && (inode->i_state & I_NEW)) { - xfs_set_inodeops(inode); - unlock_new_inode(inode); - } -} - -void -xfs_flush_inode( - xfs_inode_t *ip) -{ - struct inode *inode = LINVFS_GET_IP(XFS_ITOV(ip)); - - filemap_flush(inode->i_mapping); -} - -void -xfs_flush_device( - xfs_inode_t *ip) -{ - sync_blockdev(XFS_ITOV(ip)->v_vfsp->vfs_super->s_bdev); - xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); -} - -int -xfs_blkdev_get( - xfs_mount_t *mp, - const char *name, - struct block_device **bdevp) -{ - int error = 0; - - *bdevp = open_bdev_excl(name, 0, mp); - if (IS_ERR(*bdevp)) { - error = PTR_ERR(*bdevp); - printk("XFS: Invalid device [%s], error=%d\n", name, error); - } - - return -error; -} - -void -xfs_blkdev_put( - struct block_device *bdev) -{ - if (bdev) - close_bdev_excl(bdev); -} - - -STATIC struct inode * -linvfs_alloc_inode( - struct super_block *sb) -{ - vnode_t *vp; - - vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep, - kmem_flags_convert(KM_SLEEP)); - if (!vp) - return NULL; - return LINVFS_GET_IP(vp); -} - -STATIC void -linvfs_destroy_inode( - struct inode *inode) -{ - kmem_cache_free(linvfs_inode_cachep, LINVFS_GET_VP(inode)); -} - -STATIC void -init_once( - void *data, - kmem_cache_t *cachep, - unsigned long flags) -{ - vnode_t *vp = (vnode_t *)data; - - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) - inode_init_once(LINVFS_GET_IP(vp)); -} - -STATIC int -init_inodecache( void ) -{ - linvfs_inode_cachep = kmem_cache_create("linvfs_icache", - sizeof(vnode_t), 0, - SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, - init_once, NULL); - - if (linvfs_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -STATIC void -destroy_inodecache( void ) -{ - if (kmem_cache_destroy(linvfs_inode_cachep)) - printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__); -} - -/* - * Attempt to flush the inode, this will actually fail - * if the inode is pinned, but we dirty the inode again - * at the point when it is unpinned after a log write, - * since this is when the inode itself becomes flushable. - */ -STATIC void -linvfs_write_inode( - struct inode *inode, - int sync) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - int error, flags = FLUSH_INODE; - - if (vp) { - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - if (sync) - flags |= FLUSH_SYNC; - VOP_IFLUSH(vp, flags, error); - } -} - -STATIC void -linvfs_clear_inode( - struct inode *inode) -{ - vnode_t *vp = LINVFS_GET_VP(inode); - - if (vp) { - vn_rele(vp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); - /* - * Do all our cleanup, and remove this vnode. - */ - vn_remove(vp); - } -} - - -#define SYNCD_FLAGS (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR) - -STATIC int -xfssyncd( - void *arg) -{ - vfs_t *vfsp = (vfs_t *) arg; - int error; - - daemonize("xfssyncd"); - - vfsp->vfs_sync_task = current; - wmb(); - wake_up(&vfsp->vfs_wait_sync_task); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(xfs_syncd_interval); - /* swsusp */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); - if (vfsp->vfs_flag & VFS_UMOUNT) - break; - if (vfsp->vfs_flag & VFS_RDONLY) - continue; - VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error); - } - - vfsp->vfs_sync_task = NULL; - wmb(); - wake_up(&vfsp->vfs_wait_sync_task); - - return 0; -} - -STATIC int -linvfs_start_syncd( - vfs_t *vfsp) -{ - int pid; - - pid = kernel_thread(xfssyncd, (void *) vfsp, - CLONE_VM | CLONE_FS | CLONE_FILES); - if (pid < 0) - return -pid; - wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task); - return 0; -} - -STATIC void -linvfs_stop_syncd( - vfs_t *vfsp) -{ - vfsp->vfs_flag |= VFS_UMOUNT; - wmb(); - - wake_up_process(vfsp->vfs_sync_task); - wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task); -} - -STATIC void -linvfs_put_super( - struct super_block *sb) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - int error; - - linvfs_stop_syncd(vfsp); - VFS_SYNC(vfsp, SYNC_ATTR|SYNC_DELWRI, NULL, error); - if (!error) - VFS_UNMOUNT(vfsp, 0, NULL, error); - if (error) { - printk("XFS unmount got error %d\n", error); - printk("%s: vfsp/0x%p left dangling!\n", __FUNCTION__, vfsp); - return; - } - - vfs_deallocate(vfsp); -} - -STATIC void -linvfs_write_super( - struct super_block *sb) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - int error; - - if (sb->s_flags & MS_RDONLY) { - sb->s_dirt = 0; /* paranoia */ - return; - } - /* Push the log and superblock a little */ - VFS_SYNC(vfsp, SYNC_FSDATA, NULL, error); - sb->s_dirt = 0; -} - -STATIC int -linvfs_sync_super( - struct super_block *sb, - int wait) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - int error; - int flags = SYNC_FSDATA; - - if (wait) - flags |= SYNC_WAIT; - - VFS_SYNC(vfsp, flags, NULL, error); - sb->s_dirt = 0; - - return -error; -} - -STATIC int -linvfs_statfs( - struct super_block *sb, - struct kstatfs *statp) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - int error; - - VFS_STATVFS(vfsp, statp, NULL, error); - return -error; -} - -STATIC int -linvfs_remount( - struct super_block *sb, - int *flags, - char *options) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - struct xfs_mount_args *args = xfs_args_allocate(sb); - int error; - - VFS_PARSEARGS(vfsp, options, args, 1, error); - if (!error) - VFS_MNTUPDATE(vfsp, flags, args, error); - kmem_free(args, sizeof(*args)); - return -error; -} - -STATIC void -linvfs_freeze_fs( - struct super_block *sb) -{ - VFS_FREEZE(LINVFS_GET_VFS(sb)); -} - -STATIC struct dentry * -linvfs_get_parent( - struct dentry *child) -{ - int error; - vnode_t *vp, *cvp; - struct dentry *parent; - struct inode *ip = NULL; - struct dentry dotdot; - - dotdot.d_name.name = ".."; - dotdot.d_name.len = 2; - dotdot.d_inode = 0; - - cvp = NULL; - vp = LINVFS_GET_VP(child->d_inode); - VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error); - - if (!error) { - ASSERT(cvp); - ip = LINVFS_GET_IP(cvp); - if (!ip) { - VN_RELE(cvp); - return ERR_PTR(-EACCES); - } - } - if (error) - return ERR_PTR(-error); - parent = d_alloc_anon(ip); - if (!parent) { - VN_RELE(cvp); - parent = ERR_PTR(-ENOMEM); - } - return parent; -} - -STATIC struct dentry * -linvfs_get_dentry( - struct super_block *sb, - void *data) -{ - vnode_t *vp; - struct inode *inode; - struct dentry *result; - xfs_fid2_t xfid; - vfs_t *vfsp = LINVFS_GET_VFS(sb); - int error; - - xfid.fid_len = sizeof(xfs_fid2_t) - sizeof(xfid.fid_len); - xfid.fid_pad = 0; - xfid.fid_gen = ((__u32 *)data)[1]; - xfid.fid_ino = ((__u32 *)data)[0]; - - VFS_VGET(vfsp, &vp, (fid_t *)&xfid, error); - if (error || vp == NULL) - return ERR_PTR(-ESTALE) ; - - inode = LINVFS_GET_IP(vp); - result = d_alloc_anon(inode); - if (!result) { - iput(inode); - return ERR_PTR(-ENOMEM); - } - return result; -} - -STATIC int -linvfs_show_options( - struct seq_file *m, - struct vfsmount *mnt) -{ - struct vfs *vfsp = LINVFS_GET_VFS(mnt->mnt_sb); - int error; - - VFS_SHOWARGS(vfsp, m, error); - return error; -} - -STATIC int -linvfs_getxstate( - struct super_block *sb, - struct fs_quota_stat *fqs) -{ - struct vfs *vfsp = LINVFS_GET_VFS(sb); - int error; - - VFS_QUOTACTL(vfsp, Q_XGETQSTAT, 0, (caddr_t)fqs, error); - return -error; -} - -STATIC int -linvfs_setxstate( - struct super_block *sb, - unsigned int flags, - int op) -{ - struct vfs *vfsp = LINVFS_GET_VFS(sb); - int error; - - VFS_QUOTACTL(vfsp, op, 0, (caddr_t)&flags, error); - return -error; -} - -STATIC int -linvfs_getxquota( - struct super_block *sb, - int type, - qid_t id, - struct fs_disk_quota *fdq) -{ - struct vfs *vfsp = LINVFS_GET_VFS(sb); - int error, getmode; - - getmode = (type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETQUOTA; - VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error); - return -error; -} - -STATIC int -linvfs_setxquota( - struct super_block *sb, - int type, - qid_t id, - struct fs_disk_quota *fdq) -{ - struct vfs *vfsp = LINVFS_GET_VFS(sb); - int error, setmode; - - setmode = (type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETQLIM; - VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error); - return -error; -} - -STATIC int -linvfs_fill_super( - struct super_block *sb, - void *data, - int silent) -{ - vnode_t *rootvp; - struct vfs *vfsp = vfs_allocate(); - struct xfs_mount_args *args = xfs_args_allocate(sb); - struct kstatfs statvfs; - int error, error2; - - vfsp->vfs_super = sb; - LINVFS_SET_VFS(sb, vfsp); - if (sb->s_flags & MS_RDONLY) - vfsp->vfs_flag |= VFS_RDONLY; - bhv_insert_all_vfsops(vfsp); - - VFS_PARSEARGS(vfsp, (char *)data, args, 0, error); - if (error) { - bhv_remove_all_vfsops(vfsp, 1); - goto fail_vfsop; - } - - sb_min_blocksize(sb, BBSIZE); - sb->s_export_op = &linvfs_export_ops; - sb->s_qcop = &linvfs_qops; - sb->s_op = &linvfs_sops; - - VFS_MOUNT(vfsp, args, NULL, error); - if (error) { - bhv_remove_all_vfsops(vfsp, 1); - goto fail_vfsop; - } - - VFS_STATVFS(vfsp, &statvfs, NULL, error); - if (error) - goto fail_unmount; - - sb->s_dirt = 1; - sb->s_magic = statvfs.f_type; - sb->s_blocksize = statvfs.f_bsize; - sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; - sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); - set_posix_acl_flag(sb); - - VFS_ROOT(vfsp, &rootvp, error); - if (error) - goto fail_unmount; - - sb->s_root = d_alloc_root(LINVFS_GET_IP(rootvp)); - if (!sb->s_root) { - error = ENOMEM; - goto fail_vnrele; - } - if (is_bad_inode(sb->s_root->d_inode)) { - error = EINVAL; - goto fail_vnrele; - } - if ((error = linvfs_start_syncd(vfsp))) - goto fail_vnrele; - vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address); - - kmem_free(args, sizeof(*args)); - return 0; - -fail_vnrele: - if (sb->s_root) { - dput(sb->s_root); - sb->s_root = NULL; - } else { - VN_RELE(rootvp); - } - -fail_unmount: - VFS_UNMOUNT(vfsp, 0, NULL, error2); - -fail_vfsop: - vfs_deallocate(vfsp); - kmem_free(args, sizeof(*args)); - return -error; -} - -STATIC struct super_block * -linvfs_get_sb( - struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *data) -{ - return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super); -} - - -STATIC struct export_operations linvfs_export_ops = { - .get_parent = linvfs_get_parent, - .get_dentry = linvfs_get_dentry, -}; - -STATIC struct super_operations linvfs_sops = { - .alloc_inode = linvfs_alloc_inode, - .destroy_inode = linvfs_destroy_inode, - .write_inode = linvfs_write_inode, - .clear_inode = linvfs_clear_inode, - .put_super = linvfs_put_super, - .write_super = linvfs_write_super, - .sync_fs = linvfs_sync_super, - .write_super_lockfs = linvfs_freeze_fs, - .statfs = linvfs_statfs, - .remount_fs = linvfs_remount, - .show_options = linvfs_show_options, -}; - -STATIC struct quotactl_ops linvfs_qops = { - .get_xstate = linvfs_getxstate, - .set_xstate = linvfs_setxstate, - .get_xquota = linvfs_getxquota, - .set_xquota = linvfs_setxquota, -}; - -STATIC struct file_system_type xfs_fs_type = { - .owner = THIS_MODULE, - .name = "xfs", - .get_sb = linvfs_get_sb, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - - -STATIC int __init -init_xfs_fs( void ) -{ - int error; - struct sysinfo si; - static char message[] __initdata = KERN_INFO \ - XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled\n"; - - printk(message); - - si_meminfo(&si); - xfs_physmem = si.totalram; - - ktrace_init(64); - - error = init_inodecache(); - if (error < 0) - goto undo_inodecache; - - error = pagebuf_init(); - if (error < 0) - goto undo_pagebuf; - - vn_init(); - xfs_init(); - uuid_init(); - vfs_initdmapi(); - vfs_initquota(); - - error = register_filesystem(&xfs_fs_type); - if (error) - goto undo_register; - return 0; - -undo_register: - pagebuf_terminate(); - -undo_pagebuf: - destroy_inodecache(); - -undo_inodecache: - return error; -} - -STATIC void __exit -exit_xfs_fs( void ) -{ - vfs_exitquota(); - vfs_exitdmapi(); - unregister_filesystem(&xfs_fs_type); - xfs_cleanup(); - pagebuf_terminate(); - destroy_inodecache(); - ktrace_uninit(); -} - -module_init(init_xfs_fs); -module_exit(exit_xfs_fs); - -MODULE_AUTHOR("Silicon Graphics, Inc."); -MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); -MODULE_LICENSE("GPL"); diff --git a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h deleted file mode 100644 index 557626919..000000000 --- a/fs/xfs/linux/xfs_super.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_SUPER_H__ -#define __XFS_SUPER_H__ - -#ifdef CONFIG_XFS_DMAPI -# define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops) -# define vfs_initdmapi() dmapi_init() -# define vfs_exitdmapi() dmapi_uninit() -#else -# define vfs_insertdmapi(vfs) do { } while (0) -# define vfs_initdmapi() do { } while (0) -# define vfs_exitdmapi() do { } while (0) -#endif - -#ifdef CONFIG_XFS_QUOTA -# define vfs_insertquota(vfs) vfs_insertops(vfsp, &xfs_qmops) -extern void xfs_qm_init(void); -extern void xfs_qm_exit(void); -# define vfs_initquota() xfs_qm_init() -# define vfs_exitquota() xfs_qm_exit() -#else -# define vfs_insertquota(vfs) do { } while (0) -# define vfs_initquota() do { } while (0) -# define vfs_exitquota() do { } while (0) -#endif - -#ifdef CONFIG_XFS_POSIX_ACL -# define XFS_ACL_STRING "ACLs, " -# define set_posix_acl_flag(sb) ((sb)->s_flags |= MS_POSIXACL) -#else -# define XFS_ACL_STRING -# define set_posix_acl_flag(sb) do { } while (0) -#endif - -#ifdef CONFIG_XFS_SECURITY -# define XFS_SECURITY_STRING "security attributes, " -# define ENOSECURITY 0 -#else -# define XFS_SECURITY_STRING -# define ENOSECURITY EOPNOTSUPP -#endif - -#ifdef CONFIG_XFS_RT -# define XFS_REALTIME_STRING "realtime, " -#else -# define XFS_REALTIME_STRING -#endif - -#if XFS_BIG_BLKNOS -# if XFS_BIG_INUMS -# define XFS_BIGFS_STRING "large block/inode numbers, " -# else -# define XFS_BIGFS_STRING "large block numbers, " -# endif -#else -# define XFS_BIGFS_STRING -#endif - -#ifdef CONFIG_XFS_TRACE -# define XFS_TRACE_STRING "tracing, " -#else -# define XFS_TRACE_STRING -#endif - -#ifdef XFSDEBUG -# define XFS_DBG_STRING "debug" -#else -# define XFS_DBG_STRING "no debug" -#endif - -#define XFS_BUILD_OPTIONS XFS_ACL_STRING \ - XFS_SECURITY_STRING \ - XFS_REALTIME_STRING \ - XFS_BIGFS_STRING \ - XFS_TRACE_STRING \ - XFS_DBG_STRING /* DBG must be last */ - -#define LINVFS_GET_VFS(s) \ - (vfs_t *)((s)->s_fs_info) -#define LINVFS_SET_VFS(s, vfsp) \ - ((s)->s_fs_info = vfsp) - -struct xfs_inode; -struct xfs_mount; -struct xfs_buftarg; -struct block_device; - -extern __uint64_t xfs_max_file_offset(unsigned int); - -extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int); - -extern void xfs_flush_inode(struct xfs_inode *); -extern void xfs_flush_device(struct xfs_inode *); - -extern int xfs_blkdev_get(struct xfs_mount *, const char *, - struct block_device **); -extern void xfs_blkdev_put(struct block_device *); - -#endif /* __XFS_SUPER_H__ */ diff --git a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c deleted file mode 100644 index b9a97c9d7..000000000 --- a/fs/xfs/linux/xfs_sysctl.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include "xfs_rw.h" -#include -#include - - -static struct ctl_table_header *xfs_table_header; - - -#ifdef CONFIG_PROC_FS -STATIC int -xfs_stats_clear_proc_handler( - ctl_table *ctl, - int write, - struct file *filp, - void *buffer, - size_t *lenp) -{ - int c, ret, *valp = ctl->data; - __uint32_t vn_active; - - ret = proc_dointvec_minmax(ctl, write, filp, buffer, lenp); - - if (!ret && write && *valp) { - printk("XFS Clearing xfsstats\n"); - for (c = 0; c < NR_CPUS; c++) { - if (!cpu_possible(c)) continue; - preempt_disable(); - /* save vn_active, it's a universal truth! */ - vn_active = per_cpu(xfsstats, c).vn_active; - memset(&per_cpu(xfsstats, c), 0, - sizeof(struct xfsstats)); - per_cpu(xfsstats, c).vn_active = vn_active; - preempt_enable(); - } - xfs_stats_clear = 0; - } - - return ret; -} -#endif /* CONFIG_PROC_FS */ - -STATIC ctl_table xfs_table[] = { - {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.restrict_chown.min, &xfs_params.restrict_chown.max}, - - {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.sgid_inherit.min, &xfs_params.sgid_inherit.max}, - - {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.symlink_mode.min, &xfs_params.symlink_mode.max}, - - {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.panic_mask.min, &xfs_params.panic_mask.max}, - - {XFS_ERRLEVEL, "error_level", &xfs_params.error_level.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.error_level.min, &xfs_params.error_level.max}, - - {XFS_SYNC_INTERVAL, "sync_interval", &xfs_params.sync_interval.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.sync_interval.min, &xfs_params.sync_interval.max}, - - {XFS_INHERIT_SYNC, "inherit_sync", &xfs_params.inherit_sync.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_sync.min, &xfs_params.inherit_sync.max}, - - {XFS_INHERIT_NODUMP, "inherit_nodump", &xfs_params.inherit_nodump.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_nodump.min, &xfs_params.inherit_nodump.max}, - - {XFS_INHERIT_NOATIME, "inherit_noatime", &xfs_params.inherit_noatim.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max}, - - {XFS_FLUSH_INTERVAL, "flush_interval", &xfs_params.flush_interval.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.flush_interval.min, &xfs_params.flush_interval.max}, - - {XFS_AGE_BUFFER, "age_buffer", &xfs_params.age_buffer.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.age_buffer.min, &xfs_params.age_buffer.max}, - - /* please keep this the last entry */ -#ifdef CONFIG_PROC_FS - {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, - sizeof(int), 0644, NULL, &xfs_stats_clear_proc_handler, - &sysctl_intvec, NULL, - &xfs_params.stats_clear.min, &xfs_params.stats_clear.max}, -#endif /* CONFIG_PROC_FS */ - - {0} -}; - -STATIC ctl_table xfs_dir_table[] = { - {FS_XFS, "xfs", NULL, 0, 0555, xfs_table}, - {0} -}; - -STATIC ctl_table xfs_root_table[] = { - {CTL_FS, "fs", NULL, 0, 0555, xfs_dir_table}, - {0} -}; - -void -xfs_sysctl_register(void) -{ - xfs_table_header = register_sysctl_table(xfs_root_table, 1); -} - -void -xfs_sysctl_unregister(void) -{ - if (xfs_table_header) - unregister_sysctl_table(xfs_table_header); -} diff --git a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h deleted file mode 100644 index 0532d4012..000000000 --- a/fs/xfs/linux/xfs_sysctl.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#ifndef __XFS_SYSCTL_H__ -#define __XFS_SYSCTL_H__ - -#include - -/* - * Tunable xfs parameters - */ - -typedef struct xfs_sysctl_val { - int min; - int val; - int max; -} xfs_sysctl_val_t; - -typedef struct xfs_param { - xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/ - xfs_sysctl_val_t sgid_inherit; /* Inherit S_ISGID bit if process' GID - * is not a member of the parent dir - * GID */ - xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */ - xfs_sysctl_val_t panic_mask; /* bitmask to cause panic on errors. */ - xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ - xfs_sysctl_val_t sync_interval; /* time between sync calls */ - xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ - xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */ - xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */ - xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */ - xfs_sysctl_val_t flush_interval;/* interval between runs of the - * delwri flush daemon. */ - xfs_sysctl_val_t age_buffer; /* time for buffer to age before - * we flush it. */ -} xfs_param_t; - -/* - * xfs_error_level: - * - * How much error reporting will be done when internal problems are - * encountered. These problems normally return an EFSCORRUPTED to their - * caller, with no other information reported. - * - * 0 No error reports - * 1 Report EFSCORRUPTED errors that will cause a filesystem shutdown - * 5 Report all EFSCORRUPTED errors (all of the above errors, plus any - * additional errors that are known to not cause shutdowns) - * - * xfs_panic_mask bit 0x8 turns the error reports into panics - */ - -enum { - XFS_RESTRICT_CHOWN = 3, - XFS_SGID_INHERIT = 4, - XFS_SYMLINK_MODE = 5, - XFS_PANIC_MASK = 6, - XFS_ERRLEVEL = 7, - XFS_SYNC_INTERVAL = 8, - XFS_STATS_CLEAR = 12, - XFS_INHERIT_SYNC = 13, - XFS_INHERIT_NODUMP = 14, - XFS_INHERIT_NOATIME = 15, - XFS_FLUSH_INTERVAL = 16, - XFS_AGE_BUFFER = 17, -}; - -extern xfs_param_t xfs_params; - -#ifdef CONFIG_SYSCTL -extern void xfs_sysctl_register(void); -extern void xfs_sysctl_unregister(void); -#else -# define xfs_sysctl_register() do { } while (0) -# define xfs_sysctl_unregister() do { } while (0) -#endif /* CONFIG_SYSCTL */ - -#endif /* __XFS_SYSCTL_H__ */ diff --git a/fs/xfs/linux/xfs_version.h b/fs/xfs/linux/xfs_version.h deleted file mode 100644 index 96f963944..000000000 --- a/fs/xfs/linux/xfs_version.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -/* - * Dummy file that can contain a timestamp to put into the - * XFS init string, to help users keep track of what they're - * running - */ - -#ifndef __XFS_VERSION_H__ -#define __XFS_VERSION_H__ - -#define XFS_VERSION_STRING "SGI XFS" - -#endif /* __XFS_VERSION_H__ */ diff --git a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c deleted file mode 100644 index 2b75cccdf..000000000 --- a/fs/xfs/linux/xfs_vfs.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_macros.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_clnt.h" -#include "xfs_trans.h" -#include "xfs_sb.h" -#include "xfs_ag.h" -#include "xfs_dir.h" -#include "xfs_dir2.h" -#include "xfs_imap.h" -#include "xfs_alloc.h" -#include "xfs_dmapi.h" -#include "xfs_mount.h" -#include "xfs_quota.h" - -int -vfs_mount( - struct bhv_desc *bdp, - struct xfs_mount_args *args, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_mount) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_mount)(next, args, cr)); -} - -int -vfs_parseargs( - struct bhv_desc *bdp, - char *s, - struct xfs_mount_args *args, - int f) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_parseargs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_parseargs)(next, s, args, f)); -} - -int -vfs_showargs( - struct bhv_desc *bdp, - struct seq_file *m) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_showargs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_showargs)(next, m)); -} - -int -vfs_unmount( - struct bhv_desc *bdp, - int fl, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_unmount) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_unmount)(next, fl, cr)); -} - -int -vfs_mntupdate( - struct bhv_desc *bdp, - int *fl, - struct xfs_mount_args *args) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_mntupdate) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_mntupdate)(next, fl, args)); -} - -int -vfs_root( - struct bhv_desc *bdp, - struct vnode **vpp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_root) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_root)(next, vpp)); -} - -int -vfs_statvfs( - struct bhv_desc *bdp, - xfs_statfs_t *sp, - struct vnode *vp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_statvfs) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_statvfs)(next, sp, vp)); -} - -int -vfs_sync( - struct bhv_desc *bdp, - int fl, - struct cred *cr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_sync) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_sync)(next, fl, cr)); -} - -int -vfs_vget( - struct bhv_desc *bdp, - struct vnode **vpp, - struct fid *fidp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_vget) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_vget)(next, vpp, fidp)); -} - -int -vfs_dmapiops( - struct bhv_desc *bdp, - caddr_t addr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_dmapiops) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_dmapiops)(next, addr)); -} - -int -vfs_quotactl( - struct bhv_desc *bdp, - int cmd, - int id, - caddr_t addr) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_quotactl) - next = BHV_NEXT(next); - return ((*bhvtovfsops(next)->vfs_quotactl)(next, cmd, id, addr)); -} - -void -vfs_init_vnode( - struct bhv_desc *bdp, - struct vnode *vp, - struct bhv_desc *bp, - int unlock) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_init_vnode) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_init_vnode)(next, vp, bp, unlock)); -} - -void -vfs_force_shutdown( - struct bhv_desc *bdp, - int fl, - char *file, - int line) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_force_shutdown) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line)); -} - -void -vfs_freeze( - struct bhv_desc *bdp) -{ - struct bhv_desc *next = bdp; - - ASSERT(next); - while (! (bhvtovfsops(next))->vfs_freeze) - next = BHV_NEXT(next); - ((*bhvtovfsops(next)->vfs_freeze)(next)); -} - -vfs_t * -vfs_allocate( void ) -{ - struct vfs *vfsp; - - vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP); - bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); - init_waitqueue_head(&vfsp->vfs_wait_sync_task); - return vfsp; -} - -void -vfs_deallocate( - struct vfs *vfsp) -{ - bhv_head_destroy(VFS_BHVHEAD(vfsp)); - kmem_free(vfsp, sizeof(vfs_t)); -} - -void -vfs_insertops( - struct vfs *vfsp, - struct bhv_vfsops *vfsops) -{ - struct bhv_desc *bdp; - - bdp = kmem_alloc(sizeof(struct bhv_desc), KM_SLEEP); - bhv_desc_init(bdp, NULL, vfsp, vfsops); - bhv_insert(&vfsp->vfs_bh, bdp); -} - -void -vfs_insertbhv( - struct vfs *vfsp, - struct bhv_desc *bdp, - struct vfsops *vfsops, - void *mount) -{ - bhv_desc_init(bdp, mount, vfsp, vfsops); - bhv_insert_initial(&vfsp->vfs_bh, bdp); -} - -void -bhv_remove_vfsops( - struct vfs *vfsp, - int pos) -{ - struct bhv_desc *bhv; - - bhv = bhv_lookup_range(&vfsp->vfs_bh, pos, pos); - if (!bhv) - return; - bhv_remove(&vfsp->vfs_bh, bhv); - kmem_free(bhv, sizeof(*bhv)); -} - -void -bhv_remove_all_vfsops( - struct vfs *vfsp, - int freebase) -{ - struct xfs_mount *mp; - - bhv_remove_vfsops(vfsp, VFS_POSITION_QM); - bhv_remove_vfsops(vfsp, VFS_POSITION_DM); - if (!freebase) - return; - mp = XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfsp), &xfs_vfsops)); - VFS_REMOVEBHV(vfsp, &mp->m_bhv); - xfs_mount_free(mp, 0); -} - -void -bhv_insert_all_vfsops( - struct vfs *vfsp) -{ - struct xfs_mount *mp; - - mp = xfs_mount_init(); - vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp); - vfs_insertdmapi(vfsp); - vfs_insertquota(vfsp); -} diff --git a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h deleted file mode 100644 index dc1cd1973..000000000 --- a/fs/xfs/linux/xfs_vfs.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ -#ifndef __XFS_VFS_H__ -#define __XFS_VFS_H__ - -#include -#include "xfs_fs.h" - -struct fid; -struct cred; -struct vnode; -struct kstatfs; -struct seq_file; -struct super_block; -struct xfs_mount_args; - -typedef struct kstatfs xfs_statfs_t; - -typedef struct vfs { - u_int vfs_flag; /* flags */ - xfs_fsid_t vfs_fsid; /* file system ID */ - xfs_fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ - bhv_head_t vfs_bh; /* head of vfs behavior chain */ - struct super_block *vfs_super; /* Linux superblock structure */ - struct task_struct *vfs_sync_task; - wait_queue_head_t vfs_wait_sync_task; -} vfs_t; - -#define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ - -#define bhvtovfs(bdp) ( (struct vfs *)BHV_VOBJ(bdp) ) -#define bhvtovfsops(bdp) ( (struct vfsops *)BHV_OPS(bdp) ) -#define VFS_BHVHEAD(vfs) ( &(vfs)->vfs_bh ) -#define VFS_REMOVEBHV(vfs, bdp) ( bhv_remove(VFS_BHVHEAD(vfs), bdp) ) - -#define VFS_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ -#define VFS_POSITION_TOP BHV_POSITION_TOP /* chain top */ -#define VFS_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ - -typedef enum { - VFS_BHV_UNKNOWN, /* not specified */ - VFS_BHV_XFS, /* xfs */ - VFS_BHV_DM, /* data migration */ - VFS_BHV_QM, /* quota manager */ - VFS_BHV_IO, /* IO path */ - VFS_BHV_END /* housekeeping end-of-range */ -} vfs_bhv_t; - -#define VFS_POSITION_XFS (BHV_POSITION_BASE) -#define VFS_POSITION_DM (VFS_POSITION_BASE+10) -#define VFS_POSITION_QM (VFS_POSITION_BASE+20) -#define VFS_POSITION_IO (VFS_POSITION_BASE+30) - -#define VFS_RDONLY 0x0001 /* read-only vfs */ -#define VFS_GRPID 0x0002 /* group-ID assigned from directory */ -#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ -#define VFS_UMOUNT 0x0008 /* unmount in progress */ -#define VFS_END 0x0008 /* max flag */ - -#define SYNC_ATTR 0x0001 /* sync attributes */ -#define SYNC_CLOSE 0x0002 /* close file system down */ -#define SYNC_DELWRI 0x0004 /* look at delayed writes */ -#define SYNC_WAIT 0x0008 /* wait for i/o to complete */ -#define SYNC_BDFLUSH 0x0010 /* BDFLUSH is calling -- don't block */ -#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ -#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ -#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ - -typedef int (*vfs_mount_t)(bhv_desc_t *, - struct xfs_mount_args *, struct cred *); -typedef int (*vfs_parseargs_t)(bhv_desc_t *, char *, - struct xfs_mount_args *, int); -typedef int (*vfs_showargs_t)(bhv_desc_t *, struct seq_file *); -typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, - struct xfs_mount_args *); -typedef int (*vfs_root_t)(bhv_desc_t *, struct vnode **); -typedef int (*vfs_statvfs_t)(bhv_desc_t *, xfs_statfs_t *, struct vnode *); -typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *); -typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); -typedef int (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t); -typedef void (*vfs_init_vnode_t)(bhv_desc_t *, - struct vnode *, bhv_desc_t *, int); -typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); -typedef void (*vfs_freeze_t)(bhv_desc_t *); - -typedef struct vfsops { - bhv_position_t vf_position; /* behavior chain position */ - vfs_mount_t vfs_mount; /* mount file system */ - vfs_parseargs_t vfs_parseargs; /* parse mount options */ - vfs_showargs_t vfs_showargs; /* unparse mount options */ - vfs_unmount_t vfs_unmount; /* unmount file system */ - vfs_mntupdate_t vfs_mntupdate; /* update file system options */ - vfs_root_t vfs_root; /* get root vnode */ - vfs_statvfs_t vfs_statvfs; /* file system statistics */ - vfs_sync_t vfs_sync; /* flush files */ - vfs_vget_t vfs_vget; /* get vnode from fid */ - vfs_dmapiops_t vfs_dmapiops; /* data migration */ - vfs_quotactl_t vfs_quotactl; /* disk quota */ - vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ - vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ - vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ -} vfsops_t; - -/* - * VFS's. Operates on vfs structure pointers (starts at bhv head). - */ -#define VHEAD(v) ((v)->vfs_fbhv) -#define VFS_MOUNT(v, ma,cr, rv) ((rv) = vfs_mount(VHEAD(v), ma,cr)) -#define VFS_PARSEARGS(v, o,ma,f, rv) ((rv) = vfs_parseargs(VHEAD(v), o,ma,f)) -#define VFS_SHOWARGS(v, m, rv) ((rv) = vfs_showargs(VHEAD(v), m)) -#define VFS_UNMOUNT(v, f, cr, rv) ((rv) = vfs_unmount(VHEAD(v), f,cr)) -#define VFS_MNTUPDATE(v, fl, args, rv) ((rv) = vfs_mntupdate(VHEAD(v), fl, args)) -#define VFS_ROOT(v, vpp, rv) ((rv) = vfs_root(VHEAD(v), vpp)) -#define VFS_STATVFS(v, sp,vp, rv) ((rv) = vfs_statvfs(VHEAD(v), sp,vp)) -#define VFS_SYNC(v, flag,cr, rv) ((rv) = vfs_sync(VHEAD(v), flag,cr)) -#define VFS_VGET(v, vpp,fidp, rv) ((rv) = vfs_vget(VHEAD(v), vpp,fidp)) -#define VFS_DMAPIOPS(v, p, rv) ((rv) = vfs_dmapiops(VHEAD(v), p)) -#define VFS_QUOTACTL(v, c,id,p, rv) ((rv) = vfs_quotactl(VHEAD(v), c,id,p)) -#define VFS_INIT_VNODE(v, vp,b,ul) ( vfs_init_vnode(VHEAD(v), vp,b,ul) ) -#define VFS_FORCE_SHUTDOWN(v, fl,f,l) ( vfs_force_shutdown(VHEAD(v), fl,f,l) ) -#define VFS_FREEZE(v) ( vfs_freeze(VHEAD(v)) ) - -/* - * PVFS's. Operates on behavior descriptor pointers. - */ -#define PVFS_MOUNT(b, ma,cr, rv) ((rv) = vfs_mount(b, ma,cr)) -#define PVFS_PARSEARGS(b, o,ma,f, rv) ((rv) = vfs_parseargs(b, o,ma,f)) -#define PVFS_SHOWARGS(b, m, rv) ((rv) = vfs_showargs(b, m)) -#define PVFS_UNMOUNT(b, f,cr, rv) ((rv) = vfs_unmount(b, f,cr)) -#define PVFS_MNTUPDATE(b, fl, args, rv) ((rv) = vfs_mntupdate(b, fl, args)) -#define PVFS_ROOT(b, vpp, rv) ((rv) = vfs_root(b, vpp)) -#define PVFS_STATVFS(b, sp,vp, rv) ((rv) = vfs_statvfs(b, sp,vp)) -#define PVFS_SYNC(b, flag,cr, rv) ((rv) = vfs_sync(b, flag,cr)) -#define PVFS_VGET(b, vpp,fidp, rv) ((rv) = vfs_vget(b, vpp,fidp)) -#define PVFS_DMAPIOPS(b, p, rv) ((rv) = vfs_dmapiops(b, p)) -#define PVFS_QUOTACTL(b, c,id,p, rv) ((rv) = vfs_quotactl(b, c,id,p)) -#define PVFS_INIT_VNODE(b, vp,b2,ul) ( vfs_init_vnode(b, vp,b2,ul) ) -#define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) ) -#define PVFS_FREEZE(b) ( vfs_freeze(b) ) - -extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); -extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); -extern int vfs_showargs(bhv_desc_t *, struct seq_file *); -extern int vfs_unmount(bhv_desc_t *, int, struct cred *); -extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); -extern int vfs_root(bhv_desc_t *, struct vnode **); -extern int vfs_statvfs(bhv_desc_t *, xfs_statfs_t *, struct vnode *); -extern int vfs_sync(bhv_desc_t *, int, struct cred *); -extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *); -extern int vfs_dmapiops(bhv_desc_t *, caddr_t); -extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); -extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); -extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); -extern void vfs_freeze(bhv_desc_t *); - -typedef struct bhv_vfsops { - struct vfsops bhv_common; - void * bhv_custom; -} bhv_vfsops_t; - -#define vfs_bhv_lookup(v, id) ( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) ) -#define vfs_bhv_custom(b) ( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom ) -#define vfs_bhv_set_custom(b,o) ( (b)->bhv_custom = (void *)(o)) -#define vfs_bhv_clr_custom(b) ( (b)->bhv_custom = NULL ) - -extern vfs_t *vfs_allocate(void); -extern void vfs_deallocate(vfs_t *); -extern void vfs_insertops(vfs_t *, bhv_vfsops_t *); -extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *); - -extern void bhv_insert_all_vfsops(struct vfs *); -extern void bhv_remove_all_vfsops(struct vfs *, int); -extern void bhv_remove_vfsops(struct vfs *, int); - -#endif /* __XFS_VFS_H__ */ diff --git a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c deleted file mode 100644 index 9240efb2b..000000000 --- a/fs/xfs/linux/xfs_vnode.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include "xfs.h" - - -uint64_t vn_generation; /* vnode generation number */ -spinlock_t vnumber_lock = SPIN_LOCK_UNLOCKED; - -/* - * Dedicated vnode inactive/reclaim sync semaphores. - * Prime number of hash buckets since address is used as the key. - */ -#define NVSYNC 37 -#define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) -sv_t vsync[NVSYNC]; - -/* - * Translate stat(2) file types to vnode types and vice versa. - * Aware of numeric order of S_IFMT and vnode type values. - */ -enum vtype iftovt_tab[] = { - VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, - VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON -}; - -u_short vttoif_tab[] = { - 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK -}; - - -void -vn_init(void) -{ - register sv_t *svp; - register int i; - - for (svp = vsync, i = 0; i < NVSYNC; i++, svp++) - init_sv(svp, SV_DEFAULT, "vsy", i); -} - -/* - * Clean a vnode of filesystem-specific data and prepare it for reuse. - */ -STATIC int -vn_reclaim( - struct vnode *vp) -{ - int error; - - XFS_STATS_INC(vn_reclaim); - vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address); - - /* - * Only make the VOP_RECLAIM call if there are behaviors - * to call. - */ - if (vp->v_fbhv) { - VOP_RECLAIM(vp, error); - if (error) - return -error; - } - ASSERT(vp->v_fbhv == NULL); - - VN_LOCK(vp); - vp->v_flag &= (VRECLM|VWAIT); - VN_UNLOCK(vp, 0); - - vp->v_type = VNON; - vp->v_fbhv = NULL; - -#ifdef XFS_VNODE_TRACE - ktrace_free(vp->v_trace); - vp->v_trace = NULL; -#endif - - return 0; -} - -STATIC void -vn_wakeup( - struct vnode *vp) -{ - VN_LOCK(vp); - if (vp->v_flag & VWAIT) - sv_broadcast(vptosync(vp)); - vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED); - VN_UNLOCK(vp, 0); -} - -int -vn_wait( - struct vnode *vp) -{ - VN_LOCK(vp); - if (vp->v_flag & (VINACT | VRECLM)) { - vp->v_flag |= VWAIT; - sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); - return 1; - } - VN_UNLOCK(vp, 0); - return 0; -} - -struct vnode * -vn_initialize( - struct inode *inode) -{ - struct vnode *vp = LINVFS_GET_VP(inode); - - XFS_STATS_INC(vn_active); - XFS_STATS_INC(vn_alloc); - - vp->v_flag = VMODIFIED; - spinlock_init(&vp->v_lock, "v_lock"); - - spin_lock(&vnumber_lock); - if (!++vn_generation) /* v_number shouldn't be zero */ - vn_generation++; - vp->v_number = vn_generation; - spin_unlock(&vnumber_lock); - - ASSERT(VN_CACHED(vp) == 0); - - /* Initialize the first behavior and the behavior chain head. */ - vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode"); - -#ifdef XFS_VNODE_TRACE - vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); - printk("Allocated VNODE_TRACE at 0x%p\n", vp->v_trace); -#endif /* XFS_VNODE_TRACE */ - - vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); - return vp; -} - -/* - * Get a reference on a vnode. - */ -vnode_t * -vn_get( - struct vnode *vp, - vmap_t *vmap) -{ - struct inode *inode; - - XFS_STATS_INC(vn_get); - inode = LINVFS_GET_IP(vp); - if (inode->i_state & I_FREEING) - return NULL; - - inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino); - if (!inode) /* Inode not present */ - return NULL; - - vn_trace_exit(vp, "vn_get", (inst_t *)__return_address); - - return vp; -} - -/* - * Revalidate the Linux inode from the vnode. - */ -int -vn_revalidate( - struct vnode *vp) -{ - struct inode *inode; - vattr_t va; - int error; - - vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address); - ASSERT(vp->v_fbhv != NULL); - - va.va_mask = XFS_AT_STAT|XFS_AT_XFLAGS; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (!error) { - inode = LINVFS_GET_IP(vp); - inode->i_mode = VTTOIF(va.va_type) | va.va_mode; - inode->i_nlink = va.va_nlink; - inode->i_uid = va.va_uid; - inode->i_gid = va.va_gid; - inode->i_blocks = va.va_nblocks; - inode->i_mtime = va.va_mtime; - inode->i_ctime = va.va_ctime; - inode->i_atime = va.va_atime; - if (va.va_xflags & XFS_XFLAG_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (va.va_xflags & XFS_XFLAG_APPEND) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (va.va_xflags & XFS_XFLAG_SYNC) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (va.va_xflags & XFS_XFLAG_NOATIME) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; - VUNMODIFY(vp); - } - return -error; -} - -/* - * purge a vnode from the cache - * At this point the vnode is guaranteed to have no references (vn_count == 0) - * The caller has to make sure that there are no ways someone could - * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock). - */ -void -vn_purge( - struct vnode *vp, - vmap_t *vmap) -{ - vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address); - -again: - /* - * Check whether vp has already been reclaimed since our caller - * sampled its version while holding a filesystem cache lock that - * its VOP_RECLAIM function acquires. - */ - VN_LOCK(vp); - if (vp->v_number != vmap->v_number) { - VN_UNLOCK(vp, 0); - return; - } - - /* - * If vp is being reclaimed or inactivated, wait until it is inert, - * then proceed. Can't assume that vnode is actually reclaimed - * just because the reclaimed flag is asserted -- a vn_alloc - * reclaim can fail. - */ - if (vp->v_flag & (VINACT | VRECLM)) { - ASSERT(vn_count(vp) == 0); - vp->v_flag |= VWAIT; - sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); - goto again; - } - - /* - * Another process could have raced in and gotten this vnode... - */ - if (vn_count(vp) > 0) { - VN_UNLOCK(vp, 0); - return; - } - - XFS_STATS_DEC(vn_active); - vp->v_flag |= VRECLM; - VN_UNLOCK(vp, 0); - - /* - * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells - * vp's filesystem to flush and invalidate all cached resources. - * When vn_reclaim returns, vp should have no private data, - * either in a system cache or attached to v_data. - */ - if (vn_reclaim(vp) != 0) - panic("vn_purge: cannot reclaim"); - - /* - * Wakeup anyone waiting for vp to be reclaimed. - */ - vn_wakeup(vp); -} - -/* - * Add a reference to a referenced vnode. - */ -struct vnode * -vn_hold( - struct vnode *vp) -{ - struct inode *inode; - - XFS_STATS_INC(vn_hold); - - VN_LOCK(vp); - inode = igrab(LINVFS_GET_IP(vp)); - ASSERT(inode); - VN_UNLOCK(vp, 0); - - return vp; -} - -/* - * Call VOP_INACTIVE on last reference. - */ -void -vn_rele( - struct vnode *vp) -{ - int vcnt; - int cache; - - XFS_STATS_INC(vn_rele); - - VN_LOCK(vp); - - vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address); - vcnt = vn_count(vp); - - /* - * Since we always get called from put_inode we know - * that i_count won't be decremented after we - * return. - */ - if (!vcnt) { - /* - * As soon as we turn this on, noone can find us in vn_get - * until we turn off VINACT or VRECLM - */ - vp->v_flag |= VINACT; - VN_UNLOCK(vp, 0); - - /* - * Do not make the VOP_INACTIVE call if there - * are no behaviors attached to the vnode to call. - */ - if (vp->v_fbhv) - VOP_INACTIVE(vp, NULL, cache); - - VN_LOCK(vp); - if (vp->v_flag & VWAIT) - sv_broadcast(vptosync(vp)); - - vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED); - } - - VN_UNLOCK(vp, 0); - - vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address); -} - -/* - * Finish the removal of a vnode. - */ -void -vn_remove( - struct vnode *vp) -{ - vmap_t vmap; - - /* Make sure we don't do this to the same vnode twice */ - if (!(vp->v_fbhv)) - return; - - XFS_STATS_INC(vn_remove); - vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address); - - /* - * After the following purge the vnode - * will no longer exist. - */ - VMAP(vp, vmap); - vn_purge(vp, &vmap); -} - - -#ifdef XFS_VNODE_TRACE - -#define KTRACE_ENTER(vp, vk, s, line, ra) \ - ktrace_enter( (vp)->v_trace, \ -/* 0 */ (void *)(__psint_t)(vk), \ -/* 1 */ (void *)(s), \ -/* 2 */ (void *)(__psint_t) line, \ -/* 3 */ (void *)(vn_count(vp)), \ -/* 4 */ (void *)(ra), \ -/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ -/* 6 */ (void *)(__psint_t)smp_processor_id(), \ -/* 7 */ (void *)(__psint_t)(current->pid), \ -/* 8 */ (void *)__return_address, \ -/* 9 */ 0, 0, 0, 0, 0, 0, 0) - -/* - * Vnode tracing code. - */ -void -vn_trace_entry(vnode_t *vp, char *func, inst_t *ra) -{ - KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); -} - -void -vn_trace_exit(vnode_t *vp, char *func, inst_t *ra) -{ - KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); -} - -void -vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra) -{ - KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); -} - -void -vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra) -{ - KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); -} - -void -vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra) -{ - KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); -} -#endif /* XFS_VNODE_TRACE */ diff --git a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h deleted file mode 100644 index af0b65fe5..000000000 --- a/fs/xfs/linux/xfs_vnode.h +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - * - * Portions Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#ifndef __XFS_VNODE_H__ -#define __XFS_VNODE_H__ - -struct uio; -struct file; -struct vattr; -struct xfs_iomap; -struct attrlist_cursor_kern; - -/* - * Vnode types. VNON means no type. - */ -enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VFIFO, VBAD, VSOCK }; - -typedef xfs_ino_t vnumber_t; -typedef struct dentry vname_t; -typedef bhv_head_t vn_bhv_head_t; - -/* - * MP locking protocols: - * v_flag, v_vfsp VN_LOCK/VN_UNLOCK - * v_type read-only or fs-dependent - */ -typedef struct vnode { - __u32 v_flag; /* vnode flags (see below) */ - enum vtype v_type; /* vnode type */ - struct vfs *v_vfsp; /* ptr to containing VFS */ - vnumber_t v_number; /* in-core vnode number */ - vn_bhv_head_t v_bh; /* behavior head */ - spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */ - struct inode v_inode; /* Linux inode */ -#ifdef XFS_VNODE_TRACE - struct ktrace *v_trace; /* trace header structure */ -#endif -} vnode_t; - -#define v_fbhv v_bh.bh_first /* first behavior */ -#define v_fops v_bh.bh_first->bd_ops /* first behavior ops */ - -#define VNODE_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ -#define VNODE_POSITION_TOP BHV_POSITION_TOP /* chain top */ -#define VNODE_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ - -typedef enum { - VN_BHV_UNKNOWN, /* not specified */ - VN_BHV_XFS, /* xfs */ - VN_BHV_DM, /* data migration */ - VN_BHV_QM, /* quota manager */ - VN_BHV_IO, /* IO path */ - VN_BHV_END /* housekeeping end-of-range */ -} vn_bhv_t; - -#define VNODE_POSITION_XFS (VNODE_POSITION_BASE) -#define VNODE_POSITION_DM (VNODE_POSITION_BASE+10) -#define VNODE_POSITION_QM (VNODE_POSITION_BASE+20) -#define VNODE_POSITION_IO (VNODE_POSITION_BASE+30) - -/* - * Macros for dealing with the behavior descriptor inside of the vnode. - */ -#define BHV_TO_VNODE(bdp) ((vnode_t *)BHV_VOBJ(bdp)) -#define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp)) - -#define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh))) -#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) -#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp) -#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops) -#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops) - -/* - * Vnode to Linux inode mapping. - */ -#define LINVFS_GET_VP(inode) ((vnode_t *)list_entry(inode, vnode_t, v_inode)) -#define LINVFS_GET_IP(vp) (&(vp)->v_inode) - -/* - * Convert between vnode types and inode formats (since POSIX.1 - * defines mode word of stat structure in terms of inode formats). - */ -extern enum vtype iftovt_tab[]; -extern u_short vttoif_tab[]; -#define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) -#define VTTOIF(indx) (vttoif_tab[(int)(indx)]) -#define MAKEIMODE(indx, mode) (int)(VTTOIF(indx) | (mode)) - - -/* - * Vnode flags. - */ -#define VINACT 0x1 /* vnode is being inactivated */ -#define VRECLM 0x2 /* vnode is being reclaimed */ -#define VWAIT 0x4 /* waiting for VINACT/VRECLM to end */ -#define VMODIFIED 0x8 /* XFS inode state possibly differs */ - /* to the Linux inode state. */ - -/* - * Values for the VOP_RWLOCK and VOP_RWUNLOCK flags parameter. - */ -typedef enum vrwlock { - VRWLOCK_NONE, - VRWLOCK_READ, - VRWLOCK_WRITE, - VRWLOCK_WRITE_DIRECT, - VRWLOCK_TRY_READ, - VRWLOCK_TRY_WRITE -} vrwlock_t; - -/* - * Return values for VOP_INACTIVE. A return value of - * VN_INACTIVE_NOCACHE implies that the file system behavior - * has disassociated its state and bhv_desc_t from the vnode. - */ -#define VN_INACTIVE_CACHE 0 -#define VN_INACTIVE_NOCACHE 1 - -/* - * Values for the cmd code given to VOP_VNODE_CHANGE. - */ -typedef enum vchange { - VCHANGE_FLAGS_FRLOCKS = 0, - VCHANGE_FLAGS_ENF_LOCKING = 1, - VCHANGE_FLAGS_TRUNCATED = 2, - VCHANGE_FLAGS_PAGE_DIRTY = 3, - VCHANGE_FLAGS_IOEXCL_COUNT = 4 -} vchange_t; - - -typedef int (*vop_open_t)(bhv_desc_t *, struct cred *); -typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *, - const struct iovec *, unsigned int, - loff_t *, int, struct cred *); -typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, - loff_t *, int, size_t, read_actor_t, - void *, struct cred *); -typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, - int, unsigned int, unsigned long); -typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int, - struct cred *); -typedef int (*vop_setattr_t)(bhv_desc_t *, struct vattr *, int, - struct cred *); -typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); -typedef int (*vop_lookup_t)(bhv_desc_t *, vname_t *, vnode_t **, - int, vnode_t *, struct cred *); -typedef int (*vop_create_t)(bhv_desc_t *, vname_t *, struct vattr *, - vnode_t **, struct cred *); -typedef int (*vop_remove_t)(bhv_desc_t *, vname_t *, struct cred *); -typedef int (*vop_link_t)(bhv_desc_t *, vnode_t *, vname_t *, - struct cred *); -typedef int (*vop_rename_t)(bhv_desc_t *, vname_t *, vnode_t *, vname_t *, - struct cred *); -typedef int (*vop_mkdir_t)(bhv_desc_t *, vname_t *, struct vattr *, - vnode_t **, struct cred *); -typedef int (*vop_rmdir_t)(bhv_desc_t *, vname_t *, struct cred *); -typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, - int *); -typedef int (*vop_symlink_t)(bhv_desc_t *, vname_t *, struct vattr *, - char *, vnode_t **, struct cred *); -typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, - struct cred *); -typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, - xfs_off_t, xfs_off_t); -typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); -typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); -typedef int (*vop_release_t)(bhv_desc_t *); -typedef int (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t); -typedef void (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t); -typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, - struct xfs_iomap *, int *); -typedef int (*vop_reclaim_t)(bhv_desc_t *); -typedef int (*vop_attr_get_t)(bhv_desc_t *, char *, char *, int *, int, - struct cred *); -typedef int (*vop_attr_set_t)(bhv_desc_t *, char *, char *, int, int, - struct cred *); -typedef int (*vop_attr_remove_t)(bhv_desc_t *, char *, int, struct cred *); -typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, - struct attrlist_cursor_kern *, struct cred *); -typedef void (*vop_link_removed_t)(bhv_desc_t *, vnode_t *, int); -typedef void (*vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t); -typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); -typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, - uint64_t, int); -typedef int (*vop_iflush_t)(bhv_desc_t *, int); - - -typedef struct vnodeops { - bhv_position_t vn_position; /* position within behavior chain */ - vop_open_t vop_open; - vop_read_t vop_read; - vop_write_t vop_write; - vop_sendfile_t vop_sendfile; - vop_ioctl_t vop_ioctl; - vop_getattr_t vop_getattr; - vop_setattr_t vop_setattr; - vop_access_t vop_access; - vop_lookup_t vop_lookup; - vop_create_t vop_create; - vop_remove_t vop_remove; - vop_link_t vop_link; - vop_rename_t vop_rename; - vop_mkdir_t vop_mkdir; - vop_rmdir_t vop_rmdir; - vop_readdir_t vop_readdir; - vop_symlink_t vop_symlink; - vop_readlink_t vop_readlink; - vop_fsync_t vop_fsync; - vop_inactive_t vop_inactive; - vop_fid2_t vop_fid2; - vop_rwlock_t vop_rwlock; - vop_rwunlock_t vop_rwunlock; - vop_bmap_t vop_bmap; - vop_reclaim_t vop_reclaim; - vop_attr_get_t vop_attr_get; - vop_attr_set_t vop_attr_set; - vop_attr_remove_t vop_attr_remove; - vop_attr_list_t vop_attr_list; - vop_link_removed_t vop_link_removed; - vop_vnode_change_t vop_vnode_change; - vop_ptossvp_t vop_tosspages; - vop_pflushinvalvp_t vop_flushinval_pages; - vop_pflushvp_t vop_flush_pages; - vop_release_t vop_release; - vop_iflush_t vop_iflush; -} vnodeops_t; - -/* - * VOP's. - */ -#define _VOP_(op, vp) (*((vnodeops_t *)(vp)->v_fops)->op) - -#define VOP_READ(vp,file,iov,segs,offset,ioflags,cr,rv) \ - rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) -#define VOP_WRITE(vp,file,iov,segs,offset,ioflags,cr,rv) \ - rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) -#define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ - rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) -#define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ - rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) -#define VOP_OPEN(vp, cr, rv) \ - rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr) -#define VOP_GETATTR(vp, vap, f, cr, rv) \ - rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr) -#define VOP_SETATTR(vp, vap, f, cr, rv) \ - rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr) -#define VOP_ACCESS(vp, mode, cr, rv) \ - rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr) -#define VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv) \ - rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr) -#define VOP_CREATE(dvp,d,vap,vpp,cr,rv) \ - rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr) -#define VOP_REMOVE(dvp,d,cr,rv) \ - rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr) -#define VOP_LINK(tdvp,fvp,d,cr,rv) \ - rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr) -#define VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv) \ - rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr) -#define VOP_MKDIR(dp,d,vap,vpp,cr,rv) \ - rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr) -#define VOP_RMDIR(dp,d,cr,rv) \ - rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr) -#define VOP_READDIR(vp,uiop,cr,eofp,rv) \ - rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp) -#define VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv) \ - rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr) -#define VOP_READLINK(vp,uiop,fl,cr,rv) \ - rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,fl,cr) -#define VOP_FSYNC(vp,f,cr,b,e,rv) \ - rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e) -#define VOP_INACTIVE(vp, cr, rv) \ - rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr) -#define VOP_RELEASE(vp, rv) \ - rv = _VOP_(vop_release, vp)((vp)->v_fbhv) -#define VOP_FID2(vp, fidp, rv) \ - rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp) -#define VOP_RWLOCK(vp,i) \ - (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) -#define VOP_RWLOCK_TRY(vp,i) \ - _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) -#define VOP_RWUNLOCK(vp,i) \ - (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i) -#define VOP_FRLOCK(vp,c,fl,flags,offset,fr,rv) \ - rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr) -#define VOP_RECLAIM(vp, rv) \ - rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv) -#define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \ - rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred) -#define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \ - rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred) -#define VOP_ATTR_REMOVE(vp, name, flags, cred, rv) \ - rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred) -#define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \ - rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred) -#define VOP_LINK_REMOVED(vp, dvp, linkzero) \ - (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero) -#define VOP_VNODE_CHANGE(vp, cmd, val) \ - (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val) -/* - * These are page cache functions that now go thru VOPs. - * 'last' parameter is unused and left in for IRIX compatibility - */ -#define VOP_TOSS_PAGES(vp, first, last, fiopt) \ - _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt) -/* - * 'last' parameter is unused and left in for IRIX compatibility - */ -#define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \ - _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt) -/* - * 'last' parameter is unused and left in for IRIX compatibility - */ -#define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \ - rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt) -#define VOP_IOCTL(vp, inode, filp, fl, cmd, arg, rv) \ - rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,fl,cmd,arg) -#define VOP_IFLUSH(vp, flags, rv) \ - rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags) - -/* - * Flags for read/write calls - same values as IRIX - */ -#define IO_ISDIRECT 0x00004 /* bypass page cache */ -#define IO_INVIS 0x00020 /* don't update inode timestamps */ - -/* - * Flags for VOP_IFLUSH call - */ -#define FLUSH_SYNC 1 /* wait for flush to complete */ -#define FLUSH_INODE 2 /* flush the inode itself */ -#define FLUSH_LOG 4 /* force the last log entry for - * this inode out to disk */ - -/* - * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and - * VOP_FLUSH_PAGES. - */ -#define FI_NONE 0 /* none */ -#define FI_REMAPF 1 /* Do a remapf prior to the operation */ -#define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation. - Prevent VM access to the pages until - the operation completes. */ - -/* - * Vnode attributes. va_mask indicates those attributes the caller - * wants to set or extract. - */ -typedef struct vattr { - int va_mask; /* bit-mask of attributes present */ - enum vtype va_type; /* vnode type (for create) */ - mode_t va_mode; /* file access mode and type */ - nlink_t va_nlink; /* number of references to file */ - uid_t va_uid; /* owner user id */ - gid_t va_gid; /* owner group id */ - xfs_ino_t va_nodeid; /* file id */ - xfs_off_t va_size; /* file size in bytes */ - u_long va_blocksize; /* blocksize preferred for i/o */ - struct timespec va_atime; /* time of last access */ - struct timespec va_mtime; /* time of last modification */ - struct timespec va_ctime; /* time file changed */ - u_int va_gen; /* generation number of file */ - xfs_dev_t va_rdev; /* device the special file represents */ - __int64_t va_nblocks; /* number of blocks allocated */ - u_long va_xflags; /* random extended file flags */ - u_long va_extsize; /* file extent size */ - u_long va_nextents; /* number of extents in file */ - u_long va_anextents; /* number of attr extents in file */ - int va_projid; /* project id */ -} vattr_t; - -/* - * setattr or getattr attributes - */ -#define XFS_AT_TYPE 0x00000001 -#define XFS_AT_MODE 0x00000002 -#define XFS_AT_UID 0x00000004 -#define XFS_AT_GID 0x00000008 -#define XFS_AT_FSID 0x00000010 -#define XFS_AT_NODEID 0x00000020 -#define XFS_AT_NLINK 0x00000040 -#define XFS_AT_SIZE 0x00000080 -#define XFS_AT_ATIME 0x00000100 -#define XFS_AT_MTIME 0x00000200 -#define XFS_AT_CTIME 0x00000400 -#define XFS_AT_RDEV 0x00000800 -#define XFS_AT_BLKSIZE 0x00001000 -#define XFS_AT_NBLOCKS 0x00002000 -#define XFS_AT_VCODE 0x00004000 -#define XFS_AT_MAC 0x00008000 -#define XFS_AT_UPDATIME 0x00010000 -#define XFS_AT_UPDMTIME 0x00020000 -#define XFS_AT_UPDCTIME 0x00040000 -#define XFS_AT_ACL 0x00080000 -#define XFS_AT_CAP 0x00100000 -#define XFS_AT_INF 0x00200000 -#define XFS_AT_XFLAGS 0x00400000 -#define XFS_AT_EXTSIZE 0x00800000 -#define XFS_AT_NEXTENTS 0x01000000 -#define XFS_AT_ANEXTENTS 0x02000000 -#define XFS_AT_PROJID 0x04000000 -#define XFS_AT_SIZE_NOPERM 0x08000000 -#define XFS_AT_GENCOUNT 0x10000000 - -#define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ - XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ - XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ - XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\ - XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\ - XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT) - -#define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ - XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ - XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ - XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID) - -#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) - -#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) - -#define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\ - XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ - XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) - -/* - * Modes. - */ -#define VSUID S_ISUID /* set user id on execution */ -#define VSGID S_ISGID /* set group id on execution */ -#define VSVTX S_ISVTX /* save swapped text even after use */ -#define VREAD S_IRUSR /* read, write, execute permissions */ -#define VWRITE S_IWUSR -#define VEXEC S_IXUSR - -#define MODEMASK S_IALLUGO /* mode bits plus permission bits */ - -/* - * Check whether mandatory file locking is enabled. - */ -#define MANDLOCK(vp, mode) \ - ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) - -extern void vn_init(void); -extern int vn_wait(struct vnode *); -extern vnode_t *vn_initialize(struct inode *); - -/* - * Acquiring and invalidating vnodes: - * - * if (vn_get(vp, version, 0)) - * ...; - * vn_purge(vp, version); - * - * vn_get and vn_purge must be called with vmap_t arguments, sampled - * while a lock that the vnode's VOP_RECLAIM function acquires is - * held, to ensure that the vnode sampled with the lock held isn't - * recycled (VOP_RECLAIMed) or deallocated between the release of the lock - * and the subsequent vn_get or vn_purge. - */ - -/* - * vnode_map structures _must_ match vn_epoch and vnode structure sizes. - */ -typedef struct vnode_map { - vfs_t *v_vfsp; - vnumber_t v_number; /* in-core vnode number */ - xfs_ino_t v_ino; /* inode # */ -} vmap_t; - -#define VMAP(vp, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \ - (vmap).v_number = (vp)->v_number, \ - (vmap).v_ino = (vp)->v_inode.i_ino; } - -extern void vn_purge(struct vnode *, vmap_t *); -extern vnode_t *vn_get(struct vnode *, vmap_t *); -extern int vn_revalidate(struct vnode *); -extern void vn_remove(struct vnode *); - -static inline int vn_count(struct vnode *vp) -{ - return atomic_read(&LINVFS_GET_IP(vp)->i_count); -} - -/* - * Vnode reference counting functions (and macros for compatibility). - */ -extern vnode_t *vn_hold(struct vnode *); -extern void vn_rele(struct vnode *); - -#if defined(XFS_VNODE_TRACE) -#define VN_HOLD(vp) \ - ((void)vn_hold(vp), \ - vn_trace_hold(vp, __FILE__, __LINE__, (inst_t *)__return_address)) -#define VN_RELE(vp) \ - (vn_trace_rele(vp, __FILE__, __LINE__, (inst_t *)__return_address), \ - iput(LINVFS_GET_IP(vp))) -#else -#define VN_HOLD(vp) ((void)vn_hold(vp)) -#define VN_RELE(vp) (iput(LINVFS_GET_IP(vp))) -#endif - -/* - * Vname handling macros. - */ -#define VNAME(dentry) ((char *) (dentry)->d_name.name) -#define VNAMELEN(dentry) ((dentry)->d_name.len) -#define VNAME_TO_VNODE(dentry) (LINVFS_GET_VP((dentry)->d_inode)) - -/* - * Vnode spinlock manipulation. - */ -#define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) -#define VN_UNLOCK(vp, s) mutex_spinunlock(&(vp)->v_lock, s) -#define VN_FLAGSET(vp,b) vn_flagset(vp,b) -#define VN_FLAGCLR(vp,b) vn_flagclr(vp,b) - -static __inline__ void vn_flagset(struct vnode *vp, uint flag) -{ - spin_lock(&vp->v_lock); - vp->v_flag |= flag; - spin_unlock(&vp->v_lock); -} - -static __inline__ void vn_flagclr(struct vnode *vp, uint flag) -{ - spin_lock(&vp->v_lock); - vp->v_flag &= ~flag; - spin_unlock(&vp->v_lock); -} - -/* - * Update modify/access/change times on the vnode - */ -#define VN_MTIMESET(vp, tvp) (LINVFS_GET_IP(vp)->i_mtime = *(tvp)) -#define VN_ATIMESET(vp, tvp) (LINVFS_GET_IP(vp)->i_atime = *(tvp)) -#define VN_CTIMESET(vp, tvp) (LINVFS_GET_IP(vp)->i_ctime = *(tvp)) - -/* - * Some useful predicates. - */ -#define VN_MAPPED(vp) mapping_mapped(LINVFS_GET_IP(vp)->i_mapping) -#define VN_CACHED(vp) (LINVFS_GET_IP(vp)->i_mapping->nrpages) -#define VN_DIRTY(vp) mapping_tagged(LINVFS_GET_IP(vp)->i_mapping, \ - PAGECACHE_TAG_DIRTY) -#define VMODIFY(vp) VN_FLAGSET(vp, VMODIFIED) -#define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED) - -/* - * Flags to VOP_SETATTR/VOP_GETATTR. - */ -#define ATTR_UTIME 0x01 /* non-default utime(2) request */ -#define ATTR_DMI 0x08 /* invocation from a DMI function */ -#define ATTR_LAZY 0x80 /* set/get attributes lazily */ -#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ - -/* - * Flags to VOP_FSYNC and VOP_RECLAIM. - */ -#define FSYNC_NOWAIT 0 /* asynchronous flush */ -#define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ -#define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ -#define FSYNC_DATA 0x4 /* synchronous fsync of data only */ - -/* - * Tracking vnode activity. - */ -#if defined(XFS_VNODE_TRACE) - -#define VNODE_TRACE_SIZE 16 /* number of trace entries */ -#define VNODE_KTRACE_ENTRY 1 -#define VNODE_KTRACE_EXIT 2 -#define VNODE_KTRACE_HOLD 3 -#define VNODE_KTRACE_REF 4 -#define VNODE_KTRACE_RELE 5 - -extern void vn_trace_entry(struct vnode *, char *, inst_t *); -extern void vn_trace_exit(struct vnode *, char *, inst_t *); -extern void vn_trace_hold(struct vnode *, char *, int, inst_t *); -extern void vn_trace_ref(struct vnode *, char *, int, inst_t *); -extern void vn_trace_rele(struct vnode *, char *, int, inst_t *); - -#define VN_TRACE(vp) \ - vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) -#else -#define vn_trace_entry(a,b,c) -#define vn_trace_exit(a,b,c) -#define vn_trace_hold(a,b,c,d) -#define vn_trace_ref(a,b,c,d) -#define vn_trace_rele(a,b,c,d) -#define VN_TRACE(vp) -#endif - -#endif /* __XFS_VNODE_H__ */ diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index e0b529b33..f8f6e0fe6 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h @@ -456,6 +456,9 @@ xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); #define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ #define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ #define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */ +#define XFS_DIFLAG_BARRIER_BIT 10 /* chroot() barrier */ +#define XFS_DIFLAG_IUNLINK_BIT 11 /* inode has iunlink */ + #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) @@ -464,5 +467,8 @@ xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) +#define XFS_DIFLAG_BARRIER (1 << XFS_DIFLAG_BARRIER_BIT) +#define XFS_DIFLAG_IUNLINK (1 << XFS_DIFLAG_IUNLINK_BIT) + #endif /* __XFS_DINODE_H__ */ diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 1ed650e90..7e1b82c4f 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -76,6 +76,8 @@ struct fsxattr { #define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ #define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ #define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +#define XFS_XFLAG_BARRIER 0x00004000 /* chroot() barrier */ +#define XFS_XFLAG_IUNLINK 0x00008000 /* Immutable unlink */ #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ab973fe10..92a4c654e 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -869,6 +869,10 @@ xfs_dic2xflags( flags |= XFS_XFLAG_PREALLOC; if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= XFS_XFLAG_IMMUTABLE; + if (di_flags & XFS_DIFLAG_IUNLINK) + flags |= XFS_XFLAG_IUNLINK; + if (di_flags & XFS_DIFLAG_BARRIER) + flags |= XFS_XFLAG_BARRIER; if (di_flags & XFS_DIFLAG_APPEND) flags |= XFS_XFLAG_APPEND; if (di_flags & XFS_DIFLAG_SYNC) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index ab9b4d181..2777aca04 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -835,6 +835,10 @@ xfs_setattr( } if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; + if (vap->va_xflags & XFS_XFLAG_IUNLINK) + ip->i_d.di_flags |= XFS_DIFLAG_IUNLINK; + if (vap->va_xflags & XFS_XFLAG_BARRIER) + ip->i_d.di_flags |= XFS_DIFLAG_BARRIER; if (vap->va_xflags & XFS_XFLAG_APPEND) ip->i_d.di_flags |= XFS_DIFLAG_APPEND; if (vap->va_xflags & XFS_XFLAG_SYNC) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 82db061af..7751db56b 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -44,7 +44,8 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ -#define ACPI_OS_NAME "Linux" +#define ACPI_OS_NAME "Microsoft Windows NT" + /* Microsoft, Microsoft Windows, Microsoft Windows NT are trademarks of Microsoft Corp. */ #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 diff --git a/include/asm-alpha/fcntl.h b/include/asm-alpha/fcntl.h index ad40d002f..7e86c9a5a 100644 --- a/include/asm-alpha/fcntl.h +++ b/include/asm-alpha/fcntl.h @@ -20,6 +20,7 @@ #define O_DIRECTORY 0100000 /* must be a directory */ #define O_NOFOLLOW 0200000 /* don't follow links */ #define O_LARGEFILE 0400000 /* will be set by the kernel on every open */ +#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */ #define O_DIRECT 02000000 /* direct disk access - should check with OSF/1 */ #define F_DUPFD 0 /* dup */ diff --git a/include/asm-alpha/relay.h b/include/asm-alpha/relay.h new file mode 100644 index 000000000..104091f06 --- /dev/null +++ b/include/asm-alpha/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_ALPHA_RELAY_H +#define _ASM_ALPHA_RELAY_H + +#include +#endif diff --git a/include/asm-alpha/resource.h b/include/asm-alpha/resource.h index 686b9558d..558d177cc 100644 --- a/include/asm-alpha/resource.h +++ b/include/asm-alpha/resource.h @@ -39,7 +39,7 @@ {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_NPROC */ \ - {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ + {PAGE_SIZE,PAGE_SIZE}, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_LOCKS */ \ } diff --git a/include/asm-alpha/rmap.h b/include/asm-alpha/rmap.h deleted file mode 100644 index 08b2236ef..000000000 --- a/include/asm-alpha/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ALPHA_RMAP_H -#define _ALPHA_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index ceda5fc56..aae3ab664 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h @@ -233,6 +233,7 @@ #define __NR_osf_memcntl 260 /* not implemented */ #define __NR_osf_fdatasync 261 /* not implemented */ +#define __NR_vserver 273 /* * Linux-specific system calls begin at 300 diff --git a/include/asm-arm/arch-cl7500/ide.h b/include/asm-arm/arch-cl7500/ide.h deleted file mode 100644 index 78f97a3b2..000000000 --- a/include/asm-arm/arch-cl7500/ide.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * linux/include/asm-arm/arch-cl7500/ide.h - * - * Copyright (c) 1997 Russell King - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - */ -#include -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - if (ctrl_port) { - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - } else { - hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206; - } - if (irq != NULL) - *irq = 0; - hw->io_ports[IDE_IRQ_OFFSET] = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ - hw_regs_t hw; - - ide_init_hwif_ports(&hw, ISASLOT_IO + 0x1f0, ISASLOT_IO + 0x3f6, NULL); - hw.irq = IRQ_ISA_14; - ide_register_hw(&hw); -} diff --git a/include/asm-arm/arch-cl7500/keyboard.h b/include/asm-arm/arch-cl7500/keyboard.h deleted file mode 100644 index 660b31a0e..000000000 --- a/include/asm-arm/arch-cl7500/keyboard.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * linux/include/asm-arm/arch-cl7500/keyboard.h - * from linux/include/asm-arm/arch-rpc/keyboard.h - * - * Keyboard driver definitions for CL7500 architecture - * - * Copyright (C) 1998-2001 Russell King - */ -#include -#define NR_SCANCODES 128 - -extern int ps2kbd_init_hw(void); - -#define kbd_disable_irq() disable_irq(IRQ_KEYBOARDRX) -#define kbd_enable_irq() enable_irq(IRQ_KEYBOARDRX) -#define kbd_init_hw() ps2kbd_init_hw() diff --git a/include/asm-arm/arch-clps711x/keyboard.h b/include/asm-arm/arch-clps711x/keyboard.h deleted file mode 100644 index 30ab2199f..000000000 --- a/include/asm-arm/arch-clps711x/keyboard.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/include/asm-arm/arch-clps711x/keyboard.h - * - * Copyright (C) 1998-2001 Russell King - */ -#include - -#define NR_SCANCODES 128 - -#define kbd_disable_irq() do { } while (0) -#define kbd_enable_irq() do { } while (0) - -/* - * EDB7211 keyboard driver - */ -extern void edb7211_kbd_init_hw(void); -extern void clps711x_kbd_init_hw(void); - -static inline void kbd_init_hw(void) -{ - if (machine_is_edb7211()) - edb7211_kbd_init_hw(); - - if (machine_is_autcpu12()) - clps711x_kbd_init_hw(); -} diff --git a/include/asm-arm/arch-ebsa110/ide.h b/include/asm-arm/arch-ebsa110/ide.h deleted file mode 100644 index 35eff5c28..000000000 --- a/include/asm-arm/arch-ebsa110/ide.h +++ /dev/null @@ -1 +0,0 @@ -/* no ide */ diff --git a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h deleted file mode 100644 index 09c0310b6..000000000 --- a/include/asm-arm/arch-ebsa285/ide.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa285/ide.h - * - * Copyright (C) 1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - */ -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - if (irq) - *irq = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void ide_init_default_hwifs(void) -{ -#if 0 - hw_regs_t hw; - - memset(hw, 0, sizeof(*hw)); - - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); - hw.irq = IRQ_HARDDISK; - ide_register_hw(&hw); -#endif -} diff --git a/include/asm-arm/arch-iop3xx/ide.h b/include/asm-arm/arch-iop3xx/ide.h deleted file mode 100644 index c2b0265dd..000000000 --- a/include/asm-arm/arch-iop3xx/ide.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * include/asm-arm/arch-iop3xx/ide.h - * - * Generic IDE functions for IOP310 systems - * - * Author: Deepak Saxena - * - * Copyright 2001 MontaVista Software Inc. - * - * 09/26/2001 - Sharon Baartmans - * Fixed so it actually works. - */ - -#ifndef _ASM_ARCH_IDE_H_ -#define _ASM_ARCH_IDE_H_ - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - int regincr = 1; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += regincr; - } - - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - - if (irq) *irq = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void ide_init_default_hwifs(void) -{ - /* There are no standard ports */ -} - -#endif diff --git a/include/asm-arm/arch-l7200/ide.h b/include/asm-arm/arch-l7200/ide.h deleted file mode 100644 index 62ee12ada..000000000 --- a/include/asm-arm/arch-l7200/ide.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/include/asm-arm/arch-l7200/ide.h - * - * Copyright (c) 2000 Steve Hill (sjhill@cotw.com) - * - * Changelog: - * 03-29-2000 SJH Created file placeholder - */ -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ -} diff --git a/include/asm-arm/arch-l7200/keyboard.h b/include/asm-arm/arch-l7200/keyboard.h deleted file mode 100644 index 6628bd381..000000000 --- a/include/asm-arm/arch-l7200/keyboard.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * linux/include/asm-arm/arch-l7200/keyboard.h - * - * Keyboard driver definitions for LinkUp Systems L7200 architecture - * - * Copyright (C) 2000 Scott A McConnell (samcconn@cotw.com) - * Steve Hill (sjhill@cotw.com) - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Changelog: - * 07-18-2000 SAM Created file - * 07-28-2000 SJH Complete rewrite - */ - -#include - -#error This needs fixing --rmk - -/* - * Layout of L7200 keyboard registers - */ -struct KBD_Port { - unsigned int KBDR; - unsigned int KBDMR; - unsigned int KBSBSR; - unsigned int Reserved; - unsigned int KBKSR; -}; - -#define KBD_BASE IO_BASE_2 + 0x4000 -#define l7200kbd_hwregs ((volatile struct KBD_Port *) (KBD_BASE)) - -extern void l7200kbd_init_hw(void); -extern int l7200kbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); - -#define kbd_setkeycode(sc,kc) (-EINVAL) -#define kbd_getkeycode(sc) (-EINVAL) - -#define kbd_translate(sc, kcp, rm) ({ *(kcp) = (sc); 1; }) -#define kbd_unexpected_up(kc) (0200) -#define kbd_leds(leds) do {} while (0) -#define kbd_init_hw() l7200kbd_init_hw() -#define kbd_sysrq_xlate ((unsigned char *)NULL) -#define kbd_disable_irq() disable_irq(IRQ_GCTC2) -#define kbd_enable_irq() enable_irq(IRQ_GCTC2) - -#define SYSRQ_KEY 13 diff --git a/include/asm-arm/arch-lh7a40x/hardware.h b/include/asm-arm/arch-lh7a40x/hardware.h index aeb07c162..40e000444 100644 --- a/include/asm-arm/arch-lh7a40x/hardware.h +++ b/include/asm-arm/arch-lh7a40x/hardware.h @@ -37,10 +37,10 @@ typedef struct { volatile u32 offset[4096]; } __regbase; # define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] # define __REG(x) __REGP(io_p2v(x)) typedef struct { volatile u16 offset[4096]; } __regbase16; -# define __REGP16(x) ((__regbase16 *)((x)&~4095))->offset[((x)&4095)>>1] +# define __REGP16(x) ((__regbase16 *)((x)&~4095))->offset[((x)&4095)>>2] # define __REG16(x) __REGP16(io_p2v(x)) typedef struct { volatile u8 offset[4096]; } __regbase8; -# define __REGP8(x) ((__regbase8 *)((x)&~4095))->offset[(x)&4095] +# define __REGP8(x) ((__regbase8 *)((x)&~4095))->offset[((x)&4095)>>2] # define __REG8(x) __REGP8(io_p2v(x)) #endif diff --git a/include/asm-arm/arch-nexuspci/ide.h b/include/asm-arm/arch-nexuspci/ide.h deleted file mode 100644 index 5514808d5..000000000 --- a/include/asm-arm/arch-nexuspci/ide.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * linux/include/asm-arm/arch-nexuspci/ide.h - * - * Copyright (c) 1998 Russell King - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - */ -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - if (irq) - *irq = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void ide_init_default_hwifs(void) -{ - /* There are no standard ports */ -} diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h index bf87b3a56..a7d7a36d6 100644 --- a/include/asm-arm/arch-omap/dma.h +++ b/include/asm-arm/arch-omap/dma.h @@ -33,10 +33,10 @@ #define OMAP_DMA_EXT_NDMA_REQ 5 #define OMAP_DMA_EXT_NDMA_REQ2 6 #define OMAP_DMA_UWIRE_TX 7 -#define OMAP_DMA_MCBSP1_TX 8 -#define OMAP_DMA_MCBSP1_RX 9 -#define OMAP_DMA_MCBSP3_TX 10 -#define OMAP_DMA_MCBSP3_RX 11 +#define OMAP_DMA_MCBSP1_DMA_TX 8 +#define OMAP_DMA_MCBSP1_DMA_RX 9 +#define OMAP_DMA_MCBSP3_DMA_TX 10 +#define OMAP_DMA_MCBSP3_DMA_RX 11 #define OMAP_DMA_UART1_TX 12 #define OMAP_DMA_UART1_RX 13 #define OMAP_DMA_UART2_TX 14 @@ -86,77 +86,75 @@ #define OMAP_DMA_CRYPTO_DES_OUT 56 -#define OMAP_DMA_BASE (0xfffed800) -#define OMAP_DMA_GCR (OMAP_DMA_BASE + 0x400) -#define OMAP_DMA_GSCR (OMAP_DMA_BASE + 0x404) -#define OMAP_DMA_GRST (OMAP_DMA_BASE + 0x408) -#define OMAP_DMA_HW_ID (OMAP_DMA_BASE + 0x442) -#define OMAP_DMA_PCH2_ID (OMAP_DMA_BASE + 0x444) +#define OMAP_DMA_BASE 0xfffed800 +#define OMAP_DMA_GCR_REG (OMAP_DMA_BASE + 0x400) +#define OMAP_DMA_GSCR_REG (OMAP_DMA_BASE + 0x404) +#define OMAP_DMA_GRST_REG (OMAP_DMA_BASE + 0x408) +#define OMAP_DMA_HW_ID_REG (OMAP_DMA_BASE + 0x442) +#define OMAP_DMA_PCH2_ID_REG (OMAP_DMA_BASE + 0x444) #define OMAP_DMA_PCH0_ID (OMAP_DMA_BASE + 0x446) #define OMAP_DMA_PCH1_ID (OMAP_DMA_BASE + 0x448) #define OMAP_DMA_PCHG_ID (OMAP_DMA_BASE + 0x44a) #define OMAP_DMA_PCHD_ID (OMAP_DMA_BASE + 0x44c) -#define OMAP_DMA_CAPS_0_U (OMAP_DMA_BASE + 0x44e) -#define OMAP_DMA_CAPS_0_L (OMAP_DMA_BASE + 0x450) -#define OMAP_DMA_CAPS_1_U (OMAP_DMA_BASE + 0x452) -#define OMAP_DMA_CAPS_1_L (OMAP_DMA_BASE + 0x454) -#define OMAP_DMA_CAPS_2 (OMAP_DMA_BASE + 0x456) -#define OMAP_DMA_CAPS_3 (OMAP_DMA_BASE + 0x458) -#define OMAP_DMA_CAPS_4 (OMAP_DMA_BASE + 0x45a) -#define OMAP_DMA_PCH2_SR (OMAP_DMA_BASE + 0x460) -#define OMAP_DMA_PCH0_SR (OMAP_DMA_BASE + 0x480) -#define OMAP_DMA_PCH1_SR (OMAP_DMA_BASE + 0x482) -#define OMAP_DMA_PCHD_SR (OMAP_DMA_BASE + 0x4c0) - -#define OMAP1510_DMA_LCD_BASE (0xfffedb00) -#define OMAP1510_DMA_LCD_CTRL (OMAP1510_DMA_LCD_BASE + 0x00) -#define OMAP1510_DMA_LCD_TOP_F1_L (OMAP1510_DMA_LCD_BASE + 0x02) -#define OMAP1510_DMA_LCD_TOP_F1_U (OMAP1510_DMA_LCD_BASE + 0x04) -#define OMAP1510_DMA_LCD_BOT_F1_L (OMAP1510_DMA_LCD_BASE + 0x06) -#define OMAP1510_DMA_LCD_BOT_F1_U (OMAP1510_DMA_LCD_BASE + 0x08) - -#define OMAP1610_DMA_LCD_BASE (0xfffee300) -#define OMAP1610_DMA_LCD_CSDP (OMAP1610_DMA_LCD_BASE + 0xc0) -#define OMAP1610_DMA_LCD_CCR (OMAP1610_DMA_LCD_BASE + 0xc2) -#define OMAP1610_DMA_LCD_CTRL (OMAP1610_DMA_LCD_BASE + 0xc4) -#define OMAP1610_DMA_LCD_TOP_B1_L (OMAP1610_DMA_LCD_BASE + 0xc8) -#define OMAP1610_DMA_LCD_TOP_B1_U (OMAP1610_DMA_LCD_BASE + 0xca) -#define OMAP1610_DMA_LCD_BOT_B1_L (OMAP1610_DMA_LCD_BASE + 0xcc) -#define OMAP1610_DMA_LCD_BOT_B1_U (OMAP1610_DMA_LCD_BASE + 0xce) -#define OMAP1610_DMA_LCD_TOP_B2_L (OMAP1610_DMA_LCD_BASE + 0xd0) -#define OMAP1610_DMA_LCD_TOP_B2_U (OMAP1610_DMA_LCD_BASE + 0xd2) -#define OMAP1610_DMA_LCD_BOT_B2_L (OMAP1610_DMA_LCD_BASE + 0xd4) -#define OMAP1610_DMA_LCD_BOT_B2_U (OMAP1610_DMA_LCD_BASE + 0xd6) -#define OMAP1610_DMA_LCD_SRC_EI_B1 (OMAP1610_DMA_LCD_BASE + 0xd8) -#define OMAP1610_DMA_LCD_SRC_FI_B1_L (OMAP1610_DMA_LCD_BASE + 0xda) -#define OMAP1610_DMA_LCD_SRC_EN_B1 (OMAP1610_DMA_LCD_BASE + 0xe0) -#define OMAP1610_DMA_LCD_SRC_FN_B1 (OMAP1610_DMA_LCD_BASE + 0xe4) -#define OMAP1610_DMA_LCD_LCH_CTRL (OMAP1610_DMA_LCD_BASE + 0xea) -#define OMAP1610_DMA_LCD_SRC_FI_B1_U (OMAP1610_DMA_LCD_BASE + 0xf4) +#define OMAP_DMA_CAPS_0_U_REG (OMAP_DMA_BASE + 0x44e) +#define OMAP_DMA_CAPS_0_L_REG (OMAP_DMA_BASE + 0x450) +#define OMAP_DMA_CAPS_1_U_REG (OMAP_DMA_BASE + 0x452) +#define OMAP_DMA_CAPS_1_L_REG (OMAP_DMA_BASE + 0x454) +#define OMAP_DMA_CAPS_2_REG (OMAP_DMA_BASE + 0x456) +#define OMAP_DMA_CAPS_3_REG (OMAP_DMA_BASE + 0x458) +#define OMAP_DMA_CAPS_4_REG (OMAP_DMA_BASE + 0x45a) +#define OMAP_DMA_PCH2_SR_REG (OMAP_DMA_BASE + 0x460) +#define OMAP_DMA_PCH0_SR_REG (OMAP_DMA_BASE + 0x480) +#define OMAP_DMA_PCH1_SR_REG (OMAP_DMA_BASE + 0x482) +#define OMAP_DMA_PCHD_SR_REG (OMAP_DMA_BASE + 0x4c0) + +#define OMAP1510_DMA_LCD_CTRL 0xfffedb00 +#define OMAP1510_DMA_LCD_TOP_F1_L 0xfffedb02 +#define OMAP1510_DMA_LCD_TOP_F1_U 0xfffedb04 +#define OMAP1510_DMA_LCD_BOT_F1_L 0xfffedb06 +#define OMAP1510_DMA_LCD_BOT_F1_U 0xfffedb08 + +#define OMAP1610_DMA_LCD_CSDP 0xfffee3c0 +#define OMAP1610_DMA_LCD_CCR 0xfffee3c2 +#define OMAP1610_DMA_LCD_CTRL 0xfffee3c4 +#define OMAP1610_DMA_LCD_TOP_B1_L 0xfffee3c8 +#define OMAP1610_DMA_LCD_TOP_B1_U 0xfffee3ca +#define OMAP1610_DMA_LCD_BOT_B1_L 0xfffee3cc +#define OMAP1610_DMA_LCD_BOT_B1_U 0xfffee3ce +#define OMAP1610_DMA_LCD_TOP_B2_L 0xfffee3d0 +#define OMAP1610_DMA_LCD_TOP_B2_U 0xfffee3d2 +#define OMAP1610_DMA_LCD_BOT_B2_L 0xfffee3d4 +#define OMAP1610_DMA_LCD_BOT_B2_U 0xfffee3d6 +#define OMAP1610_DMA_LCD_SRC_EI_B1 0xfffee3d8 +#define OMAP1610_DMA_LCD_SRC_FI_B1_L 0xfffee3da +#define OMAP1610_DMA_LCD_SRC_EN_B1 0xfffee3e0 +#define OMAP1610_DMA_LCD_SRC_FN_B1 0xfffee3e4 +#define OMAP1610_DMA_LCD_LCH_CTRL 0xfffee3ea +#define OMAP1610_DMA_LCD_SRC_FI_B1_U 0xfffee3f4 /* Every LCh has its own set of the registers below */ -#define OMAP_DMA_CSDP(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x00) -#define OMAP_DMA_CCR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x02) -#define OMAP_DMA_CICR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x04) -#define OMAP_DMA_CSR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x06) -#define OMAP_DMA_CSSA_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x08) -#define OMAP_DMA_CSSA_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0a) -#define OMAP_DMA_CDSA_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0c) -#define OMAP_DMA_CDSA_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0e) -#define OMAP_DMA_CEN(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x10) -#define OMAP_DMA_CFN(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x12) -#define OMAP_DMA_CSFI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x14) -#define OMAP_DMA_CSEI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x16) -#define OMAP_DMA_CSAC(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x18) -#define OMAP_DMA_CDAC(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1a) -#define OMAP_DMA_CDEI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1c) -#define OMAP_DMA_CDFI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1e) -#define OMAP_DMA_COLOR_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x20) -#define OMAP_DMA_COLOR_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x22) -#define OMAP_DMA_CCR2(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x24) -#define OMAP_DMA_CLNK_CTRL(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x28) -#define OMAP_DMA_LCH_CTRL(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x2a) +#define OMAP_DMA_CSDP_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x00) +#define OMAP_DMA_CCR_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x02) +#define OMAP_DMA_CICR_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x04) +#define OMAP_DMA_CSR_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x06) +#define OMAP_DMA_CSSA_L_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x08) +#define OMAP_DMA_CSSA_U_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0a) +#define OMAP_DMA_CDSA_L_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0c) +#define OMAP_DMA_CDSA_U_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0e) +#define OMAP_DMA_CEN_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x10) +#define OMAP_DMA_CFN_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x12) +#define OMAP_DMA_CSFI_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x14) +#define OMAP_DMA_CSEI_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x16) +#define OMAP_DMA_CSAC_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x18) +#define OMAP_DMA_CDAC_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1a) +#define OMAP_DMA_CDEI_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1c) +#define OMAP_DMA_CDFI_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1e) +#define OMAP_DMA_COLOR_L_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x20) +#define OMAP_DMA_COLOR_U_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x22) +#define OMAP_DMA_CCR2_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x24) +#define OMAP_DMA_CLNK_CTRL_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x28) +#define OMAP_DMA_LCH_CTRL_REG(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x2a) #define OMAP_DMA_TOUT_IRQ (1 << 0) #define OMAP_DMA_DROP_IRQ (1 << 1) @@ -194,11 +192,6 @@ enum { OMAP_LCD_DMA_B2_BOTTOM }; -enum { - OMAP_DMA_DATA_BURST_4, - OMAP_DMA_DATA_BURST_8 -}; - extern int omap_request_dma(int dev_id, const char *dev_name, void (* callback)(int lch, u16 ch_status, void *data), void *data, int *dma_ch); @@ -210,20 +203,10 @@ extern void omap_stop_dma(int lch); extern void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, int frame_count, int sync_mode); -extern void omap_set_dma_constant_fill(int lch, u32 color); -extern void omap_set_dma_transparent_copy(int lch, u32 color); - extern void omap_set_dma_src_params(int lch, int src_port, int src_amode, unsigned long src_start); -extern void omap_set_dma_src_index(int lch, int eidx, int fidx); -extern void omap_set_dma_src_data_pack(int lch, int enable); -extern void omap_set_dma_src_burst_mode(int lch, int burst_mode); - extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, unsigned long dest_start); -extern void omap_set_dma_dest_index(int lch, int eidx, int fidx); -extern void omap_set_dma_dest_data_pack(int lch, int enable); -extern void omap_set_dma_dest_burst_mode(int lch, int burst_mode); extern void omap_dma_link_lch (int lch_head, int lch_queue); extern void omap_dma_unlink_lch (int lch_head, int lch_queue); diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h index 348072bc4..c3889427a 100644 --- a/include/asm-arm/arch-omap/hardware.h +++ b/include/asm-arm/arch-omap/hardware.h @@ -10,7 +10,6 @@ * Author: RidgeRun, Inc. Greg Lonnon * * Reorganized for Linux-2.6 by Tony Lindgren - * and Dirk Behme * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -41,7 +40,49 @@ #ifndef __ASSEMBLER__ #include #endif -#include + +/* + * ---------------------------------------------------------------------------- + * I/O mapping + * ---------------------------------------------------------------------------- + */ +#define IO_PHYS 0xFFFB0000 +#define IO_OFFSET 0x01000000 /* Virtual IO = 0xfefb0000 */ +#define IO_VIRT (IO_PHYS - IO_OFFSET) +#define IO_SIZE 0x40000 +#define IO_ADDRESS(x) ((x) - IO_OFFSET) + +#define PCIO_BASE 0 + +#define io_p2v(x) ((x) - IO_OFFSET) +#define io_v2p(x) ((x) + IO_OFFSET) + +#ifndef __ASSEMBLER__ + +/* 16 bit uses LDRH/STRH, base +/- offset_8 */ +typedef struct { volatile u16 offset[256]; } __regbase16; +#define __REGV16(vaddr) ((__regbase16 *)((vaddr)&~0xff)) \ + ->offset[((vaddr)&0xff)>>1] +#define __REG16(paddr) __REGV16(io_p2v(paddr)) + +/* 8/32 bit uses LDR/STR, base +/- offset_12 */ +typedef struct { volatile u8 offset[4096]; } __regbase8; +#define __REGV8(vaddr) ((__regbase8 *)((paddr)&~4095)) \ + ->offset[((paddr)&4095)>>0] +#define __REG8(paddr) __REGV8(io_p2v(paddr)) + +typedef struct { volatile u32 offset[4096]; } __regbase32; +#define __REGV32(vaddr) ((__regbase32 *)((vaddr)&~4095)) \ + ->offset[((vaddr)&4095)>>2] +#define __REG32(paddr) __REGV32(io_p2v(paddr)) + +#else + +#define __REG8(paddr) io_p2v(paddr) +#define __REG16(paddr) io_p2v(paddr) +#define __REG32(paddr) io_p2v(paddr) + +#endif /* * --------------------------------------------------------------------------- @@ -56,14 +97,14 @@ * Clocks * ---------------------------------------------------------------------------- */ -#define CLKGEN_REG_BASE (0xfffece00) -#define ARM_CKCTL (CLKGEN_REG_BASE + 0x0) -#define ARM_IDLECT1 (CLKGEN_REG_BASE + 0x4) -#define ARM_IDLECT2 (CLKGEN_REG_BASE + 0x8) -#define ARM_EWUPCT (CLKGEN_REG_BASE + 0xC) -#define ARM_RSTCT1 (CLKGEN_REG_BASE + 0x10) -#define ARM_RSTCT2 (CLKGEN_REG_BASE + 0x14) -#define ARM_SYSST (CLKGEN_REG_BASE + 0x18) +#define CLKGEN_RESET_BASE (0xfffece00) +#define ARM_CKCTL (CLKGEN_RESET_BASE + 0x0) +#define ARM_IDLECT1 (CLKGEN_RESET_BASE + 0x4) +#define ARM_IDLECT2 (CLKGEN_RESET_BASE + 0x8) +#define ARM_EWUPCT (CLKGEN_RESET_BASE + 0xC) +#define ARM_RSTCT1 (CLKGEN_RESET_BASE + 0x10) +#define ARM_RSTCT2 (CLKGEN_RESET_BASE + 0x14) +#define ARM_SYSST (CLKGEN_RESET_BASE + 0x18) #define CK_RATEF 1 #define CK_IDLEF 2 @@ -72,27 +113,19 @@ #define SETARM_IDLE_SHIFT /* DPLL control registers */ -#define DPLL_CTL (0xfffecf00) +#define DPLL_CTL_REG (0xfffecf00) +#define CK_DPLL1 (0xfffecf00) -/* DSP clock control */ -#define DSP_CONFIG_REG_BASE (0xe1008000) -#define DSP_IDLECT1 (DSP_CONFIG_REG_BASE + 0x4) -#define DSP_IDLECT2 (DSP_CONFIG_REG_BASE + 0x8) - -/* - * --------------------------------------------------------------------------- - * UPLD - * --------------------------------------------------------------------------- - */ +/* ULPD */ #define ULPD_REG_BASE (0xfffe0800) -#define ULPD_IT_STATUS (ULPD_REG_BASE + 0x14) -#define ULPD_CLOCK_CTRL (ULPD_REG_BASE + 0x30) -#define ULPD_SOFT_REQ (ULPD_REG_BASE + 0x34) -#define ULPD_DPLL_CTRL (ULPD_REG_BASE + 0x3c) -#define ULPD_STATUS_REQ (ULPD_REG_BASE + 0x40) -#define ULPD_APLL_CTRL (ULPD_REG_BASE + 0x4c) -#define ULPD_POWER_CTRL (ULPD_REG_BASE + 0x50) -#define ULPD_CAM_CLK_CTRL (ULPD_REG_BASE + 0x7c) +#define ULPD_IT_STATUS_REG (ULPD_REG_BASE + 0x14) +#define ULPD_CLOCK_CTRL_REG (ULPD_REG_BASE + 0x30) +#define ULPD_SOFT_REQ_REG (ULPD_REG_BASE + 0x34) +#define ULPD_DPLL_CTRL_REG (ULPD_REG_BASE + 0x3c) +#define ULPD_STATUS_REQ_REG (ULPD_REG_BASE + 0x40) +#define ULPD_APLL_CTRL_REG (ULPD_REG_BASE + 0x4c) +#define ULPD_POWER_CTRL_REG (ULPD_REG_BASE + 0x50) +#define ULPD_CAM_CLK_CTRL_REG (ULPD_REG_BASE + 0x7c) /* * --------------------------------------------------------------------------- @@ -113,24 +146,18 @@ #define TIMER32k_ARL (1<<3) /* MPU Timer base addresses */ -#define OMAP_TIMER1_BASE (0xfffec500) -#define OMAP_TIMER2_BASE (0xfffec600) -#define OMAP_TIMER3_BASE (0xfffec700) -#define OMAP_MPUTIMER_BASE OMAP_TIMER1_BASE -#define OMAP_MPUTIMER_OFFSET 0x100 +#define OMAP_MPUTIMER_BASE 0xfffec500 +#define OMAP_MPUTIMER_OFF 0x00000100 -/* MPU Timer Registers */ -#define OMAP_TIMER1_CNTL (OMAP_TIMER_BASE1 + 0x0) -#define OMAP_TIMER1_LOAD_TIM (OMAP_TIMER_BASE1 + 0x4) -#define OMAP_TIMER1_READ_TIM (OMAP_TIMER_BASE1 + 0x8) +#define OMAP_TIMER1_BASE 0xfffec500 +#define OMAP_TIMER2_BASE 0xfffec600 +#define OMAP_TIMER3_BASE 0xfffec700 +#define OMAP_WATCHDOG_BASE 0xfffec800 -#define OMAP_TIMER2_CNTL (OMAP_TIMER_BASE2 + 0x0) -#define OMAP_TIMER2_LOAD_TIM (OMAP_TIMER_BASE2 + 0x4) -#define OMAP_TIMER2_READ_TIM (OMAP_TIMER_BASE2 + 0x8) - -#define OMAP_TIMER3_CNTL (OMAP_TIMER_BASE3 + 0x0) -#define OMAP_TIMER3_LOAD_TIM (OMAP_TIMER_BASE3 + 0x4) -#define OMAP_TIMER3_READ_TIM (OMAP_TIMER_BASE3 + 0x8) +/* MPU Timer Registers */ +#define CNTL_TIMER 0 +#define LOAD_TIM 4 +#define READ_TIM 8 /* CNTL_TIMER register bits */ #define MPUTIM_FREE (1<<6) @@ -140,13 +167,6 @@ #define MPUTIM_AR (1<<1) #define MPUTIM_ST (1<<0) -/* Watchdog */ -#define OMAP_WATCHDOG_BASE (0xfffec800) -#define OMAP_WDT_TIMER (OMAP_WATCHDOG_BASE + 0x0) -#define OMAP_WDT_LOAD_TIM (OMAP_WATCHDOG_BASE + 0x4) -#define OMAP_WDT_READ_TIM (OMAP_WATCHDOG_BASE + 0x4) -#define OMAP_WDT_TIMER_MODE (OMAP_WATCHDOG_BASE + 0x8) - /* * --------------------------------------------------------------------------- * Interrupts @@ -154,30 +174,22 @@ */ #define OMAP_IH1_BASE 0xfffecb00 #define OMAP_IH2_BASE 0xfffe0000 - -#define OMAP_IH1_ITR (OMAP_IH1_BASE + 0x00) -#define OMAP_IH1_MIR (OMAP_IH1_BASE + 0x04) -#define OMAP_IH1_SIR_IRQ (OMAP_IH1_BASE + 0x10) -#define OMAP_IH1_SIR_FIQ (OMAP_IH1_BASE + 0x14) -#define OMAP_IH1_CONTROL (OMAP_IH1_BASE + 0x18) -#define OMAP_IH1_ILR0 (OMAP_IH1_BASE + 0x1c) -#define OMAP_IH1_ISR (OMAP_IH1_BASE + 0x9c) - -#define OMAP_IH2_ITR (OMAP_IH2_BASE + 0x00) -#define OMAP_IH2_MIR (OMAP_IH2_BASE + 0x04) -#define OMAP_IH2_SIR_IRQ (OMAP_IH2_BASE + 0x10) -#define OMAP_IH2_SIR_FIQ (OMAP_IH2_BASE + 0x14) -#define OMAP_IH2_CONTROL (OMAP_IH2_BASE + 0x18) -#define OMAP_IH2_ILR0 (OMAP_IH2_BASE + 0x1c) -#define OMAP_IH2_ISR (OMAP_IH2_BASE + 0x9c) - -#define IRQ_ITR_REG_OFFSET 0x00 -#define IRQ_MIR_REG_OFFSET 0x04 -#define IRQ_SIR_IRQ_REG_OFFSET 0x10 -#define IRQ_SIR_FIQ_REG_OFFSET 0x14 -#define IRQ_CONTROL_REG_OFFSET 0x18 -#define IRQ_ISR_REG_OFFSET 0x9c -#define IRQ_ILR0_REG_OFFSET 0x1c +#define OMAP_ITR 0x0 +#define OMAP_MASK 0x4 + +#define IRQ_ITR 0x00 +#define IRQ_MIR 0x04 +#define IRQ_SIR_IRQ 0x10 +#define IRQ_SIR_FIQ 0x14 +#define IRQ_CONTROL_REG 0x18 +#define IRQ_ISR 0x9c +#define IRQ_ILR0 0x1c + +/* OMAP-1610 specific interrupt handler registers */ +#define OMAP_IH2_SECT1 (OMAP_IH2_BASE) +#define OMAP_IH2_SECT2 (OMAP_IH2_BASE + 0x100) +#define OMAP_IH2_SECT3 (OMAP_IH2_BASE + 0x200) +#define OMAP_IH2_SECT4 (OMAP_IH2_BASE + 0x300) /* * --------------------------------------------------------------------------- @@ -186,9 +198,9 @@ */ #define TCMIF_BASE 0xfffecc00 #define IMIF_PRIO (TCMIF_BASE + 0x00) -#define EMIFS_PRIO (TCMIF_BASE + 0x04) -#define EMIFF_PRIO (TCMIF_BASE + 0x08) -#define EMIFS_CONFIG (TCMIF_BASE + 0x0c) +#define EMIFS_PRIO_REG (TCMIF_BASE + 0x04) +#define EMIFF_PRIO_REG (TCMIF_BASE + 0x08) +#define EMIFS_CONFIG_REG (TCMIF_BASE + 0x0c) #define EMIFS_CS0_CONFIG (TCMIF_BASE + 0x10) #define EMIFS_CS1_CONFIG (TCMIF_BASE + 0x14) #define EMIFS_CS2_CONFIG (TCMIF_BASE + 0x18) @@ -201,6 +213,7 @@ #define TC_ENDIANISM (TCMIF_BASE + 0x34) #define EMIFF_SDRAM_CONFIG_2 (TCMIF_BASE + 0x3c) #define EMIF_CFG_DYNAMIC_WS (TCMIF_BASE + 0x40) + /* * ---------------------------------------------------------------------------- * System control registers @@ -252,24 +265,25 @@ * --------------------------------------------------------------------------- */ #define TIPB_PUBLIC_CNTL_BASE 0xfffed300 -#define MPU_PUBLIC_TIPB_CNTL (TIPB_PUBLIC_CNTL_BASE + 0x8) +#define MPU_PUBLIC_TIPB_CNTL_REG (TIPB_PUBLIC_CNTL_BASE + 0x8) #define TIPB_PRIVATE_CNTL_BASE 0xfffeca00 -#define MPU_PRIVATE_TIPB_CNTL (TIPB_PRIVATE_CNTL_BASE + 0x8) +#define MPU_PRIVATE_TIPB_CNTL_REG (TIPB_PRIVATE_CNTL_BASE + 0x8) /* * ---------------------------------------------------------------------------- - * MPUI interface + * DSP control registers * ---------------------------------------------------------------------------- */ -#define MPUI_BASE (0xfffec900) -#define MPUI_CTRL (MPUI_BASE + 0x0) -#define MPUI_DEBUG_ADDR (MPUI_BASE + 0x4) -#define MPUI_DEBUG_DATA (MPUI_BASE + 0x8) -#define MPUI_DEBUG_FLAG (MPUI_BASE + 0xc) -#define MPUI_STATUS_REG (MPUI_BASE + 0x10) -#define MPUI_DSP_STATUS (MPUI_BASE + 0x14) -#define MPUI_DSP_BOOT_CONFIG (MPUI_BASE + 0x18) -#define MPUI_DSP_API_CONFIG (MPUI_BASE + 0x1c) +/* MPUI Interface Registers */ +#define MPUI_CTRL_REG (0xfffec900) +#define MPUI_DEBUG_ADDR (0xfffec904) +#define MPUI_DEBUG_DATA (0xfffec908) +#define MPUI_DEBUG_FLAG (0xfffec90c) +#define MPUI_STATUS_REG (0xfffec910) +#define MPUI_DSP_STATUS_REG (0xfffec914) +#define MPUI_DSP_BOOT_CONFIG (0xfffec918) +#define MPUI_DSP_API_CONFIG (0xfffec91c) + #ifndef __ASSEMBLER__ @@ -278,38 +292,34 @@ * Processor differentiation * --------------------------------------------------------------------------- */ -#define OMAP_ID_BASE (0xfffed400) -#define OMAP_ID_REG __REG32(OMAP_ID_BASE + 0x04) - -#define ID_SHIFT 12 -#define ID_MASK 0x7fff +#define OMAP_ID_REG __REG32(0xfffed404) /* See also uncompress.h */ -#define OMAP_ID_730 0x355F -#define OMAP_ID_1510 0x3470 -#define OMAP_ID_1610 0x3576 -#define OMAP_ID_1710 0x35F7 -#define OMAP_ID_5912 0x358C +#define OMAP_ID_730 0xB55F +#define OMAP_ID_1510 0xB470 +#define OMAP_ID_1610 0xB576 +#define OMAP_ID_1710 0xB5F7 +#define OMAP_ID_5912 0xB58C #ifdef CONFIG_ARCH_OMAP730 #include "omap730.h" -#define cpu_is_omap730() (((OMAP_ID_REG >> ID_SHIFT) & ID_MASK) == OMAP_ID_730) +#define cpu_is_omap730() (((OMAP_ID_REG >> 12) & 0xffff) == OMAP_ID_730) #else #define cpu_is_omap730() 0 #endif #ifdef CONFIG_ARCH_OMAP1510 #include "omap1510.h" -#define cpu_is_omap1510() (((OMAP_ID_REG >> ID_SHIFT) & ID_MASK) == OMAP_ID_1510) +#define cpu_is_omap1510() (((OMAP_ID_REG >> 12) & 0xffff) == OMAP_ID_1510) #else #define cpu_is_omap1510() 0 #endif #ifdef CONFIG_ARCH_OMAP1610 #include "omap1610.h" -#define cpu_is_omap1710() (((OMAP_ID_REG >> ID_SHIFT) & ID_MASK) == OMAP_ID_1710) +#define cpu_is_omap1710() (((OMAP_ID_REG >> 12) & 0xffff) == OMAP_ID_1710) /* Detect 1710 as 1610 for now */ -#define cpu_is_omap1610() (((OMAP_ID_REG >> ID_SHIFT) & ID_MASK) == OMAP_ID_1610 \ +#define cpu_is_omap1610() (((OMAP_ID_REG >> 12) & 0xffff) == OMAP_ID_1610 \ || cpu_is_omap1710()) #else #define cpu_is_omap1610() 0 @@ -318,7 +328,7 @@ #ifdef CONFIG_ARCH_OMAP5912 #include "omap5912.h" -#define cpu_is_omap5912() (((OMAP_ID_REG >> ID_SHIFT) & ID_MASK) == OMAP_ID_5912) +#define cpu_is_omap5912() (((OMAP_ID_REG >> 12) & 0xffff) == OMAP_ID_5912) #else #define cpu_is_omap5912() 0 #endif diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h index 405395706..a5ecbec21 100644 --- a/include/asm-arm/arch-omap/mux.h +++ b/include/asm-arm/arch-omap/mux.h @@ -140,20 +140,16 @@ typedef enum { R18_1510_USB_GPIO0, W4_USB_PUEN, W4_USB_CLKO, - W4_USB_HIGHZ, - W4_GPIO58, /* USB1 master */ USB1_SUSP, USB1_SEO, - W13_1610_USB1_SE0, USB1_TXEN, USB1_TXD, USB1_VP, USB1_VM, USB1_RCV, USB1_SPEED, - R13_1610_USB1_SPEED, /* USB2 master */ USB2_SUSP, @@ -220,7 +216,6 @@ typedef enum { /* OMAP-1610 GPIO */ P20_1610_GPIO4, V9_1610_GPIO7, - W8_1610_GPIO9, N19_1610_GPIO13, P10_1610_GPIO22, V5_1610_GPIO24, @@ -322,20 +317,16 @@ MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) MUX_CFG("R18_1510_USB_GPIO0", 7, 9, 0, 1, 11, 1, NA, 0, 1) MUX_CFG("W4_USB_PUEN", D, 3, 0, 3, 5, 1, NA, 0, 1) MUX_CFG("W4_USB_CLKO", D, 3, 1, 3, 5, 0, NA, 0, 1) -MUX_CFG("W4_USB_HIGHZ", D, 3, 4, 3, 5, 0, 3, 0, 1) -MUX_CFG("W4_GPIO58", D, 3, 7, 3, 5, 0, 3, 0, 1) /* USB1 master */ MUX_CFG("USB1_SUSP", 8, 27, 2, 1, 27, 0, NA, 0, 1) MUX_CFG("USB1_SE0", 9, 0, 2, 1, 28, 0, NA, 0, 1) -MUX_CFG("W13_1610_USB1_SE0", 9, 0, 4, 1, 28, 0, NA, 0, 1) MUX_CFG("USB1_TXEN", 9, 3, 2, 1, 29, 0, NA, 0, 1) MUX_CFG("USB1_TXD", 9, 24, 1, 2, 4, 0, NA, 0, 1) MUX_CFG("USB1_VP", A, 3, 1, 2, 7, 0, NA, 0, 1) MUX_CFG("USB1_VM", A, 6, 1, 2, 8, 0, NA, 0, 1) MUX_CFG("USB1_RCV", A, 9, 1, 2, 9, 0, NA, 0, 1) MUX_CFG("USB1_SPEED", A, 12, 2, 2, 10, 0, NA, 0, 1) -MUX_CFG("R13_1610_USB1_SPEED", A, 12, 5, 2, 10, 0, NA, 0, 1) /* USB2 master */ MUX_CFG("USB2_SUSP", B, 3, 1, 2, 17, 0, NA, 0, 1) @@ -403,7 +394,6 @@ MUX_CFG("J18_1610_ETM_D7", 5, 27, 1, 0, 19, 0, 0, 0, 1) /* OMAP-1610 GPIO */ MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1) MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1) -MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1) MUX_CFG("N19_1610_GPIO13", 6, 12, 0, 1, 2, 0, 1, 1, 1) MUX_CFG("P10_1610_GPIO22", C, 0, 7, 2, 26, 0, 2, 1, 1) MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1) @@ -415,7 +405,7 @@ MUX_CFG("U18_1610_UWIRE_SDI", 8, 0, 0, 1, 18, 0, 1, 1, 1) MUX_CFG("W21_1610_UWIRE_SDO", 8, 3, 0, 1, 19, 0, 1, 1, 1) MUX_CFG("N14_1610_UWIRE_CS0", 8, 9, 1, 1, 21, 0, 1, 1, 1) MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1) -MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1) +MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, NA, 0, 0, NA, 0, 0) /* First MMC interface, same on 1510 and 1610 */ MUX_CFG("MMC_CMD", A, 27, 0, 2, 15, 1, 2, 1, 1) diff --git a/include/asm-arm/arch-omap/uncompress.h b/include/asm-arm/arch-omap/uncompress.h index 9b287366d..f0b82d370 100644 --- a/include/asm-arm/arch-omap/uncompress.h +++ b/include/asm-arm/arch-omap/uncompress.h @@ -25,7 +25,7 @@ #define UART_OMAP_MDR1 0x08 /* mode definition register */ #define check_port(base, shift) ((base[UART_OMAP_MDR1 << shift] & 7) == 0) -#define omap_get_id() ((*(volatile unsigned int *)(0xfffed404)) >> 12) & ID_MASK +#define omap_get_id() ((*(volatile unsigned int *)(0xfffed404)) >> 12) & 0xffff static void puts(const char *s) diff --git a/include/asm-arm/arch-pxa/hardware.h b/include/asm-arm/arch-pxa/hardware.h index ffd2fa2eb..bd600bd0e 100644 --- a/include/asm-arm/arch-pxa/hardware.h +++ b/include/asm-arm/arch-pxa/hardware.h @@ -90,4 +90,13 @@ extern unsigned int get_lcdclk_frequency_10khz(void); #endif + +/* + * Implementation specifics + */ + +#include "lubbock.h" +#include "mainstone.h" +#include "idp.h" + #endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-pxa/ide.h b/include/asm-arm/arch-pxa/ide.h deleted file mode 100644 index a9efdce2b..000000000 --- a/include/asm-arm/arch-pxa/ide.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/include/asm-arm/arch-pxa/ide.h - * - * Author: George Davis - * Created: Jan 10, 2002 - * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h - * - */ - -#include -#include -#include - - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - int regincr = 1; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += regincr; - } - - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - - if (irq) - *irq = 0; -} - - -/* - * Register the standard ports for this architecture with the IDE driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ - /* Nothing to declare... */ -} diff --git a/include/asm-arm/arch-pxa/keyboard.h b/include/asm-arm/arch-pxa/keyboard.h deleted file mode 100644 index 7bec3179b..000000000 --- a/include/asm-arm/arch-pxa/keyboard.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * linux/include/asm-arm/arch-pxa/keyboard.h - * - * This file contains the architecture specific keyboard definitions - */ - -#ifndef _PXA_KEYBOARD_H -#define _PXA_KEYBOARD_H - -#include -#include - -extern struct kbd_ops_struct *kbd_ops; - -#define kbd_disable_irq() do { } while(0); -#define kbd_enable_irq() do { } while(0); - -extern int sa1111_kbd_init_hw(void); - -static inline void kbd_init_hw(void) -{ - if (machine_is_lubbock()) - sa1111_kbd_init_hw(); -} - - -#endif /* _PXA_KEYBOARD_H */ - diff --git a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h deleted file mode 100644 index 92c7030ab..000000000 --- a/include/asm-arm/arch-rpc/ide.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * linux/include/asm-arm/arch-rpc/ide.h - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - */ -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - if (irq) - *irq = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ - hw_regs_t hw; - - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); - hw.irq = IRQ_HARDDISK; - ide_register_hw(&hw, NULL); -} diff --git a/include/asm-arm/arch-s3c2410/ide.h b/include/asm-arm/arch-s3c2410/ide.h deleted file mode 100644 index de651e75d..000000000 --- a/include/asm-arm/arch-s3c2410/ide.h +++ /dev/null @@ -1,49 +0,0 @@ -/* linux/include/asm-arm/arch-s3c2410/ide.h - * - * Copyright (C) 1997 Russell King - * Copyright (C) 2003 Simtec Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code - * 16-05-2003 BJD Changed to work with BAST IDE ports - * 04-09-2003 BJD Modifications for V2.6 - */ - -#ifndef __ASM_ARCH_IDE_H -#define __ASM_ARCH_IDE_H - -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ - -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - if (irq) - *irq = 0; -} - -/* we initialise our ide devices from the main ide core, due to problems - * with doing it in this function -*/ - -#define ide_init_default_hwifs() do { } while(0) - -#endif /* __ASM_ARCH_IDE_H */ diff --git a/include/asm-arm/arch-sa1100/keyboard.h b/include/asm-arm/arch-sa1100/keyboard.h deleted file mode 100644 index 3dacd71d9..000000000 --- a/include/asm-arm/arch-sa1100/keyboard.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * linux/include/asm-arm/arch-sa1100/keyboard.h - * Created 16 Dec 1999 by Nicolas Pitre - * This file contains the SA1100 architecture specific keyboard definitions - */ -#ifndef _SA1100_KEYBOARD_H -#define _SA1100_KEYBOARD_H - -#include -#include - -extern void gc_kbd_init_hw(void); -extern void smartio_kbd_init_hw(void); - -static inline void kbd_init_hw(void) -{ - if (machine_is_graphicsclient()) - gc_kbd_init_hw(); - if (machine_is_adsbitsy()) - smartio_kbd_init_hw(); -} - -#endif /* _SA1100_KEYBOARD_H */ diff --git a/include/asm-arm/arch-shark/ide.h b/include/asm-arm/arch-shark/ide.h deleted file mode 100644 index f6a99b22f..000000000 --- a/include/asm-arm/arch-shark/ide.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * linux/include/asm-arm/arch-shark/ide.h - * - * by Alexander Schulz - * - * derived from: - * linux/include/asm-arm/arch-ebsa285/ide.h - * Copyright (c) 1998 Russell King - */ - -#include - -/* - * Set up a hw structure for a specified data port, control port and IRQ. - * This should follow whatever the default interface uses. - */ -static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - if (irq) - *irq = 0; -} - -/* - * This registers the standard ports for this architecture with the IDE - * driver. - */ -static __inline__ void -ide_init_default_hwifs(void) -{ - hw_regs_t hw; - - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); - hw.irq = 14; - ide_register_hw(&hw,NULL); -} - diff --git a/include/asm-arm/arch-shark/keyboard.h b/include/asm-arm/arch-shark/keyboard.h deleted file mode 100644 index 52b5ed6e1..000000000 --- a/include/asm-arm/arch-shark/keyboard.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * linux/include/asm-arm/arch-shark/keyboard.h - * by Alexander Schulz - * - * Derived from linux/include/asm-arm/arch-ebsa285/keyboard.h - * (C) 1998 Russell King - * (C) 1998 Phil Blundell - */ -#include -#include -#include -#include -#include - -#define KEYBOARD_IRQ IRQ_ISA_KEYBOARD -#define NR_SCANCODES 128 - -#define kbd_disable_irq() do { } while (0) -#define kbd_enable_irq() do { } while (0) - -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); -extern unsigned char pckbd_sysrq_xlate[128]; - -static inline void kbd_init_hw(void) -{ - k_setkeycode = pckbd_setkeycode; - k_getkeycode = pckbd_getkeycode; - k_translate = pckbd_translate; - k_unexpected_up = pckbd_unexpected_up; - k_leds = pckbd_leds; -#ifdef CONFIG_MAGIC_SYSRQ - k_sysrq_key = 0x54; - k_sysrq_xlate = pckbd_sysrq_xlate; -#endif - pckbd_init_hw(); -} - -/* - * PC Keyboard specifics - */ - -/* resource allocation */ -#define kbd_request_region() request_region(0x60, 16, "keyboard") -#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ - "keyboard", NULL) - -/* How to access the keyboard macros on this platform. */ -#define kbd_read_input() inb(KBD_DATA_REG) -#define kbd_read_status() inb(KBD_STATUS_REG) -#define kbd_write_output(val) outb(val, KBD_DATA_REG) -#define kbd_write_command(val) outb(val, KBD_CNTL_REG) - -/* Some stoneage hardware needs delays after some operations. */ -#define kbd_pause() do { } while(0) - -/* - * Machine specific bits for the PS/2 driver - */ -#define aux_request_irq(hand, dev_id) \ - request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) - -#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) diff --git a/include/asm-arm/arch-tbox/ide.h b/include/asm-arm/arch-tbox/ide.h deleted file mode 100644 index d66e67c94..000000000 --- a/include/asm-arm/arch-tbox/ide.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * linux/include/asm-arm/arch-tbox/ide.h - */ diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index 048ed44db..224c8d729 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -291,7 +291,17 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr) * about to change to user space. This is the same method as used on SPARC64. * See update_mmu_cache for the user space part. */ -extern void flush_dcache_page(struct page *); +extern void __flush_dcache_page(struct page *); + +static inline void flush_dcache_page(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else + __flush_dcache_page(page); +} #define flush_dcache_mmap_lock(mapping) \ spin_lock_irq(&(mapping)->tree_lock) diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h new file mode 100644 index 000000000..2fbf6078b --- /dev/null +++ b/include/asm-arm/hardware/clock.h @@ -0,0 +1,121 @@ +/* + * linux/include/asm-arm/hardware/clock.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASMARM_CLOCK_H +#define ASMARM_CLOCK_H + +struct device; + +/* + * The base API. + */ + + +/* + * struct clk - an machine class defined object / cookie. + */ +struct clk; + +/** + * clk_get - lookup and obtain a reference to a clock producer. + * @dev: device for clock "consumer" + * @id: device ID + * + * Returns a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. + */ +struct clk *clk_get(struct device *dev, const char *id); + +/** + * clk_enable - inform the system when the clock source should be running. + * @clk: clock source + * + * If the clock can not be enabled/disabled, this should return success. + * + * Returns success (0) or negative errno. + */ +int clk_enable(struct clk *clk); + +/** + * clk_disable - inform the system when the clock source is no longer required. + * @clk: clock source + */ +void clk_disable(struct clk *clk); + +/** + * clk_use - increment the use count + * @clk: clock source + * + * Returns success (0) or negative errno. + */ +int clk_use(struct clk *clk); + +/** + * clk_unuse - decrement the use count + * @clk: clock source + */ +void clk_unuse(struct clk *clk); + +/** + * clk_get_rate - obtain the current clock rate for a clock source. + * This is only valid once the clock source has been enabled. + * @clk: clock source + */ +unsigned long clk_get_rate(struct clk *clk); + +/** + * clk_put - "free" the clock source + * @clk: clock source + */ +void clk_put(struct clk *clk); + + +/* + * The remaining APIs are optional for machine class support. + */ + + +/** + * clk_round_rate - adjust a rate to the exact rate a clock can provide + * @clk: clock source + * @rate: desired clock rate in kHz + * + * Returns rounded clock rate, or negative errno. + */ +long clk_round_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_rate - set the clock rate for a clock source + * @clk: clock source + * @rate: desired clock rate in kHz + * + * Returns success (0) or negative errno. + */ +int clk_set_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_parent - set the parent clock source for this clock + * @clk: clock source + * @parent: parent clock source + * + * Returns success (0) or negative errno. + */ +int clk_set_parent(struct clk *clk, struct clk *parent); + +/** + * clk_get_parent - get the parent clock source for this clock + * @clk: clock source + * + * Returns struct clk corresponding to parent clock source, or + * valid IS_ERR() condition containing errno. + */ +struct clk *clk_get_parent(struct clk *clk); + +#endif diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 14ac954a1..c561da379 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -312,13 +312,6 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG); flush_pmd_entry(pmdp); \ } while (0) -#define copy_pmd(pmdpd,pmdps) \ - do { \ - pmdpd[0] = pmdps[0]; \ - pmdpd[1] = pmdps[1]; \ - flush_pmd_entry(pmdpd); \ - } while (0) - #define pmd_clear(pmdp) \ do { \ pmdp[0] = __pmd(0); \ diff --git a/include/asm-arm/relay.h b/include/asm-arm/relay.h new file mode 100644 index 000000000..f9913f1b1 --- /dev/null +++ b/include/asm-arm/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_ARM_RELAY_H +#define _ASM_ARM_RELAY_H + +#include +#endif diff --git a/include/asm-arm/resource.h b/include/asm-arm/resource.h index 9da87b622..0e42fa868 100644 --- a/include/asm-arm/resource.h +++ b/include/asm-arm/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-arm/rmap.h b/include/asm-arm/rmap.h deleted file mode 100644 index bb9ee93c1..000000000 --- a/include/asm-arm/rmap.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ARM_RMAP_H -#define _ARM_RMAP_H - -#include - -#endif /* _ARM_RMAP_H */ diff --git a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h index ab3cad4fb..a21e6a01e 100644 --- a/include/asm-arm/tlb.h +++ b/include/asm-arm/tlb.h @@ -58,7 +58,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) if (rss < freed) freed = rss; - mm->rss = rss - freed; + // mm->rss = rss - freed; + vx_rsspages_sub(mm, freed); if (freed) { flush_tlb_mm(mm); diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 1435eb396..5cd716591 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -466,7 +466,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-arm/vfp.h b/include/asm-arm/vfp.h new file mode 100644 index 000000000..14c5e0946 --- /dev/null +++ b/include/asm-arm/vfp.h @@ -0,0 +1,78 @@ +/* + * linux/include/asm-arm/vfp.h + * + * VFP register definitions. + * First, the standard VFP set. + */ + +#define FPSID cr0 +#define FPSCR cr1 +#define FPEXC cr8 + +/* FPSID bits */ +#define FPSID_IMPLEMENTER_BIT (24) +#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT) +#define FPSID_SOFTWARE (1<<23) +#define FPSID_FORMAT_BIT (21) +#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT) +#define FPSID_NODOUBLE (1<<20) +#define FPSID_ARCH_BIT (16) +#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT) +#define FPSID_PART_BIT (8) +#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT) +#define FPSID_VARIANT_BIT (4) +#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT) +#define FPSID_REV_BIT (0) +#define FPSID_REV_MASK (0xF << FPSID_REV_BIT) + +/* FPEXC bits */ +#define FPEXC_EXCEPTION (1<<31) +#define FPEXC_ENABLE (1<<30) + +/* FPSCR bits */ +#define FPSCR_DEFAULT_NAN (1<<25) +#define FPSCR_FLUSHTOZERO (1<<24) +#define FPSCR_ROUND_NEAREST (0<<22) +#define FPSCR_ROUND_PLUSINF (1<<22) +#define FPSCR_ROUND_MINUSINF (2<<22) +#define FPSCR_ROUND_TOZERO (3<<22) +#define FPSCR_RMODE_BIT (22) +#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT) +#define FPSCR_STRIDE_BIT (20) +#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT) +#define FPSCR_LENGTH_BIT (16) +#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT) +#define FPSCR_IOE (1<<8) +#define FPSCR_DZE (1<<9) +#define FPSCR_OFE (1<<10) +#define FPSCR_UFE (1<<11) +#define FPSCR_IXE (1<<12) +#define FPSCR_IDE (1<<15) +#define FPSCR_IOC (1<<0) +#define FPSCR_DZC (1<<1) +#define FPSCR_OFC (1<<2) +#define FPSCR_UFC (1<<3) +#define FPSCR_IXC (1<<4) +#define FPSCR_IDC (1<<7) + +/* + * VFP9-S specific. + */ +#define FPINST cr9 +#define FPINST2 cr10 + +/* FPEXC bits */ +#define FPEXC_FPV2 (1<<28) +#define FPEXC_LENGTH_BIT (8) +#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT) +#define FPEXC_INV (1 << 7) +#define FPEXC_UFC (1 << 3) +#define FPEXC_OFC (1 << 2) +#define FPEXC_IOC (1 << 0) + +/* Bit patterns for decoding the packaged operation descriptors */ +#define VFPOPDESC_LENGTH_BIT (9) +#define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT) +#define VFPOPDESC_UNUSED_BIT (24) +#define VFPOPDESC_UNUSED_MASK (0xFF << VFPOPDESC_UNUSED_BIT) +#define VFPOPDESC_OPDESC_MASK (~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK)) diff --git a/include/asm-arm/vfpmacros.h b/include/asm-arm/vfpmacros.h new file mode 100644 index 000000000..15bd6e74c --- /dev/null +++ b/include/asm-arm/vfpmacros.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-arm/vfpmacros.h + * + * Assembler-only file containing VFP macros and register definitions. + */ +#include "vfp.h" + +@ Macros to allow building with old toolkits (with no VFP support) + .macro VFPFMRX, rd, sysreg, cond + MRC\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMRX \rd, \sysreg + .endm + + .macro VFPFMXR, sysreg, rd, cond + MCR\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMXR \sysreg, \rd + .endm + + @ read all the working registers back into the VFP + .macro VFPFLDMIA, base + LDC p11, cr0, [\base],#33*4 @ FLDMIAX \base!, {d0-d15} + .endm + + @ write all the working registers out of the VFP + .macro VFPFSTMIA, base + STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15} + .endm diff --git a/include/asm-arm26/relay.h b/include/asm-arm26/relay.h new file mode 100644 index 000000000..f9913f1b1 --- /dev/null +++ b/include/asm-arm26/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_ARM_RELAY_H +#define _ASM_ARM_RELAY_H + +#include +#endif diff --git a/include/asm-arm26/resource.h b/include/asm-arm26/resource.h index 9da87b622..118700868 100644 --- a/include/asm-arm26/resource.h +++ b/include/asm-arm26/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-arm26/rmap.h b/include/asm-arm26/rmap.h deleted file mode 100644 index 6d5b6e092..000000000 --- a/include/asm-arm26/rmap.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _ARM_RMAP_H -#define _ARM_RMAP_H - -/* - * linux/include/asm-arm26/proc-armv/rmap.h - * - * Architecture dependant parts of the reverse mapping code, - * - * ARM is different since hardware page tables are smaller than - * the page size and Linux uses a "duplicate" one with extra info. - * For rmap this means that the first 2 kB of a page are the hardware - * page tables and the last 2 kB are the software page tables. - */ - -static inline void pgtable_add_rmap(struct page *page, struct mm_struct * mm, unsigned long address) -{ - page->mapping = (void *)mm; - page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); - inc_page_state(nr_page_table_pages); -} - -static inline void pgtable_remove_rmap(struct page *page) -{ - page->mapping = NULL; - page->index = 0; - dec_page_state(nr_page_table_pages); -} - -static inline struct mm_struct * ptep_to_mm(pte_t * ptep) -{ - struct page * page = virt_to_page(ptep); - return (struct mm_struct *)page->mapping; -} - -/* The page table takes half of the page */ -#define PTE_MASK ((PAGE_SIZE / 2) - 1) - -static inline unsigned long ptep_to_address(pte_t * ptep) -{ - struct page * page = virt_to_page(ptep); - unsigned long low_bits; - - low_bits = ((unsigned long)ptep & PTE_MASK) * PTRS_PER_PTE; - return page->index + low_bits; -} - -//FIXME!!! IS these correct? -static inline pte_addr_t ptep_to_paddr(pte_t *ptep) -{ - return (pte_addr_t)ptep; -} - -static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) -{ - return (pte_t *)pte_paddr; -} - -static inline void rmap_ptep_unmap(pte_t *pte) -{ - return; -} - - -//#include - -#endif /* _ARM_RMAP_H */ diff --git a/include/asm-arm26/tlb.h b/include/asm-arm26/tlb.h index ee6d11d86..214185e68 100644 --- a/include/asm-arm26/tlb.h +++ b/include/asm-arm26/tlb.h @@ -38,7 +38,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) if (rss < freed) freed = rss; - mm->rss = rss - freed; + // mm->rss = rss - freed; + vx_rsspages_sub(mm, freed); if (freed) { flush_tlb_mm(mm); diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h index e64b01117..432eafc7a 100644 --- a/include/asm-arm26/unistd.h +++ b/include/asm-arm26/unistd.h @@ -397,7 +397,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-cris/relay.h b/include/asm-cris/relay.h new file mode 100644 index 000000000..30ee42c13 --- /dev/null +++ b/include/asm-cris/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_CRIS_RELAY_H +#define _ASM_CRIS_RELAY_H + +#include +#endif diff --git a/include/asm-cris/resource.h b/include/asm-cris/resource.h index 83561dab9..78848fbb6 100644 --- a/include/asm-cris/resource.h +++ b/include/asm-cris/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-cris/rmap.h b/include/asm-cris/rmap.h deleted file mode 100644 index c5bf2a811..000000000 --- a/include/asm-cris/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _CRIS_RMAP_H -#define _CRIS_RMAP_H - -/* nothing to see, move along :) */ -#include - -#endif diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index 0b58c457b..71b7f6946 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h @@ -314,7 +314,6 @@ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-generic/relay.h b/include/asm-generic/relay.h new file mode 100644 index 000000000..c6d8dead8 --- /dev/null +++ b/include/asm-generic/relay.h @@ -0,0 +1,76 @@ +#ifndef _ASM_GENERIC_RELAY_H +#define _ASM_GENERIC_RELAY_H +/* + * linux/include/asm-generic/relay.h + * + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com) + * + * Architecture-independent definitions for relayfs + */ + +#include + +/** + * get_time_delta - utility function for getting time delta + * @now: pointer to a timeval struct that may be given current time + * @rchan: the channel + * + * Returns the time difference between the current time and the buffer + * start time. + */ +static inline u32 +get_time_delta(struct timeval *now, struct rchan *rchan) +{ + u32 time_delta; + + do_gettimeofday(now); + time_delta = calc_time_delta(now, &rchan->buf_start_time); + + return time_delta; +} + +/** + * get_timestamp - utility function for getting a time and TSC pair + * @now: current time + * @tsc: the TSC associated with now + * @rchan: the channel + * + * Sets the value pointed to by now to the current time. Value pointed to + * by tsc is not set since there is no generic TSC support. + */ +static inline void +get_timestamp(struct timeval *now, + u32 *tsc, + struct rchan *rchan) +{ + do_gettimeofday(now); +} + +/** + * get_time_or_tsc: - Utility function for getting a time or a TSC. + * @now: current time + * @tsc: current TSC + * @rchan: the channel + * + * Sets the value pointed to by now to the current time. + */ +static inline void +get_time_or_tsc(struct timeval *now, + u32 *tsc, + struct rchan *rchan) +{ + do_gettimeofday(now); +} + +/** + * have_tsc - does this platform have a useable TSC? + * + * Returns 0. + */ +static inline int +have_tsc(void) +{ + return 0; +} +#endif diff --git a/include/asm-generic/rmap.h b/include/asm-generic/rmap.h deleted file mode 100644 index f743d9f80..000000000 --- a/include/asm-generic/rmap.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _GENERIC_RMAP_H -#define _GENERIC_RMAP_H -/* - * linux/include/asm-generic/rmap.h - * - * Architecture dependent parts of the reverse mapping code, - * this version should work for most architectures with a - * 'normal' page table layout. - * - * We use the struct page of the page table page to find out - * the process and full address of a page table entry: - * - page->mapping points to the process' mm_struct - * - page->index has the high bits of the address - * - the lower bits of the address are calculated from the - * offset of the page table entry within the page table page - * - * For CONFIG_HIGHPTE, we need to represent the address of a pte in a - * scalar pte_addr_t. The pfn of the pte's page is shifted left by PAGE_SIZE - * bits and is then ORed with the byte offset of the pte within its page. - * - * For CONFIG_HIGHMEM4G, the pte_addr_t is 32 bits. 20 for the pfn, 12 for - * the offset. - * - * For CONFIG_HIGHMEM64G, the pte_addr_t is 64 bits. 52 for the pfn, 12 for - * the offset. - */ -#include - -static inline void pgtable_add_rmap(struct page * page, struct mm_struct * mm, unsigned long address) -{ -#ifdef BROKEN_PPC_PTE_ALLOC_ONE - /* OK, so PPC calls pte_alloc() before mem_map[] is setup ... ;( */ - extern int mem_init_done; - - if (!mem_init_done) - return; -#endif - page->mapping = (void *)mm; - page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); - inc_page_state(nr_page_table_pages); -} - -static inline void pgtable_remove_rmap(struct page * page) -{ - page->mapping = NULL; - page->index = 0; - dec_page_state(nr_page_table_pages); -} - -static inline struct mm_struct * ptep_to_mm(pte_t * ptep) -{ - struct page * page = kmap_atomic_to_page(ptep); - return (struct mm_struct *) page->mapping; -} - -static inline unsigned long ptep_to_address(pte_t * ptep) -{ - struct page * page = kmap_atomic_to_page(ptep); - unsigned long low_bits; - low_bits = ((unsigned long)ptep & (PTRS_PER_PTE*sizeof(pte_t) - 1)) - * (PAGE_SIZE/sizeof(pte_t)); - return page->index + low_bits; -} - -#ifdef CONFIG_HIGHPTE -static inline pte_addr_t ptep_to_paddr(pte_t *ptep) -{ - pte_addr_t paddr; - paddr = ((pte_addr_t)page_to_pfn(kmap_atomic_to_page(ptep))) << PAGE_SHIFT; - return paddr + (pte_addr_t)((unsigned long)ptep & ~PAGE_MASK); -} -#else -static inline pte_addr_t ptep_to_paddr(pte_t *ptep) -{ - return (pte_addr_t)ptep; -} -#endif - -#ifndef CONFIG_HIGHPTE -static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) -{ - return (pte_t *)pte_paddr; -} - -static inline void rmap_ptep_unmap(pte_t *pte) -{ - return; -} -#endif - -#endif /* _GENERIC_RMAP_H */ diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 1358c5136..aa7d3c093 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -15,6 +15,7 @@ #include #include +#include #include /* @@ -91,7 +92,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) if (rss < freed) freed = rss; - mm->rss = rss - freed; + // mm->rss = rss - freed; + vx_rsspages_sub(mm, freed); tlb_flush_mmu(tlb, start, end); /* keep the page table cache within bounds */ diff --git a/include/asm-h8300/aki3068net/machine-depend.h b/include/asm-h8300/aki3068net/machine-depend.h deleted file mode 100644 index 510b86b5d..000000000 --- a/include/asm-h8300/aki3068net/machine-depend.h +++ /dev/null @@ -1,29 +0,0 @@ -/* AE-3068 board depend header */ - -/* TIMER rate define */ -#ifdef H8300_TIMER_DEFINE -#define H8300_TIMER_COUNT_DATA 20000*10/8192 -#define H8300_TIMER_FREQ 20000*1000/8192 -#endif - -/* AE-3068 RTL8019AS Config */ -#ifdef H8300_NE_DEFINE - -#define NE2000_ADDR 0x200000 -#define NE2000_IRQ 5 -#define NE2000_BYTE volatile unsigned short - -#define WCRL 0xfee023 -#define MAR0A 0xffff20 -#define ETCR0A 0xffff24 -#define DTCR0A 0xffff27 -#define MAR0B 0xffff28 -#define DTCR0B 0xffff2f - -#define H8300_INIT_NE() \ -do { \ - wordlength = 1; \ - outb_p(0x48, ioaddr + EN0_DCFG); \ -} while(0) - -#endif diff --git a/include/asm-h8300/edosk2674/machine-depend.h b/include/asm-h8300/edosk2674/machine-depend.h deleted file mode 100644 index 1e98b40e5..000000000 --- a/include/asm-h8300/edosk2674/machine-depend.h +++ /dev/null @@ -1,70 +0,0 @@ -/* EDOSK2674 board depend header */ - -/* TIMER rate define */ -#ifdef H8300_TIMER_DEFINE -#define H8300_TIMER_COUNT_DATA 33000*10/8192 -#define H8300_TIMER_FREQ 33000*1000/8192 -#endif - -/* EDOSK-2674R SMSC Network Controler Target Depend impliments */ -#ifdef H8300_SMSC_DEFINE - -#define SMSC_BASE 0xf80000 -#define SMSC_IRQ 16 - -/* sorry quick hack */ -#if defined(outw) -# undef outw -#endif -#define outw(d,a) edosk2674_smsc_outw(d,(volatile unsigned short *)(a)) -#if defined(inw) -# undef inw -#endif -#define inw(a) edosk2674_smsc_inw((volatile unsigned short *)(a)) -#if defined(outsw) -# undef outsw -#endif -#define outsw(a,p,l) edosk2674_smsc_outsw((volatile unsigned short *)(a),p,l) -#if defined(insw) -# undef insw -#endif -#define insw(a,p,l) edosk2674_smsc_insw((volatile unsigned short *)(a),p,l) - -static inline void edosk2674_smsc_outw( - unsigned short d, - volatile unsigned short *a - ) -{ - *a = (d >> 8) | (d << 8); -} - -static inline unsigned short edosk2674_smsc_inw( - volatile unsigned short *a - ) -{ - unsigned short d; - d = *a; - return (d >> 8) | (d << 8); -} - -static inline void edosk2674_smsc_outsw( - volatile unsigned short *a, - unsigned short *p, - unsigned long l - ) -{ - for (; l != 0; --l, p++) - *a = *p; -} - -static inline void edosk2674_smsc_insw( - volatile unsigned short *a, - unsigned short *p, - unsigned long l - ) -{ - for (; l != 0; --l, p++) - *p = *a; -} - -#endif diff --git a/include/asm-h8300/generic/machine-depend.h b/include/asm-h8300/generic/machine-depend.h deleted file mode 100644 index 2d78096e5..000000000 --- a/include/asm-h8300/generic/machine-depend.h +++ /dev/null @@ -1,17 +0,0 @@ -/* machine depend header */ - -/* TIMER rate define */ -#ifdef H8300_TIMER_DEFINE -#include -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) || defined(CONFIG_H8S2678) -#define H8300_TIMER_COUNT_DATA CONFIG_CPU_CLOCK*10/8192 -#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 -#endif - -#if defined(CONFIG_H8_3002) || defined(CONFIG_H83048) -#define H8300_TIMER_COUNT_DATA CONFIG_CPU_CLOCK*10/8 -#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 -#endif - -#endif - diff --git a/include/asm-h8300/generic/timer_rate.h b/include/asm-h8300/generic/timer_rate.h deleted file mode 100644 index 0f6f4190e..000000000 --- a/include/asm-h8300/generic/timer_rate.h +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) || defined(CONFIG_H8S2678) -#define H8300_TIMER_COUNT_DATA CONFIG_CPU_CLOCK*10/8192 -#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 -#endif - -#if defined(H8_3002) || defined(CONFIG_H83048) -#define H8300_TIMER_COUNT_DATA CONFIG_CPU_CLOCK*10/8 -#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 -#endif - -#if !defined(H8300_TIMER_COUNT_DATA) -#error illigal configuration -#endif diff --git a/include/asm-h8300/h8300_smsc.h b/include/asm-h8300/h8300_smsc.h deleted file mode 100644 index f8fa7f9cc..000000000 --- a/include/asm-h8300/h8300_smsc.h +++ /dev/null @@ -1,20 +0,0 @@ -/****************************************************************************/ - -/* - * h8300_smsc.h -- SMSC in H8/300H and H8S Evalution Board. - * - * (C) Copyright 2003, Yoshinori Sato - */ - -/****************************************************************************/ -#ifndef h8300smsc_h -#define h8300smsc_h -/****************************************************************************/ - -/* Such a description is OK ? */ -#define H8300_SMSC_DEFINE -#include -#undef H8300_SMSC_DEFINE - -/****************************************************************************/ -#endif /* h8300smsc_h */ diff --git a/include/asm-h8300/h8max/machine-depend.h b/include/asm-h8300/h8max/machine-depend.h deleted file mode 100644 index e87d22e6d..000000000 --- a/include/asm-h8300/h8max/machine-depend.h +++ /dev/null @@ -1,100 +0,0 @@ -/* H8MAX board depend header */ - -/* TIMER rate define */ -#ifdef H8300_TIMER_DEFINE -#define H8300_TIMER_COUNT_DATA 25000*10/8192 -#define H8300_TIMER_FREQ 25000*1000/8192 -#endif - -/* H8MAX RTL8019AS Config */ -#ifdef H8300_NE_DEFINE - -#define NE2000_ADDR 0x800600 -#define NE2000_IRQ 4 -#define NE2000_IRQ_VECTOR (12 + NE2000_IRQ) -#define NE2000_BYTE volatile unsigned short - -/* sorry quick hack */ -#if defined(outb) -# undef outb -#endif -#define outb(d,a) h8max_outb((d),(a) - NE2000_ADDR) -#if defined(inb) -# undef inb -#endif -#define inb(a) h8max_inb((a) - NE2000_ADDR) -#if defined(outb_p) -# undef outb_p -#endif -#define outb_p(d,a) h8max_outb((d),(a) - NE2000_ADDR) -#if defined(inb_p) -# undef inb_p -#endif -#define inb_p(a) h8max_inb((a) - NE2000_ADDR) -#if defined(outsw) -# undef outsw -#endif -#define outsw(a,p,l) h8max_outsw((a) - NE2000_ADDR,(unsigned short *)p,l) -#if defined(insw) -# undef insw -#endif -#define insw(a,p,l) h8max_insw((a) - NE2000_ADDR,(unsigned short *)p,l) -#if defined(outsb) -# undef outsb -#endif -#define outsb(a,p,l) h8max_outsb((a) - NE2000_ADDR,(unsigned char *)p,l) -#if defined(insb) -# undef insb -#endif -#define insb(a,p,l) h8max_insb((a) - NE2000_ADDR,(unsigned char *)p,l) - -#define H8300_INIT_NE() \ -do { \ - wordlength = 2; \ - h8max_outb(0x49, ioaddr + EN0_DCFG); \ - SA_prom[14] = SA_prom[15] = 0x57;\ -} while(0) - -static inline void h8max_outb(unsigned char d,unsigned char a) -{ - *(unsigned short *)(NE2000_ADDR + (a << 1)) = d; -} - -static inline unsigned char h8max_inb(unsigned char a) -{ - return *(unsigned char *)(NE2000_ADDR + (a << 1) +1); -} - -static inline void h8max_outsw(unsigned char a,unsigned short *p,unsigned long l) -{ - unsigned short d; - for (; l != 0; --l, p++) { - d = (((*p) >> 8) & 0xff) | ((*p) << 8); - *(unsigned short *)(NE2000_ADDR + (a << 1)) = d; - } -} - -static inline void h8max_insw(unsigned char a,unsigned short *p,unsigned long l) -{ - unsigned short d; - for (; l != 0; --l, p++) { - d = *(unsigned short *)(NE2000_ADDR + (a << 1)); - *p = (d << 8)|((d >> 8) & 0xff); - } -} - -static inline void h8max_outsb(unsigned char a,unsigned char *p,unsigned long l) -{ - for (; l != 0; --l, p++) { - *(unsigned short *)(NE2000_ADDR + (a << 1)) = *p; - } -} - -static inline void h8max_insb(unsigned char a,unsigned char *p,unsigned long l) -{ - for (; l != 0; --l, p++) { - *p = *((unsigned char *)(NE2000_ADDR + (a << 1))+1); - } -} - -#endif diff --git a/include/asm-h8300/relay.h b/include/asm-h8300/relay.h new file mode 100644 index 000000000..34ebfdd2f --- /dev/null +++ b/include/asm-h8300/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_H8300_RELAY_H +#define _ASM_H8300_RELAY_H + +#include +#endif diff --git a/include/asm-h8300/resource.h b/include/asm-h8300/resource.h index 38b8e942a..278f104a6 100644 --- a/include/asm-h8300/resource.h +++ b/include/asm-h8300/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index a6d15d494..326c271fd 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h @@ -468,7 +468,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 42164a6d5..a6f577192 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -122,8 +122,6 @@ static inline void disable_acpi(void) #define FIX_ACPI_PAGES 4 extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq); -extern int (*platform_rename_gsi)(int ioapic, int gsi); - #ifdef CONFIG_X86_IO_APIC extern int skip_ioapic_setup; extern int acpi_skip_timer_override; diff --git a/include/asm-i386/atomic_kmap.h b/include/asm-i386/atomic_kmap.h new file mode 100644 index 000000000..5a1b90130 --- /dev/null +++ b/include/asm-i386/atomic_kmap.h @@ -0,0 +1,96 @@ +/* + * atomic_kmap.h: temporary virtual kernel memory mappings + * + * Copyright (C) 2003 Ingo Molnar + */ + +#ifndef _ASM_ATOMIC_KMAP_H +#define _ASM_ATOMIC_KMAP_H + +#ifdef __KERNEL__ + +#include +#include + +#ifdef CONFIG_DEBUG_HIGHMEM +#define HIGHMEM_DEBUG 1 +#else +#define HIGHMEM_DEBUG 0 +#endif + +extern pte_t *kmap_pte; +#define kmap_prot PAGE_KERNEL +#define kmap_prot_nocache PAGE_KERNEL_NOCACHE + +#define PKMAP_BASE (0xff000000UL) +#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE) + +static inline unsigned long __kmap_atomic_vaddr(enum km_type type) +{ + enum fixed_addresses idx; + + idx = type + KM_TYPE_NR*smp_processor_id(); + return __fix_to_virt(FIX_KMAP_BEGIN + idx); +} + +static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + /* + * NOTE: entries that rely on some secondary TLB-flush + * effect must not be global: + */ + set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); + + return (void*) vaddr; +} + +static inline void *__kmap_atomic(struct page *page, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +#if HIGHMEM_DEBUG + BUG_ON(!pte_none(*(kmap_pte-idx))); +#else + /* + * Performance optimization - do not flush if the new + * pte is the same as the old one: + */ + if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot))) + return (void *) vaddr; +#endif + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); + __flush_tlb_one(vaddr); + + return (void*) vaddr; +} + +static inline void __kunmap_atomic(void *kvaddr, enum km_type type) +{ +#if HIGHMEM_DEBUG + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); + + BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)); + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(kmap_pte-idx); + __flush_tlb_one(vaddr); +#endif +} + +#define __kunmap_atomic_type(type) \ + __kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type)) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_ATOMIC_KMAP_H */ diff --git a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h index 1afe056aa..59fe7fc4c 100644 --- a/include/asm-i386/checksum.h +++ b/include/asm-i386/checksum.h @@ -25,7 +25,7 @@ asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsign * better 64-bit) boundary */ -asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum, +asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum, int *src_err_ptr, int *dst_err_ptr); /* @@ -39,14 +39,19 @@ static __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst, int len, int sum) { - return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); + /* + * The direct function is OK for kernel-space => kernel-space copies: + */ + return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); } static __inline__ unsigned int csum_partial_copy_from_user ( const char *src, char *dst, int len, int sum, int *err_ptr) { - return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL); + if (copy_from_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(dst, len, sum); } /* @@ -172,11 +177,26 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, +static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst, int len, int sum, int *err_ptr) { if (access_ok(VERIFY_WRITE, dst, len)) - return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return -1; /* invalid checksum */ +} + +static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) { + if (copy_to_user(dst, src, len)) + *err_ptr = -EFAULT; + return csum_partial(src, len, sum); + } if (len) *err_ptr = -EFAULT; diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index a6fceb3ce..d6005e6e8 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -47,6 +47,7 @@ /* Don't duplicate feature flags which are redundant with Intel! */ #define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */ #define X86_FEATURE_MP (1*32+19) /* MP Capable. */ +#define X86_FEATURE_NX (1*32+20) /* Execute Disable */ #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ #define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */ #define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */ @@ -100,6 +101,7 @@ #define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM) #define cpu_has_ht boot_cpu_has(X86_FEATURE_HT) #define cpu_has_mp boot_cpu_has(X86_FEATURE_MP) +#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX) #define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR) #define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR) #define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR) diff --git a/include/asm-i386/crash.h b/include/asm-i386/crash.h new file mode 100644 index 000000000..b6ae4f36f --- /dev/null +++ b/include/asm-i386/crash.h @@ -0,0 +1,75 @@ +#ifndef _ASM_I386_CRASH_H +#define _ASM_I386_CRASH_H + +/* + * linux/include/asm-i386/crash.h + * + * Copyright (c) 2004 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __KERNEL__ + +#include +#include +#include + +extern int page_is_ram(unsigned long); + +static inline void * +map_virtual(u64 offset, struct page **pp) +{ + struct page *page; + unsigned long pfn; + void *vaddr; + + pfn = (unsigned long)(offset >> PAGE_SHIFT); + + if (!page_is_ram(pfn)) { + printk(KERN_INFO + "crash memory driver: !page_is_ram(pfn: %lx)\n", pfn); + return NULL; + } + + if (!pfn_valid(pfn)) { + printk(KERN_INFO + "crash memory driver: invalid pfn: %lx )\n", pfn); + return NULL; + } + + page = pfn_to_page(pfn); + + vaddr = kmap(page); + if (!vaddr) { + printk(KERN_INFO + "crash memory driver: pfn: %lx kmap(page: %lx) failed\n", + pfn, (unsigned long)page); + return NULL; + } + + *pp = page; + return (vaddr + (offset & (PAGE_SIZE-1))); +} + +static inline void unmap_virtual(struct page *page) +{ + kunmap(page); +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_I386_CRASH_H */ diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h index 9361aff2e..942c27980 100644 --- a/include/asm-i386/desc.h +++ b/include/asm-i386/desc.h @@ -21,6 +21,13 @@ struct Xgt_desc_struct { extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; +extern void trap_init_virtual_IDT(void); +extern void trap_init_virtual_GDT(void); + +asmlinkage int system_call(void); +asmlinkage void lcall7(void); +asmlinkage void lcall27(void); + #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8)) @@ -30,6 +37,7 @@ extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; */ extern struct desc_struct default_ldt[]; extern void set_intr_gate(unsigned int irq, void * addr); +extern void set_trap_gate(unsigned int n, void *addr); #define _set_tssldt_desc(n,addr,limit,type) \ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ @@ -90,39 +98,30 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu) #undef C } -static inline void clear_LDT(void) +extern struct page *default_ldt_page; +extern void load_LDT_nolock(mm_context_t *pc, int cpu); + +static inline void load_LDT(mm_context_t *pc) { int cpu = get_cpu(); - - set_ldt_desc(cpu, &default_ldt[0], 5); - load_LDT_desc(); + load_LDT_nolock(pc, cpu); put_cpu(); } -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) +static inline void set_user_cs(struct desc_struct *desc, unsigned long limit) { - void *segments = pc->ldt; - int count = pc->size; - - if (likely(!count)) { - segments = &default_ldt[0]; - count = 5; - } - - set_ldt_desc(cpu, segments, count); - load_LDT_desc(); + limit = (limit - 1) / PAGE_SIZE; + desc->a = limit & 0xffff; + desc->b = (limit & 0xf0000) | 0x00c0fb00; } -static inline void load_LDT(mm_context_t *pc) -{ - int cpu = get_cpu(); - load_LDT_nolock(pc, cpu); - put_cpu(); -} +#define load_user_cs_desc(cpu, mm) \ + cpu_gdt_table[(cpu)][GDT_ENTRY_DEFAULT_USER_CS] = (mm)->context.user_cs -#endif /* !__ASSEMBLY__ */ +extern void arch_add_exec_range(struct mm_struct *mm, unsigned long limit); +extern void arch_remove_exec_range(struct mm_struct *mm, unsigned long limit); +extern void arch_flush_exec_range(struct mm_struct *mm); + +#endif /* !__ASSEMBLY__ */ #endif diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index cda7f174b..f55884baa 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -9,6 +9,7 @@ #include #include #include /* for savesegment */ +#include #include @@ -117,7 +118,8 @@ typedef struct user_fxsr_struct elf_fpxregset_t; #define AT_SYSINFO_EHDR 33 #ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +/* child inherits the personality of the parent */ +#define SET_PERSONALITY(ex, ibcs2) do { } while (0) extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); @@ -127,15 +129,22 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs) -#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) -#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) -#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) extern void __kernel_vsyscall; - -#define ARCH_DLINFO \ -do { \ - NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ +#define VSYSCALL_BASE ((unsigned long)current->mm->context.vdso) +#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) +#define VSYSCALL_OFFSET ((unsigned long) &__kernel_vsyscall) +#define VSYSCALL_ENTRY (VSYSCALL_BASE + VSYSCALL_OFFSET) + +/* kernel-internal fixmap address: */ +#define __VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) +#define __VSYSCALL_EHDR ((const struct elfhdr *) __VSYSCALL_BASE) + +#define ARCH_DLINFO \ +do { \ + if (VSYSCALL_BASE) { \ + NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ + } \ } while (0) /* @@ -146,15 +155,15 @@ do { \ * Dumping its extra ELF program headers includes all the other information * a debugger needs to easily find how the vsyscall DSO was being used. */ -#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) +#define ELF_CORE_EXTRA_PHDRS (__VSYSCALL_EHDR->e_phnum) #define ELF_CORE_WRITE_EXTRA_PHDRS \ do { \ const struct elf_phdr *const vsyscall_phdrs = \ - (const struct elf_phdr *) (VSYSCALL_BASE \ - + VSYSCALL_EHDR->e_phoff); \ + (const struct elf_phdr *) (__VSYSCALL_BASE \ + + __VSYSCALL_EHDR->e_phoff); \ int i; \ Elf32_Off ofs = 0; \ - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + for (i = 0; i < __VSYSCALL_EHDR->e_phnum; ++i) { \ struct elf_phdr phdr = vsyscall_phdrs[i]; \ if (phdr.p_type == PT_LOAD) { \ BUG_ON(ofs != 0); \ @@ -172,10 +181,10 @@ do { \ #define ELF_CORE_WRITE_EXTRA_DATA \ do { \ const struct elf_phdr *const vsyscall_phdrs = \ - (const struct elf_phdr *) (VSYSCALL_BASE \ - + VSYSCALL_EHDR->e_phoff); \ + (const struct elf_phdr *) (__VSYSCALL_BASE \ + + __VSYSCALL_EHDR->e_phoff); \ int i; \ - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + for (i = 0; i < __VSYSCALL_EHDR->e_phnum; ++i) { \ if (vsyscall_phdrs[i].p_type == PT_LOAD) \ DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \ @@ -184,4 +193,10 @@ do { \ #endif +#define __HAVE_ARCH_RANDOMIZE_BRK +extern void randomize_brk(unsigned long old_brk); + +#define __HAVE_ARCH_VSYSCALL +extern void map_vsyscall(void); + #endif diff --git a/include/asm-i386/fcntl.h b/include/asm-i386/fcntl.h index 41e3c4d91..ae67b6f4c 100644 --- a/include/asm-i386/fcntl.h +++ b/include/asm-i386/fcntl.h @@ -20,6 +20,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h index 07d4c64ae..df4ae5834 100644 --- a/include/asm-i386/fixmap.h +++ b/include/asm-i386/fixmap.h @@ -18,17 +18,15 @@ #include #include #include -#ifdef CONFIG_HIGHMEM #include #include -#endif /* * Here we define all the compile-time 'special' virtual * addresses. The point is to have a constant address at * compile time, but to set the physical address only - * in the boot process. We allocate these special addresses - * from the end of virtual memory (0xfffff000) backwards. + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xffffe000) backwards. * Also this lets us do fail-safe vmalloc(), we * can guarantee that these special addresses and * vmalloc()-ed addresses never overlap. @@ -41,11 +39,20 @@ * TLB entries of such buffers will not be flushed across * task switches. */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ enum fixed_addresses { FIX_HOLE, FIX_VSYSCALL, #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ +#else + FIX_VSTACK_HOLE_1, #endif #ifdef CONFIG_X86_IO_APIC FIX_IO_APIC_BASE_0, @@ -57,16 +64,21 @@ enum fixed_addresses { FIX_LI_PCIA, /* Lithium PCI Bridge A */ FIX_LI_PCIB, /* Lithium PCI Bridge B */ #endif -#ifdef CONFIG_X86_F00F_BUG - FIX_F00F_IDT, /* Virtual mapping for IDT */ -#endif + FIX_IDT, + FIX_GDT_1, + FIX_GDT_0, + FIX_TSS_3, + FIX_TSS_2, + FIX_TSS_1, + FIX_TSS_0, + FIX_ENTRY_TRAMPOLINE_1, + FIX_ENTRY_TRAMPOLINE_0, #ifdef CONFIG_X86_CYCLONE_TIMER FIX_CYCLONE_TIMER, /*cyclone timer register*/ + FIX_VSTACK_HOLE_2, #endif -#ifdef CONFIG_HIGHMEM FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, -#endif #ifdef CONFIG_ACPI_BOOT FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, @@ -98,12 +110,15 @@ extern void __set_fixmap (enum fixed_addresses idx, __set_fixmap(idx, 0, __pgprot(0)) /* - * used by vmalloc.c. + * used by vmalloc.c and various other places. * * Leave one empty page between vmalloc'ed areas and * the start of the fixmap. + * + * IMPORTANT: we have to align FIXADDR_TOP so that the virtual stack + * is THREAD_SIZE aligned. */ -#define FIXADDR_TOP (0xfffff000UL) +#define FIXADDR_TOP (0xffffe000UL & ~(THREAD_SIZE-1)) #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h index 454b23ffd..baf5b5aae 100644 --- a/include/asm-i386/highmem.h +++ b/include/asm-i386/highmem.h @@ -25,26 +25,19 @@ #include #include #include +#include /* declarations for highmem.c */ extern unsigned long highstart_pfn, highend_pfn; -extern pte_t *kmap_pte; -extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; - -extern void kmap_init(void); +extern void kmap_init(void) __init; /* * Right now we initialize only a single pte table. It can be extended * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#if NR_CPUS <= 32 -#define PKMAP_BASE (0xff800000UL) -#else -#define PKMAP_BASE (0xff600000UL) -#endif #ifdef CONFIG_X86_PAE #define LAST_PKMAP 512 #else @@ -60,6 +53,7 @@ extern void FASTCALL(kunmap_high(struct page *page)); void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic(struct page *page, enum km_type type); +void *kmap_atomic_nocache_pfn(unsigned long pfn, enum km_type type); void kunmap_atomic(void *kvaddr, enum km_type type); struct page *kmap_atomic_to_page(void *ptr); diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index 5649b4a79..d1a4dd68f 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -31,7 +31,6 @@ extern int can_request_irq(unsigned int, unsigned long flags); #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ #endif -#ifdef CONFIG_4KSTACKS /* * per-CPU IRQ handling contexts (thread information and stack) */ @@ -46,9 +45,6 @@ extern union irq_ctx *softirq_ctx[NR_CPUS]; extern void irq_ctx_init(int cpu); #define __ARCH_HAS_DO_SOFTIRQ -#else -#define irq_ctx_init(cpu) do { ; } while (0) -#endif struct irqaction; struct pt_regs; diff --git a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h index 6886a0c3f..a82d62fd0 100644 --- a/include/asm-i386/kmap_types.h +++ b/include/asm-i386/kmap_types.h @@ -2,30 +2,34 @@ #define _ASM_KMAP_TYPES_H #include - -#ifdef CONFIG_DEBUG_HIGHMEM -# define D(n) __KM_FENCE_##n , -#else -# define D(n) -#endif +#include enum km_type { -D(0) KM_BOUNCE_READ, -D(1) KM_SKB_SUNRPC_DATA, -D(2) KM_SKB_DATA_SOFTIRQ, -D(3) KM_USER0, -D(4) KM_USER1, -D(5) KM_BIO_SRC_IRQ, -D(6) KM_BIO_DST_IRQ, -D(7) KM_PTE0, -D(8) KM_PTE1, -D(9) KM_IRQ0, -D(10) KM_IRQ1, -D(11) KM_SOFTIRQ0, -D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR -}; + /* + * IMPORTANT: don't move these 3 entries, be wary when adding entries, + * the 4G/4G virtual stack must be THREAD_SIZE aligned on each cpu. + */ + KM_BOUNCE_READ, + KM_VSTACK_BASE, + KM_VSTACK_TOP = KM_VSTACK_BASE + STACK_PAGE_COUNT-1, -#undef D + KM_LDT_PAGE15, + KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1, + KM_USER_COPY, + KM_VSTACK_HOLE, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; #endif diff --git a/include/asm-i386/mmu.h b/include/asm-i386/mmu.h index f431a0b86..2623313fe 100644 --- a/include/asm-i386/mmu.h +++ b/include/asm-i386/mmu.h @@ -7,11 +7,20 @@ * we put the segment information here. * * cpu_vm_mask is used to optimize ldt flushing. + * + * exec_limit is used to track the range PROT_EXEC + * mappings span. */ + +#define MAX_LDT_PAGES 16 + typedef struct { int size; struct semaphore sem; - void *ldt; + struct page *ldt_pages[MAX_LDT_PAGES]; + struct desc_struct user_cs; + unsigned long exec_limit; + void *vdso; } mm_context_t; #endif diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h index 99cff6506..52beaf79f 100644 --- a/include/asm-i386/mmu_context.h +++ b/include/asm-i386/mmu_context.h @@ -29,6 +29,10 @@ static inline void switch_mm(struct mm_struct *prev, { int cpu = smp_processor_id(); +#ifdef CONFIG_X86_SWITCH_PAGETABLES + if (tsk->mm) + tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd); +#endif if (likely(prev != next)) { /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); @@ -39,12 +43,14 @@ static inline void switch_mm(struct mm_struct *prev, cpu_set(cpu, next->cpu_vm_mask); /* Re-load page tables */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif /* * load the LDT, if the LDT is different: */ - if (unlikely(prev->context.ldt != next->context.ldt)) + if (unlikely(prev->context.size + next->context.size)) load_LDT_nolock(&next->context, cpu); } #ifdef CONFIG_SMP @@ -56,7 +62,9 @@ static inline void switch_mm(struct mm_struct *prev, /* We were in lazy tlb mode and leave_mm disabled * tlb flush IPI delivery. We must reload %cr3. */ +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) load_cr3(next->pgd); +#endif load_LDT_nolock(&next->context, cpu); } } @@ -67,6 +75,6 @@ static inline void switch_mm(struct mm_struct *prev, asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0)) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL) + switch_mm((prev),(next),current) #endif diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h index 8ec1dae63..614d05f27 100644 --- a/include/asm-i386/module.h +++ b/include/asm-i386/module.h @@ -60,11 +60,7 @@ struct mod_arch_specific #define MODULE_REGPARM "" #endif -#ifdef CONFIG_4KSTACKS #define MODULE_STACKSIZE "4KSTACKS " -#else -#define MODULE_STACKSIZE "" -#endif #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_REGPARM MODULE_STACKSIZE diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h index ffdeea9d1..3589c36b8 100644 --- a/include/asm-i386/msr.h +++ b/include/asm-i386/msr.h @@ -217,6 +217,15 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val) #define MSR_K7_FID_VID_CTL 0xC0010041 #define MSR_K7_FID_VID_STATUS 0xC0010042 +/* extended feature register */ +#define MSR_EFER 0xc0000080 + +/* EFER bits: */ + +/* Execute Disable enable */ +#define _EFER_NX 11 +#define EFER_NX (1<<_EFER_NX) + /* Centaur-Hauls/IDT defined MSRs. */ #define MSR_IDT_FCR1 0x107 #define MSR_IDT_FCR2 0x108 diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 5884b3c92..627420ff1 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -1,6 +1,8 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H +#include + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -9,11 +11,10 @@ #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ - #include +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #ifdef CONFIG_X86_USE_3DNOW #include @@ -40,15 +41,18 @@ * These are used to make use of C type-checking.. */ #ifdef CONFIG_X86_PAE +extern unsigned long long __supported_pte_mask; typedef struct { unsigned long pte_low, pte_high; } pte_t; typedef struct { unsigned long long pmd; } pmd_t; typedef struct { unsigned long long pgd; } pgd_t; +typedef struct { unsigned long long pgprot; } pgprot_t; #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) #define HPAGE_SHIFT 21 #else typedef struct { unsigned long pte_low; } pte_t; typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; #define boot_pte_t pte_t /* or would you rather have a typedef */ #define pte_val(x) ((x).pte_low) #define HPAGE_SHIFT 22 @@ -61,7 +65,6 @@ typedef struct { unsigned long pgd; } pgd_t; #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) #endif -typedef struct { unsigned long pgprot; } pgprot_t; #define pmd_val(x) ((x).pmd) #define pgd_val(x) ((x).pgd) @@ -88,8 +91,19 @@ typedef struct { unsigned long pgprot; } pgprot_t; * * If you want more physical memory than this then see the CONFIG_HIGHMEM4G * and CONFIG_HIGHMEM64G options in the kernel configuration. + * + * Note: on PAE the kernel must never go below 32 MB, we use the + * first 8 entries of the 2-level boot pgd for PAE magic. */ +#ifdef CONFIG_X86_4G_VM_LAYOUT +#define __PAGE_OFFSET (0x02000000) +#define TASK_SIZE (0xff000000) +#else +#define __PAGE_OFFSET (0xc0000000) +#define TASK_SIZE (0xc0000000) +#endif + /* * This much address space is reserved for vmalloc() and iomap() * as well as fixmap mappings. @@ -114,16 +128,10 @@ static __inline__ int get_order(unsigned long size) #endif /* __ASSEMBLY__ */ -#ifdef __ASSEMBLY__ -#define __PAGE_OFFSET (0xC0000000) -#else -#define __PAGE_OFFSET (0xC0000000UL) -#endif - - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) -#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) @@ -136,8 +144,10 @@ static __inline__ int get_order(unsigned long size) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->flags & PF_RELOCEXEC) ? 0 : VM_EXEC) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #endif /* __KERNEL__ */ diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h index a44e26693..4b5ecab79 100644 --- a/include/asm-i386/pgalloc.h +++ b/include/asm-i386/pgalloc.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include /* for struct page */ @@ -52,4 +53,6 @@ static inline void pte_free(struct page *pte) #define check_pgt_cache() do { } while (0) +#define HAVE_ARCH_UNMAPPED_AREA 1 + #endif /* _I386_PGALLOC_H */ diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h index 147acd853..a4c24db82 100644 --- a/include/asm-i386/pgtable-3level.h +++ b/include/asm-i386/pgtable-3level.h @@ -101,18 +101,24 @@ static inline unsigned long pte_pfn(pte_t pte) (pte.pte_high << (32 - PAGE_SHIFT)); } +extern unsigned long long __supported_pte_mask; + static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { pte_t pte; - pte.pte_high = page_nr >> (32 - PAGE_SHIFT); - pte.pte_low = (page_nr << PAGE_SHIFT) | pgprot_val(pgprot); + pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \ + (pgprot_val(pgprot) >> 32); + pte.pte_high &= (__supported_pte_mask >> 32); + pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \ + __supported_pte_mask; return pte; } static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) { - return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); + return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \ + pgprot_val(pgprot)) & __supported_pte_mask); } /* diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 299c75871..dd0bb8a2d 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -16,32 +16,30 @@ #include #include #include +#include #ifndef _I386_BITOPS_H #include #endif -#include -#include -#include - -/* - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) -extern unsigned long empty_zero_page[1024]; extern pgd_t swapper_pg_dir[1024]; -extern kmem_cache_t *pgd_cache; -extern kmem_cache_t *pmd_cache; +extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; extern spinlock_t pgd_lock; extern struct page *pgd_list; - void pmd_ctor(void *, kmem_cache_t *, unsigned long); +void kpmd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_ctor(void *, kmem_cache_t *, unsigned long); void pgd_dtor(void *, kmem_cache_t *, unsigned long); void pgtable_cache_init(void); -void paging_init(void); +extern void paging_init(void); +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end); + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[1024]; +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) #endif /* !__ASSEMBLY__ */ @@ -51,6 +49,11 @@ void paging_init(void); * newer 3-level PAE-mode page tables. */ #ifndef __ASSEMBLY__ + +extern void set_system_gate(unsigned int n, void *addr); +extern void init_entry_mappings(void); +extern void entry_trampoline_setup(void); + #ifdef CONFIG_X86_PAE # include #else @@ -63,7 +66,12 @@ void paging_init(void); #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) +#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT) +# define USER_PTRS_PER_PGD 4 +#else +# define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE) +#endif + #define FIRST_USER_PGD_NR 0 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) @@ -110,6 +118,7 @@ void paging_init(void); #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ #define _PAGE_BIT_UNUSED2 10 #define _PAGE_BIT_UNUSED3 11 +#define _PAGE_BIT_NX 63 #define _PAGE_PRESENT 0x001 #define _PAGE_RW 0x002 @@ -126,28 +135,51 @@ void paging_init(void); #define _PAGE_FILE 0x040 /* set:pagecache unset:swap */ #define _PAGE_PROTNONE 0x080 /* If not present */ +#ifdef CONFIG_X86_PAE +#define _PAGE_NX (1ULL<<_PAGE_BIT_NX) +#else +#define _PAGE_NX 0 +#endif #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_NONE \ + __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#define PAGE_SHARED \ + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) + +#define PAGE_SHARED_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY_NOEXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) +#define PAGE_COPY_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY \ + PAGE_COPY_NOEXEC +#define PAGE_READONLY \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) +#define PAGE_READONLY_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define _PAGE_KERNEL \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) +#define _PAGE_KERNEL_EXEC \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) -extern unsigned long __PAGE_KERNEL; -#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) -#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) -#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) +extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; +#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) +#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) +#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) +#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) +#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) +#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) /* * The i386 can't do page protection for execute, and considers that @@ -158,19 +190,19 @@ extern unsigned long __PAGE_KERNEL; #define __P001 PAGE_READONLY #define __P010 PAGE_COPY #define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY +#define __P100 PAGE_READONLY_EXEC +#define __P101 PAGE_READONLY_EXEC +#define __P110 PAGE_COPY_EXEC +#define __P111 PAGE_COPY_EXEC #define __S000 PAGE_NONE #define __S001 PAGE_READONLY #define __S010 PAGE_SHARED #define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED +#define __S100 PAGE_READONLY_EXEC +#define __S101 PAGE_READONLY_EXEC +#define __S110 PAGE_SHARED_EXEC +#define __S111 PAGE_SHARED_EXEC /* * Define this if things work differently on an i386 and an i486: @@ -239,11 +271,21 @@ static inline void ptep_mkdirty(pte_t *ptep) { set_bit(_PAGE_BIT_DIRTY, &ptep- #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE) +#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte.pte_low &= _PAGE_CHG_MASK; pte.pte_low |= pgprot_val(newprot); +#ifdef CONFIG_X86_PAE + /* + * Chop off the NX bit (if present), and add the NX portion of + * the newprot (if present): + */ + pte.pte_high &= -1 ^ (1 << (_PAGE_BIT_NX - 32)); + pte.pte_high |= (pgprot_val(newprot) >> 32) & \ + (__supported_pte_mask >> 32); +#endif return pte; } @@ -357,4 +399,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __HAVE_ARCH_PTE_SAME #include +/* + * The size of the low 1:1 mappings we use during bootup, + * SMP-boot and ACPI-sleep: + */ +#define LOW_MAPPINGS_SIZE (16*1024*1024) + + #endif /* _I386_PGTABLE_H */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 9d49ea237..efdbf17c2 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -292,15 +292,18 @@ extern unsigned int machine_submodel_id; extern unsigned int BIOS_revision; extern unsigned int mca_pentium_flag; -/* - * User space process size: 3GB (default). - */ -#define TASK_SIZE (PAGE_OFFSET) - /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ -#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3) + +#define SHLIB_BASE 0x00111000 + +#define __HAVE_ARCH_ALIGN_STACK +extern unsigned long arch_align_stack(unsigned long sp); + +#define __HAVE_ARCH_MMAP_TOP +extern unsigned long mmap_top(void); /* * Size of io_bitmap, covering ports 0 to 0x3ff. @@ -406,9 +409,16 @@ struct tss_struct { #define ARCH_MIN_TASKALIGN 16 + +#define STACK_PAGE_COUNT (4096/PAGE_SIZE) + + + + struct thread_struct { /* cached TLS descriptors. */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; + void *stack_page[STACK_PAGE_COUNT]; unsigned long esp0; unsigned long sysenter_cs; unsigned long eip; @@ -452,7 +462,8 @@ struct thread_struct { .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ } -static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread) +static inline void +load_esp0(struct tss_struct *tss, struct thread_struct *thread) { tss->esp0 = thread->esp0; /* This can only happen when SEP is enabled, no need to test "SEP"arately */ @@ -462,6 +473,8 @@ static inline void load_esp0(struct tss_struct *tss, struct thread_struct *threa } } +extern int use_nx; + #define start_thread(regs, new_eip, new_esp) do { \ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \ set_fs(USER_DS); \ @@ -471,6 +484,7 @@ static inline void load_esp0(struct tss_struct *tss, struct thread_struct *threa regs->xcs = __USER_CS; \ regs->eip = new_eip; \ regs->esp = new_esp; \ + load_user_cs_desc(smp_processor_id(), current->mm); \ } while (0) /* Forward declaration, a strange C thing */ @@ -488,6 +502,23 @@ extern void prepare_to_copy(struct task_struct *tsk); */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +#ifdef CONFIG_X86_HIGH_ENTRY +#define virtual_esp0(tsk) \ + ((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack)) +#else +# define virtual_esp0(tsk) ((tsk)->thread.esp0) +#endif + +#define load_virtual_esp0(tss, task) \ + do { \ + tss->esp0 = virtual_esp0(task); \ + if (likely(cpu_has_sep) && unlikely(tss->ss1 != task->thread.sysenter_cs)) { \ + tss->ss1 = task->thread.sysenter_cs; \ + wrmsr(MSR_IA32_SYSENTER_CS, \ + task->thread.sysenter_cs, 0); \ + } \ + } while (0) + extern unsigned long thread_saved_pc(struct task_struct *tsk); void show_trace(struct task_struct *task, unsigned long *stack); diff --git a/include/asm-i386/relay.h b/include/asm-i386/relay.h new file mode 100644 index 000000000..98e5b7246 --- /dev/null +++ b/include/asm-i386/relay.h @@ -0,0 +1,101 @@ +#ifndef _ASM_I386_RELAY_H +#define _ASM_I386_RELAY_H +/* + * linux/include/asm-i386/relay.h + * + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com) + * + * i386 definitions for relayfs + */ + +#include + +#ifdef CONFIG_X86_TSC +#include + +/** + * get_time_delta - utility function for getting time delta + * @now: pointer to a timeval struct that may be given current time + * @rchan: the channel + * + * Returns either the TSC if TSCs are being used, or the time and the + * time difference between the current time and the buffer start time + * if TSCs are not being used. + */ +static inline u32 +get_time_delta(struct timeval *now, struct rchan *rchan) +{ + u32 time_delta; + + if ((using_tsc(rchan) == 1) && cpu_has_tsc) + rdtscl(time_delta); + else { + do_gettimeofday(now); + time_delta = calc_time_delta(now, &rchan->buf_start_time); + } + + return time_delta; +} + +/** + * get_timestamp - utility function for getting a time and TSC pair + * @now: current time + * @tsc: the TSC associated with now + * @rchan: the channel + * + * Sets the value pointed to by now to the current time and the value + * pointed to by tsc to the tsc associated with that time, if the + * platform supports TSC. + */ +static inline void +get_timestamp(struct timeval *now, + u32 *tsc, + struct rchan *rchan) +{ + do_gettimeofday(now); + + if ((using_tsc(rchan) == 1) && cpu_has_tsc) + rdtscl(*tsc); +} + +/** + * get_time_or_tsc - utility function for getting a time or a TSC + * @now: current time + * @tsc: current TSC + * @rchan: the channel + * + * Sets the value pointed to by now to the current time or the value + * pointed to by tsc to the current tsc, depending on whether we're + * using TSCs or not. + */ +static inline void +get_time_or_tsc(struct timeval *now, + u32 *tsc, + struct rchan *rchan) +{ + if ((using_tsc(rchan) == 1) && cpu_has_tsc) + rdtscl(*tsc); + else + do_gettimeofday(now); +} + +/** + * have_tsc - does this platform have a useable TSC? + * + * Returns 1 if this platform has a useable TSC counter for + * timestamping purposes, 0 otherwise. + */ +static inline int +have_tsc(void) +{ + if (cpu_has_tsc) + return 1; + else + return 0; +} + +#else /* No TSC support (#ifdef CONFIG_X86_TSC) */ +#include +#endif /* #ifdef CONFIG_X86_TSC */ +#endif diff --git a/include/asm-i386/resource.h b/include/asm-i386/resource.h index e0da3ad1d..afa2eec75 100644 --- a/include/asm-i386/resource.h +++ b/include/asm-i386/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-i386/rmap.h b/include/asm-i386/rmap.h deleted file mode 100644 index 353afee85..000000000 --- a/include/asm-i386/rmap.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _I386_RMAP_H -#define _I386_RMAP_H - -/* nothing to see, move along */ -#include - -#ifdef CONFIG_HIGHPTE -static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) -{ - unsigned long pfn = (unsigned long)(pte_paddr >> PAGE_SHIFT); - unsigned long off = ((unsigned long)pte_paddr) & ~PAGE_MASK; - return (pte_t *)((char *)kmap_atomic(pfn_to_page(pfn), KM_PTE2) + off); -} - -static inline void rmap_ptep_unmap(pte_t *pte) -{ - kunmap_atomic(pte, KM_PTE2); -} -#endif - -#endif diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h index a14f9f37d..c5ceb5d71 100644 --- a/include/asm-i386/string.h +++ b/include/asm-i386/string.h @@ -58,6 +58,29 @@ __asm__ __volatile__( return dest; } +/* + * This is a more generic variant of strncpy_count() suitable for + * implementing string-access routines with all sorts of return + * code semantics. It's used by mm/usercopy.c. + */ +static inline size_t strncpy_count(char * dest,const char *src,size_t count) +{ + __asm__ __volatile__( + + "1:\tdecl %0\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "2:" + "incl %0" + : "=c" (count) + :"S" (src),"D" (dest),"0" (count) : "memory"); + + return count; +} + static inline char * strcat(char * dest,const char * src) { int d0, d1, d2, d3; diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 4ef147f97..d941e6d92 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -37,6 +37,8 @@ struct thread_info { 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ + void *sysenter_return; + void *real_stack, *virtual_stack, *user_pgd; struct restart_block restart_block; unsigned long previous_esp; /* ESP of the previous stack in case @@ -52,11 +54,7 @@ struct thread_info { #endif #define PREEMPT_ACTIVE 0x4000000 -#ifdef CONFIG_4KSTACKS #define THREAD_SIZE (4096) -#else -#define THREAD_SIZE (8192) -#endif #define STACK_WARN (THREAD_SIZE/8) /* @@ -66,7 +64,7 @@ struct thread_info { */ #ifndef __ASSEMBLY__ -#define INIT_THREAD_INFO(tsk) \ +#define INIT_THREAD_INFO(tsk, thread_info) \ { \ .task = &tsk, \ .exec_domain = &default_exec_domain, \ @@ -77,6 +75,7 @@ struct thread_info { .restart_block = { \ .fn = do_no_restart_syscall, \ }, \ + .real_stack = &thread_info, \ } #define init_thread_info (init_thread_union.thread_info) @@ -143,6 +142,7 @@ static inline unsigned long current_stack_pointer(void) #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_IRET 5 /* return with iret */ +#define TIF_DB7 6 /* has debug registers */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ @@ -153,6 +153,7 @@ static inline unsigned long current_stack_pointer(void) #define _TIF_SINGLESTEP (1<active_mm) __flush_tlb(); +#endif } static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb_one(addr); +#endif } static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (vma->vm_mm == current->active_mm) __flush_tlb(); +#endif } #else @@ -111,11 +117,10 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, __flush_tlb() extern void flush_tlb_all(void); -extern void flush_tlb_current_task(void); extern void flush_tlb_mm(struct mm_struct *); extern void flush_tlb_page(struct vm_area_struct *, unsigned long); -#define flush_tlb() flush_tlb_current_task() +#define flush_tlb() flush_tlb_all() static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end) { diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 656be13d0..d3ac37f4c 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #define VERIFY_READ 0 @@ -26,7 +27,7 @@ #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) @@ -150,6 +151,45 @@ extern void __get_user_4(void); :"=a" (ret),"=d" (x) \ :"0" (ptr)) +extern int get_user_size(unsigned int size, void *val, const void *ptr); +extern int put_user_size(unsigned int size, const void *val, void *ptr); +extern int zero_user_size(unsigned int size, void *ptr); +extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr); +extern int strlen_fromuser_size(unsigned int size, const void *ptr); + + +# define indirect_get_user(x,ptr) \ +({ int __ret_gu,__val_gu; \ + __typeof__(ptr) __ptr_gu = (ptr); \ + __ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\ + (x) = (__typeof__(*__ptr_gu))__val_gu; \ + __ret_gu; \ +}) +#define indirect_put_user(x,ptr) \ +({ \ + __typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x); \ + put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \ +}) +#define __indirect_put_user indirect_put_user +#define __indirect_get_user indirect_get_user + +#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from) +#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to) + +#define __indirect_copy_from_user indirect_copy_from_user +#define __indirect_copy_to_user indirect_copy_to_user + +#define indirect_strncpy_from_user(dst, src, count) \ + copy_str_fromuser_size(count, dst, src) + +extern int strlen_fromuser_size(unsigned int size, const void *ptr); +#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str) +#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1) + +extern int zero_user_size(unsigned int size, void *ptr); + +#define indirect_clear_user(mem, len) zero_user_size(len, mem) +#define __indirect_clear_user clear_user /* Careful: we have to cast the result to the type of the pointer for sign reasons */ /** @@ -169,7 +209,7 @@ extern void __get_user_4(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define get_user(x,ptr) \ +#define direct_get_user(x,ptr) \ ({ int __ret_gu,__val_gu; \ __chk_user_ptr(ptr); \ switch(sizeof (*(ptr))) { \ @@ -200,7 +240,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define put_user(x,ptr) \ +#define direct_put_user(x,ptr) \ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) @@ -224,7 +264,7 @@ extern void __put_user_bad(void); * Returns zero on success, or -EFAULT on error. * On error, the variable @x is set to zero. */ -#define __get_user(x,ptr) \ +#define __direct_get_user(x,ptr) \ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) @@ -247,7 +287,7 @@ extern void __put_user_bad(void); * * Returns zero on success, or -EFAULT on error. */ -#define __put_user(x,ptr) \ +#define __direct_put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __put_user_nocheck(x,ptr,size) \ @@ -375,8 +415,8 @@ do { \ : "m"(__m(addr)), "i"(errret), "0"(err)) -unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n); -unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n); +unsigned long __must_check __copy_to_user_ll(void __user *to, const void *from, unsigned long n); +unsigned long __must_check __copy_from_user_ll(void *to, const void __user *from, unsigned long n); /* * Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault @@ -399,8 +439,8 @@ unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned lo * Returns number of bytes that could not be copied. * On success, this will be zero. */ -static inline unsigned long -__copy_to_user(void __user *to, const void *from, unsigned long n) +static inline unsigned long __must_check +__direct_copy_to_user(void __user *to, const void *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -437,8 +477,8 @@ __copy_to_user(void __user *to, const void *from, unsigned long n) * If some data could not be copied, this function will pad the copied * data to the requested size using zero bytes. */ -static inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) +static inline unsigned long __must_check +__direct_copy_from_user(void *to, const void __user *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -458,9 +498,55 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) return __copy_from_user_ll(to, from, n); } -unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); -unsigned long copy_from_user(void *to, - const void __user *from, unsigned long n); +/** + * copy_to_user: - Copy a block of data into user space. + * @to: Destination address, in user space. + * @from: Source address, in kernel space. + * @n: Number of bytes to copy. + * + * Context: User context only. This function may sleep. + * + * Copy data from kernel space to user space. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + */ +static inline unsigned long __must_check +direct_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_WRITE, to, n)) + n = __direct_copy_to_user(to, from, n); + return n; +} + +/** + * copy_from_user: - Copy a block of data from user space. + * @to: Destination address, in kernel space. + * @from: Source address, in user space. + * @n: Number of bytes to copy. + * + * Context: User context only. This function may sleep. + * + * Copy data from user space to kernel space. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + * + * If some data could not be copied, this function will pad the copied + * data to the requested size using zero bytes. + */ +static inline unsigned long __must_check +direct_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_READ, from, n)) + n = __direct_copy_from_user(to, from, n); + else + memset(to, 0, n); + return n; +} + long strncpy_from_user(char *dst, const char __user *src, long count); long __strncpy_from_user(char *dst, const char __user *src, long count); @@ -478,10 +564,68 @@ long __strncpy_from_user(char *dst, const char __user *src, long count); * If there is a limit on the length of a valid string, you may wish to * consider using strnlen_user() instead. */ -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) -long strnlen_user(const char __user *str, long n); -unsigned long clear_user(void __user *mem, unsigned long len); -unsigned long __clear_user(void __user *mem, unsigned long len); +long direct_strncpy_from_user(char *dst, const char *src, long count); +long __direct_strncpy_from_user(char *dst, const char *src, long count); +#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1) +long direct_strnlen_user(const char *str, long n); +unsigned long direct_clear_user(void *mem, unsigned long len); +unsigned long __direct_clear_user(void *mem, unsigned long len); + +extern int indirect_uaccess; + +#ifdef CONFIG_X86_UACCESS_INDIRECT + +/* + * Return code and zeroing semantics: + + __clear_user 0 <-> bytes not done + clear_user 0 <-> bytes not done + __copy_to_user 0 <-> bytes not done + copy_to_user 0 <-> bytes not done + __copy_from_user 0 <-> bytes not done, zero rest + copy_from_user 0 <-> bytes not done, zero rest + __get_user 0 <-> -EFAULT + get_user 0 <-> -EFAULT + __put_user 0 <-> -EFAULT + put_user 0 <-> -EFAULT + strlen_user strlen + 1 <-> 0 + strnlen_user strlen + 1 (or n+1) <-> 0 + strncpy_from_user strlen (or n) <-> -EFAULT + + */ + +#define __clear_user(mem,len) __indirect_clear_user(mem,len) +#define clear_user(mem,len) indirect_clear_user(mem,len) +#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n) +#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n) +#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n) +#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n) +#define __get_user(val,ptr) __indirect_get_user(val,ptr) +#define get_user(val,ptr) indirect_get_user(val,ptr) +#define __put_user(val,ptr) __indirect_put_user(val,ptr) +#define put_user(val,ptr) indirect_put_user(val,ptr) +#define strlen_user(str) indirect_strlen_user(str) +#define strnlen_user(src,count) indirect_strnlen_user(src,count) +#define strncpy_from_user(dst,src,count) \ + indirect_strncpy_from_user(dst,src,count) + +#else + +#define __clear_user __direct_clear_user +#define clear_user direct_clear_user +#define __copy_to_user __direct_copy_to_user +#define copy_to_user direct_copy_to_user +#define __copy_from_user __direct_copy_from_user +#define copy_from_user direct_copy_from_user +#define __get_user __direct_get_user +#define get_user direct_get_user +#define __put_user __direct_put_user +#define put_user direct_put_user +#define strlen_user direct_strlen_user +#define strnlen_user direct_strnlen_user +#define strncpy_from_user direct_strncpy_from_user + +#endif /* CONFIG_X86_UACCESS_INDIRECT */ #endif /* __i386_UACCESS_H */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 0df3f9b0a..b70f8a999 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -292,6 +292,7 @@ #define NR_syscalls 284 +#ifndef __KERNEL_SYSCALLS_NO_ERRNO__ /* user-visible error numbers are in the range -1 - -124: see */ #define __syscall_return(type, res) \ @@ -303,6 +304,10 @@ do { \ return (type) (res); \ } while (0) +#else +# define __syscall_return(type, res) return (type) (res) +#endif + /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ type name(void) \ @@ -403,7 +408,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ @@ -434,6 +438,8 @@ static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) static inline _syscall3(int,open,const char *,file,int,flag,int,mode) static inline _syscall1(int,close,int,fd) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall1(long,chroot,char *,filename) +static inline _syscall1(long,chdir,char *,filename) asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, diff --git a/include/asm-ia64/crash.h b/include/asm-ia64/crash.h new file mode 100644 index 000000000..f51e828d6 --- /dev/null +++ b/include/asm-ia64/crash.h @@ -0,0 +1,90 @@ +#ifndef _ASM_IA64_CRASH_H +#define _ASM_IA64_CRASH_H + +/* + * linux/include/asm-ia64/crash.h + * + * Copyright (c) 2004 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __KERNEL__ + +#include +#include +#include + +static inline void * +map_virtual(u64 offset, struct page **pp) +{ + struct page *page; + unsigned long pfn; + u32 type; + + if (REGION_NUMBER(offset) == 5) { + char byte; + + if (__get_user(byte, (char *)offset) == 0) + return (void *)offset; + else + return NULL; + } + + switch (type = efi_mem_type(offset)) + { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + break; + + default: + printk(KERN_INFO + "crash memory driver: invalid memory type for %lx: %d\n", + offset, type); + return NULL; + } + + pfn = offset >> PAGE_SHIFT; + + if (!pfn_valid(pfn)) { + printk(KERN_INFO + "crash memory driver: invalid pfn: %lx )\n", pfn); + return NULL; + } + + page = pfn_to_page(pfn); + + if (!page->virtual) { + printk(KERN_INFO + "crash memory driver: offset: %lx page: %lx page->virtual: NULL\n", + offset, (unsigned long)page); + return NULL; + } + + return (page->virtual + (offset & (PAGE_SIZE-1))); +} + +static inline void unmap_virtual(struct page *page) +{ + return; +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IA64_CRASH_H */ diff --git a/include/asm-ia64/fcntl.h b/include/asm-ia64/fcntl.h index 697dd0bc0..9ea319afd 100644 --- a/include/asm-ia64/fcntl.h +++ b/include/asm-ia64/fcntl.h @@ -28,6 +28,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 68be9d57c..69a9e8d81 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -23,6 +23,10 @@ #include #include +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + /* * Very stupidly, we used to get new pgd's and pmd's, init their contents * to point to the NULL versions of the next level page table, later on diff --git a/include/asm-ia64/relay.h b/include/asm-ia64/relay.h new file mode 100644 index 000000000..1d7628ec6 --- /dev/null +++ b/include/asm-ia64/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_IA64_RELAY_H +#define _ASM_IA64_RELAY_H + +#include +#endif diff --git a/include/asm-ia64/resource.h b/include/asm-ia64/resource.h index 06d11777d..eb171fcef 100644 --- a/include/asm-ia64/resource.h +++ b/include/asm-ia64/resource.h @@ -44,7 +44,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-ia64/rmap.h b/include/asm-ia64/rmap.h deleted file mode 100644 index 179c565dd..000000000 --- a/include/asm-ia64/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ASM_IA64_RMAP_H -#define _ASM_IA64_RMAP_H - -/* nothing to see, move along */ -#include - -#endif /* _ASM_IA64_RMAP_H */ diff --git a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h index 20e9b5775..976ec6c61 100644 --- a/include/asm-ia64/sn/pda.h +++ b/include/asm-ia64/sn/pda.h @@ -9,11 +9,11 @@ #define _ASM_IA64_SN_PDA_H #include +#include #include #include #include - /* * CPU-specific data structure. * diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index 57c7db10a..2c53f8dc8 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -239,7 +239,7 @@ extern void ia64_load_extra (struct task_struct *task); * the latest fph state from another CPU. In other words: eager save, lazy restore. */ # define switch_to(prev,next,last) do { \ - if (ia64_psr(ia64_task_regs(prev))->mfh && ia64_is_local_fpu_owner(prev)) { \ + if (ia64_psr(ia64_task_regs(prev))->mfh) { \ ia64_psr(ia64_task_regs(prev))->mfh = 0; \ (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ __ia64_save_fpu((prev)->thread.fph); \ diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h index 5d714b206..f1ff70964 100644 --- a/include/asm-ia64/tlb.h +++ b/include/asm-ia64/tlb.h @@ -163,7 +163,8 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end) if (rss < freed) freed = rss; - mm->rss = rss - freed; + // mm->rss = rss - freed; + vx_rsspages_sub(mm, freed); /* * Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and * tlb->end_addr. diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index ca3c7b958..0fb824465 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -109,7 +109,7 @@ #define __NR_syslog 1117 #define __NR_setitimer 1118 #define __NR_getitimer 1119 -/* 1120 was __NR_old_stat */ +#define __NR_tux 1120 /* was __NR_old_stat */ /* 1121 was __NR_old_lstat */ /* 1122 was __NR_old_fstat */ #define __NR_vhangup 1123 @@ -258,7 +258,6 @@ #define __NR_mq_notify 1266 #define __NR_mq_getsetattr 1267 #define __NR_kexec_load 1268 -#define __NR_vserver 1269 #ifdef __KERNEL__ @@ -275,7 +274,6 @@ # define __ARCH_WANT_SYS_OLDUMOUNT # define __ARCH_WANT_SYS_SIGPENDING # define __ARCH_WANT_SYS_SIGPROCMASK -# define __ARCH_WANT_SYS_RT_SIGACTION #endif #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff --git a/include/asm-m68k/relay.h b/include/asm-m68k/relay.h new file mode 100644 index 000000000..ec637ffb8 --- /dev/null +++ b/include/asm-m68k/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_M68K_RELAY_H +#define _ASM_M68K_RELAY_H + +#include +#endif diff --git a/include/asm-m68k/resource.h b/include/asm-m68k/resource.h index e2ad93f6a..8b6e74a35 100644 --- a/include/asm-m68k/resource.h +++ b/include/asm-m68k/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-m68k/rmap.h b/include/asm-m68k/rmap.h deleted file mode 100644 index 85119e414..000000000 --- a/include/asm-m68k/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _M68K_RMAP_H -#define _M68K_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 6a105788a..65806ca4e 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -239,7 +239,9 @@ #define __NR_fremovexattr 234 #define __NR_futex 235 -#define NR_syscalls 236 +#define __NR_vserver 273 + +#define NR_syscalls 274 /* user-visible error numbers are in the range -1 - -124: see */ @@ -359,7 +361,6 @@ __syscall_return(type,__res); \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-m68knommu/relay.h b/include/asm-m68knommu/relay.h new file mode 100644 index 000000000..ef1afa6b2 --- /dev/null +++ b/include/asm-m68knommu/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_M68KNOMMU_RELAY_H +#define _ASM_M68KNOMMU_RELAY_H + +#include +#endif diff --git a/include/asm-m68knommu/rmap.h b/include/asm-m68knommu/rmap.h deleted file mode 100644 index b3664ccd5..000000000 --- a/include/asm-m68knommu/rmap.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Do not need anything here */ - diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index b10e469b2..bf2f87892 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h @@ -221,7 +221,9 @@ #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 -#define NR_syscalls 256 +#define __NR_vserver 273 + +#define NR_syscalls 274 /* user-visible error numbers are in the range -1 - -122: see */ @@ -394,7 +396,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-mips/relay.h b/include/asm-mips/relay.h new file mode 100644 index 000000000..37304bd30 --- /dev/null +++ b/include/asm-mips/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_RELAY_H +#define _ASM_RELAY_H + +#include +#endif diff --git a/include/asm-mips/rmap.h b/include/asm-mips/rmap.h deleted file mode 100644 index c9efd7b98..000000000 --- a/include/asm-mips/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_RMAP_H -#define __ASM_RMAP_H - -/* nothing to see, move along */ -#include - -#endif /* __ASM_RMAP_H */ diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index 4dfc72bd1..40a96a4e9 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -288,20 +288,21 @@ #define __NR_clock_nanosleep (__NR_Linux + 265) #define __NR_tgkill (__NR_Linux + 266) #define __NR_utimes (__NR_Linux + 267) -#define __NR_mbind (__NR_Linux + 268) -#define __NR_get_mempolicy (__NR_Linux + 269) -#define __NR_set_mempolicy (__NR_Linux + 270) -#define __NR_mq_open (__NR_Linux + 271) -#define __NR_mq_unlink (__NR_Linux + 272) -#define __NR_mq_timedsend (__NR_Linux + 273) -#define __NR_mq_timedreceive (__NR_Linux + 274) -#define __NR_mq_notify (__NR_Linux + 275) -#define __NR_mq_getsetattr (__NR_Linux + 276) +#define __NR_vserver (__NR_Linux + 273) +#define __NR_mbind (__NR_Linux + 274) +#define __NR_get_mempolicy (__NR_Linux + 275) +#define __NR_set_mempolicy (__NR_Linux + 276) +#define __NR_mq_open (__NR_Linux + 277) +#define __NR_mq_unlink (__NR_Linux + 278) +#define __NR_mq_timedsend (__NR_Linux + 279) +#define __NR_mq_timedreceive (__NR_Linux + 280) +#define __NR_mq_notify (__NR_Linux + 281) +#define __NR_mq_getsetattr (__NR_Linux + 282) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 276 +#define __NR_Linux_syscalls 282 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ @@ -1091,7 +1092,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION # ifndef __mips64 # define __ARCH_WANT_STAT64 # endif diff --git a/include/asm-mips64/relay.h b/include/asm-mips64/relay.h new file mode 100644 index 000000000..37304bd30 --- /dev/null +++ b/include/asm-mips64/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_RELAY_H +#define _ASM_RELAY_H + +#include +#endif diff --git a/include/asm-parisc/relay.h b/include/asm-parisc/relay.h new file mode 100644 index 000000000..cea0c777f --- /dev/null +++ b/include/asm-parisc/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_PARISC_RELAY_H +#define _ASM_PARISC_RELAY_H + +#include +#endif diff --git a/include/asm-parisc/resource.h b/include/asm-parisc/resource.h index f9088848f..8b0fab7e3 100644 --- a/include/asm-parisc/resource.h +++ b/include/asm-parisc/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-parisc/rmap.h b/include/asm-parisc/rmap.h deleted file mode 100644 index 4ea8eb454..000000000 --- a/include/asm-parisc/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _PARISC_RMAP_H -#define _PARISC_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 72b457db1..1c410cdb3 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h @@ -728,7 +728,9 @@ #define __NR_mq_notify (__NR_Linux + 233) #define __NR_mq_getsetattr (__NR_Linux + 234) -#define __NR_Linux_syscalls 235 +#define __NR_vserver (__NR_Linux + 273) + +#define __NR_Linux_syscalls 273 #define HPUX_GATEWAY_ADDR 0xC0000004 #define LINUX_GATEWAY_ADDR 0x100 @@ -899,7 +901,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif /* mmap & mmap2 take 6 arguments */ diff --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h index 27ae7d2f6..118b4ab70 100644 --- a/include/asm-ppc/fcntl.h +++ b/include/asm-ppc/fcntl.h @@ -20,6 +20,7 @@ #define O_NOFOLLOW 0100000 /* don't follow links */ #define O_LARGEFILE 0200000 #define O_DIRECT 0400000 /* direct disk access hint */ +#define O_ATOMICLOOKUP 01000000 /* tux hack */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-ppc/fsl_ocp.h b/include/asm-ppc/fsl_ocp.h new file mode 100644 index 000000000..9f88999d4 --- /dev/null +++ b/include/asm-ppc/fsl_ocp.h @@ -0,0 +1,54 @@ +/* + * include/asm-ppc/fsl_ocp.h + * + * Definitions for the on-chip peripherals on Freescale PPC processors + * + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_FS_OCP_H__ +#define __ASM_FS_OCP_H__ + +/* A table of information for supporting the Gianfar Ethernet Controller + * This helps identify which enet controller we are dealing with, + * and what type of enet controller it is + */ +struct ocp_gfar_data { + uint interruptTransmit; + uint interruptError; + uint interruptReceive; + uint interruptPHY; + uint flags; + uint phyid; + uint phyregidx; + unsigned char mac_addr[6]; +}; + +/* Flags in the flags field */ +#define GFAR_HAS_COALESCE 0x20 +#define GFAR_HAS_RMON 0x10 +#define GFAR_HAS_MULTI_INTR 0x08 +#define GFAR_FIRM_SET_MACADDR 0x04 +#define GFAR_HAS_PHY_INTR 0x02 /* if not set use a timer */ +#define GFAR_HAS_GIGABIT 0x01 + +/* Data structure for I2C support. Just contains a couple flags + * to distinguish various I2C implementations*/ +struct ocp_fs_i2c_data { + uint flags; +}; + +/* Flags for I2C */ +#define FS_I2C_SEPARATE_DFSRR 0x02 +#define FS_I2C_32BIT 0x01 + +#endif /* __ASM_FS_OCP_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/immap_85xx.h b/include/asm-ppc/immap_85xx.h new file mode 100644 index 000000000..50fb5e470 --- /dev/null +++ b/include/asm-ppc/immap_85xx.h @@ -0,0 +1,126 @@ +/* + * include/asm-ppc/immap_85xx.h + * + * MPC85xx Internal Memory Map + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IMMAP_85XX_H__ +#define __ASM_IMMAP_85XX_H__ + +/* Eventually this should define all the IO block registers in 85xx */ + +/* PCI Registers */ +typedef struct ccsr_pci { + uint cfg_addr; /* 0x.000 - PCI Configuration Address Register */ + uint cfg_data; /* 0x.004 - PCI Configuration Data Register */ + uint int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */ + char res1[3060]; + uint potar0; /* 0x.c00 - PCI Outbound Transaction Address Register 0 */ + uint potear0; /* 0x.c04 - PCI Outbound Translation Extended Address Register 0 */ + uint powbar0; /* 0x.c08 - PCI Outbound Window Base Address Register 0 */ + char res2[4]; + uint powar0; /* 0x.c10 - PCI Outbound Window Attributes Register 0 */ + char res3[12]; + uint potar1; /* 0x.c20 - PCI Outbound Transaction Address Register 1 */ + uint potear1; /* 0x.c24 - PCI Outbound Translation Extended Address Register 1 */ + uint powbar1; /* 0x.c28 - PCI Outbound Window Base Address Register 1 */ + char res4[4]; + uint powar1; /* 0x.c30 - PCI Outbound Window Attributes Register 1 */ + char res5[12]; + uint potar2; /* 0x.c40 - PCI Outbound Transaction Address Register 2 */ + uint potear2; /* 0x.c44 - PCI Outbound Translation Extended Address Register 2 */ + uint powbar2; /* 0x.c48 - PCI Outbound Window Base Address Register 2 */ + char res6[4]; + uint powar2; /* 0x.c50 - PCI Outbound Window Attributes Register 2 */ + char res7[12]; + uint potar3; /* 0x.c60 - PCI Outbound Transaction Address Register 3 */ + uint potear3; /* 0x.c64 - PCI Outbound Translation Extended Address Register 3 */ + uint powbar3; /* 0x.c68 - PCI Outbound Window Base Address Register 3 */ + char res8[4]; + uint powar3; /* 0x.c70 - PCI Outbound Window Attributes Register 3 */ + char res9[12]; + uint potar4; /* 0x.c80 - PCI Outbound Transaction Address Register 4 */ + uint potear4; /* 0x.c84 - PCI Outbound Translation Extended Address Register 4 */ + uint powbar4; /* 0x.c88 - PCI Outbound Window Base Address Register 4 */ + char res10[4]; + uint powar4; /* 0x.c90 - PCI Outbound Window Attributes Register 4 */ + char res11[268]; + uint pitar3; /* 0x.da0 - PCI Inbound Translation Address Register 3 */ + char res12[4]; + uint piwbar3; /* 0x.da8 - PCI Inbound Window Base Address Register 3 */ + uint piwbear3; /* 0x.dac - PCI Inbound Window Base Extended Address Register 3 */ + uint piwar3; /* 0x.db0 - PCI Inbound Window Attributes Register 3 */ + char res13[12]; + uint pitar2; /* 0x.dc0 - PCI Inbound Translation Address Register 2 */ + char res14[4]; + uint piwbar2; /* 0x.dc8 - PCI Inbound Window Base Address Register 2 */ + uint piwbear2; /* 0x.dcc - PCI Inbound Window Base Extended Address Register 2 */ + uint piwar2; /* 0x.dd0 - PCI Inbound Window Attributes Register 2 */ + char res15[12]; + uint pitar1; /* 0x.de0 - PCI Inbound Translation Address Register 1 */ + char res16[4]; + uint piwbar1; /* 0x.de8 - PCI Inbound Window Base Address Register 1 */ + char res17[4]; + uint piwar1; /* 0x.df0 - PCI Inbound Window Attributes Register 1 */ + char res18[12]; + uint err_dr; /* 0x.e00 - PCI Error Detect Register */ + uint err_cap_dr; /* 0x.e04 - PCI Error Capture Disable Register */ + uint err_en; /* 0x.e08 - PCI Error Enable Register */ + uint err_attrib; /* 0x.e0c - PCI Error Attributes Capture Register */ + uint err_addr; /* 0x.e10 - PCI Error Address Capture Register */ + uint err_ext_addr; /* 0x.e14 - PCI Error Extended Address Capture Register */ + uint err_dl; /* 0x.e18 - PCI Error Data Low Capture Register */ + uint err_dh; /* 0x.e1c - PCI Error Data High Capture Register */ + uint gas_timr; /* 0x.e20 - PCI Gasket Timer Register */ + uint pci_timr; /* 0x.e24 - PCI Timer Register */ + char res19[472]; +} ccsr_pci_t; + +/* Global Utility Registers */ +typedef struct ccsr_guts { + uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ + uint porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ + uint porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */ + uint pordevsr; /* 0x.000c - POR I/O Device Status Register */ + uint pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ + char res1[12]; + uint gpporcr; /* 0x.0020 - General-Purpose POR Configuration Register */ + char res2[12]; + uint gpiocr; /* 0x.0030 - GPIO Control Register */ + char res3[12]; + uint gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */ + char res4[12]; + uint gpindr; /* 0x.0050 - General-Purpose Input Data Register */ + char res5[12]; + uint pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ + char res6[12]; + uint devdisr; /* 0x.0070 - Device Disable Control */ + char res7[12]; + uint powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ + char res8[12]; + uint mcpsumr; /* 0x.0090 - Machine Check Summary Register */ + char res9[12]; + uint pvr; /* 0x.00a0 - Processor Version Register */ + uint svr; /* 0x.00a4 - System Version Register */ + char res10[3416]; + uint clkocr; /* 0x.0e00 - Clock Out Select Register */ + char res11[12]; + uint ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ + char res12[12]; + uint lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ + char res13[61916]; +} ccsr_guts_t; + +#endif /* __ASM_IMMAP_85XX_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h new file mode 100644 index 000000000..276a81706 --- /dev/null +++ b/include/asm-ppc/mpc85xx.h @@ -0,0 +1,128 @@ +/* + * include/asm-ppc/mpc85xx.h + * + * MPC85xx definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_MPC85xx_H__ +#define __ASM_MPC85xx_H__ + +#include +#include + +#ifdef CONFIG_85xx + +#ifdef CONFIG_MPC8540_ADS +#include +#endif + +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +#define PCI_DRAM_OFFSET pci_dram_offset + +/* + * The "residual" board information structure the boot loader passes + * into the kernel. + */ +extern unsigned char __res[]; + +/* Internal IRQs on MPC85xx OpenPIC */ +/* Not all of these exist on all MPC85xx implementations */ + +#ifndef MPC85xx_OPENPIC_IRQ_OFFSET +#define MPC85xx_OPENPIC_IRQ_OFFSET 64 +#endif + +/* The 32 internal sources */ +#define MPC85xx_IRQ_L2CACHE ( 0 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_ECM ( 1 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DDR ( 2 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_LBIU ( 3 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DMA0 ( 4 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DMA1 ( 5 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DMA2 ( 6 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DMA3 ( 7 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_PCI1 ( 8 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_PCI2 ( 9 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_RIO_ERROR ( 9 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_RIO_BELL (10 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_RIO_TX (11 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_RIO_RX (12 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC1_TX (13 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC1_RX (14 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC1_ERROR (18 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC2_TX (19 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC2_RX (20 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC2_ERROR (24 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_FEC (25 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_DUART (26 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_IIC1 (27 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_PERFMON (28 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_CPM (30 + MPC85xx_OPENPIC_IRQ_OFFSET) + +/* The 12 external interrupt lines */ +#define MPC85xx_IRQ_EXT0 (32 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT1 (33 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT2 (34 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT3 (35 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT4 (36 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT5 (37 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT6 (38 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT7 (39 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT8 (40 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT9 (41 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT10 (42 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT11 (43 + MPC85xx_OPENPIC_IRQ_OFFSET) + +/* Offset from CCSRBAR */ +#define MPC85xx_CPM_OFFSET (0x80000) +#define MPC85xx_CPM_SIZE (0x40000) +#define MPC85xx_DMA_OFFSET (0x21000) +#define MPC85xx_DMA_SIZE (0x01000) +#define MPC85xx_ENET1_OFFSET (0x24000) +#define MPC85xx_ENET1_SIZE (0x01000) +#define MPC85xx_ENET2_OFFSET (0x25000) +#define MPC85xx_ENET2_SIZE (0x01000) +#define MPC85xx_ENET3_OFFSET (0x26000) +#define MPC85xx_ENET3_SIZE (0x01000) +#define MPC85xx_GUTS_OFFSET (0xe0000) +#define MPC85xx_GUTS_SIZE (0x01000) +#define MPC85xx_IIC1_OFFSET (0x03000) +#define MPC85xx_IIC1_SIZE (0x01000) +#define MPC85xx_OPENPIC_OFFSET (0x40000) +#define MPC85xx_OPENPIC_SIZE (0x40000) +#define MPC85xx_PCI1_OFFSET (0x08000) +#define MPC85xx_PCI1_SIZE (0x01000) +#define MPC85xx_PCI2_OFFSET (0x09000) +#define MPC85xx_PCI2_SIZE (0x01000) +#define MPC85xx_PERFMON_OFFSET (0xe1000) +#define MPC85xx_PERFMON_SIZE (0x01000) +#define MPC85xx_UART0_OFFSET (0x04500) +#define MPC85xx_UART0_SIZE (0x00100) +#define MPC85xx_UART1_OFFSET (0x04600) +#define MPC85xx_UART1_SIZE (0x00100) + +#define MPC85xx_CCSRBAR_SIZE (1024*1024) + +/* Let modules/drivers get at CCSRBAR */ +extern phys_addr_t get_ccsrbar(void); + +#ifdef MODULE +#define CCSRBAR get_ccsrbar() +#else +#define CCSRBAR BOARD_CCSRBAR +#endif + +#endif /* CONFIG_85xx */ +#endif /* __ASM_MPC85xx_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h index 931b6de7e..0ec3df239 100644 --- a/include/asm-ppc/pgalloc.h +++ b/include/asm-ppc/pgalloc.h @@ -40,5 +40,10 @@ extern void pte_free(struct page *pte); #define check_pgt_cache() do { } while (0) +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + + #endif /* _PPC_PGALLOC_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 01256bda1..976796d2f 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -555,12 +555,8 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW); pte_update(ptep, 0, bits); } - #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ - do { \ - __ptep_set_access_flags(__ptep, __entry, __dirty); \ - flush_tlb_page_nohash(__vma, __address); \ - } while(0) + __ptep_set_access_flags(__ptep, __entry, __dirty) /* * Macro to mark a page protection value as "uncacheable". diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h index 2c688c1fd..2267f08d2 100644 --- a/include/asm-ppc/reg_booke.h +++ b/include/asm-ppc/reg_booke.h @@ -11,24 +11,19 @@ #ifndef __ASSEMBLY__ /* Device Control Registers */ -void __mtdcr(int reg, unsigned int val); -unsigned int __mfdcr(int reg); -#define mfdcr(rn) \ - ({unsigned int rval; \ - if (__builtin_constant_p(rn)) \ - asm volatile("mfdcr %0," __stringify(rn) \ - : "=r" (rval)); \ - else \ - rval = __mfdcr(rn); \ +#define mfdcr(rn) mfdcr_or_dflt(rn, 0) +#define mfdcr_or_dflt(rn,default_rval) \ + ({unsigned int rval; \ + if (rn == 0) \ + rval = default_rval; \ + else \ + asm volatile("mfdcr %0," __stringify(rn) : "=r" (rval)); \ rval;}) -#define mtdcr(rn, v) \ -do { \ - if (__builtin_constant_p(rn)) \ - asm volatile("mtdcr " __stringify(rn) ",%0" \ - : : "r" (v)); \ - else \ - __mtdcr(rn, v); \ +#define mtdcr(rn, v) \ +do { \ + if (rn != 0) \ + asm volatile("mtdcr " __stringify(rn) ",%0" : : "r" (v)); \ } while (0) /* R/W of indirect DCRs make use of standard naming conventions for DCRs */ diff --git a/include/asm-ppc/relay.h b/include/asm-ppc/relay.h new file mode 100644 index 000000000..c5b8526a7 --- /dev/null +++ b/include/asm-ppc/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_PPC_RELAY_H +#define _ASM_PPC_RELAY_H + +#include +#endif diff --git a/include/asm-ppc/resource.h b/include/asm-ppc/resource.h index 956b34602..475f3095e 100644 --- a/include/asm-ppc/resource.h +++ b/include/asm-ppc/resource.h @@ -34,7 +34,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-ppc/rmap.h b/include/asm-ppc/rmap.h deleted file mode 100644 index 50556b5ff..000000000 --- a/include/asm-ppc/rmap.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _PPC_RMAP_H -#define _PPC_RMAP_H - -/* PPC calls pte_alloc() before mem_map[] is setup ... */ -#define BROKEN_PPC_PTE_ALLOC_ONE - -#include - -#endif diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h index d91ba524d..3ceaf16a5 100644 --- a/include/asm-ppc/spinlock.h +++ b/include/asm-ppc/spinlock.h @@ -65,6 +65,7 @@ static inline void _raw_spin_unlock(spinlock_t *lock) extern void _raw_spin_lock(spinlock_t *lock); extern void _raw_spin_unlock(spinlock_t *lock); extern int _raw_spin_trylock(spinlock_t *lock); +extern unsigned long __spin_trylock(volatile unsigned long *lock); #endif @@ -135,26 +136,6 @@ static __inline__ void _raw_read_unlock(rwlock_t *rw) : "cr0", "memory"); } -static __inline__ int _raw_write_trylock(rwlock_t *rw) -{ - unsigned int tmp; - - __asm__ __volatile__( -"2: lwarx %0,0,%1 # write_trylock\n\ - cmpwi 0,%0,0\n\ - bne- 1f\n" - PPC405_ERR77(0,%1) -" stwcx. %2,0,%1\n\ - bne- 2b\n\ - isync\n\ -1:" - : "=&r"(tmp) - : "r"(&rw->lock), "r"(-1) - : "cr0", "memory"); - - return tmp == 0; -} - static __inline__ void _raw_write_lock(rwlock_t *rw) { unsigned int tmp; @@ -188,7 +169,6 @@ extern void _raw_read_lock(rwlock_t *rw); extern void _raw_read_unlock(rwlock_t *rw); extern void _raw_write_lock(rwlock_t *rw); extern void _raw_write_unlock(rwlock_t *rw); -extern int _raw_write_trylock(rwlock_t *rw); #endif diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h index 57fb02c6c..388789e68 100644 --- a/include/asm-ppc/unistd.h +++ b/include/asm-ppc/unistd.h @@ -261,7 +261,7 @@ #define __NR_fadvise64_64 254 #define __NR_rtas 255 /* Number 256 is reserved for sys_debug_setcontext */ -/* Number 257 is reserved for vserver */ +#define __NR_vserver 257 /* Number 258 is reserved for new sys_remap_file_pages */ /* Number 259 is reserved for new sys_mbind */ /* Number 260 is reserved for new sys_get_mempolicy */ @@ -402,7 +402,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION /* * Forking from kernel space will result in the child getting a new, diff --git a/include/asm-ppc64/fcntl.h b/include/asm-ppc64/fcntl.h index 1ef83570b..790d62449 100644 --- a/include/asm-ppc64/fcntl.h +++ b/include/asm-ppc64/fcntl.h @@ -27,6 +27,7 @@ #define O_NOFOLLOW 0100000 /* don't follow links */ #define O_LARGEFILE 0200000 #define O_DIRECT 0400000 /* direct disk access hint */ +#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h index f6262bad7..ed8139880 100644 --- a/include/asm-ppc64/io.h +++ b/include/asm-ppc64/io.h @@ -307,7 +307,7 @@ static inline void out_le32(volatile unsigned *addr, int val) static inline void out_be32(volatile unsigned *addr, int val) { - __asm__ __volatile__("stw%U0%X0 %1,%0; sync" + __asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val)); } @@ -356,9 +356,9 @@ static inline void out_le64(volatile unsigned long *addr, unsigned long val) : "=&r" (tmp) , "=&r" (val) : "1" (val) , "b" (addr) , "m" (*addr)); } -static inline void out_be64(volatile unsigned long *addr, unsigned long val) +static inline void out_be64(volatile unsigned long *addr, int val) { - __asm__ __volatile__("std%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val)); + __asm__ __volatile__("std %1,0(%0); sync" : "=m" (*addr) : "r" (val)); } #ifndef CONFIG_PPC_ISERIES diff --git a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h index bf38c7f01..9b6028915 100644 --- a/include/asm-ppc64/paca.h +++ b/include/asm-ppc64/paca.h @@ -37,8 +37,6 @@ extern struct paca_struct paca[]; register struct paca_struct *local_paca asm("r13"); #define get_paca() local_paca -struct task_struct; - /*============================================================================ * Name_______: paca * @@ -61,7 +59,7 @@ struct paca_struct { */ struct ItLpPaca *xLpPacaPtr; /* Pointer to LpPaca for PLIC 0x00 */ struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC 0x08 */ - struct task_struct *xCurrent; /* Pointer to current 0x10 */ + u64 xCurrent; /* Pointer to current 0x10 */ /* Note: the spinlock functions in arch/ppc64/lib/locks.c load lock_token and xPacaIndex with a single lwz instruction, using the constant offset 24. If you move either field, fix the spinlocks and rwlocks. */ diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h index 3a073a3c0..29b5727ef 100644 --- a/include/asm-ppc64/pgalloc.h +++ b/include/asm-ppc64/pgalloc.h @@ -10,6 +10,11 @@ extern kmem_cache_t *zero_cache; +/* Dummy functions since we don't support execshield on ppc */ +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h index b1e7f6d4f..befa84567 100644 --- a/include/asm-ppc64/pgtable.h +++ b/include/asm-ppc64/pgtable.h @@ -428,10 +428,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) :"cc"); } #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ - do { \ - __ptep_set_access_flags(__ptep, __entry, __dirty); \ - flush_tlb_page_nohash(__vma, __address); \ - } while(0) + __ptep_set_access_flags(__ptep, __entry, __dirty) /* * Macro to mark a page protection value as "uncacheable". diff --git a/include/asm-ppc64/relay.h b/include/asm-ppc64/relay.h new file mode 100644 index 000000000..3c428ef02 --- /dev/null +++ b/include/asm-ppc64/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_PPC64_RELAY_H +#define _ASM_PPC64_RELAY_H + +#include +#endif diff --git a/include/asm-ppc64/resource.h b/include/asm-ppc64/resource.h index b43a4ea0a..691a3fa3e 100644 --- a/include/asm-ppc64/resource.h +++ b/include/asm-ppc64/resource.h @@ -43,7 +43,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-ppc64/rmap.h b/include/asm-ppc64/rmap.h deleted file mode 100644 index cf58a01ec..000000000 --- a/include/asm-ppc64/rmap.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _PPC64_RMAP_H -#define _PPC64_RMAP_H - -/* PPC64 calls pte_alloc() before mem_map[] is setup ... */ -#define BROKEN_PPC_PTE_ALLOC_ONE - -#include - -#endif diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h index 20c4b3aae..39ffcca2f 100644 --- a/include/asm-ppc64/unistd.h +++ b/include/asm-ppc64/unistd.h @@ -267,7 +267,7 @@ #define __NR_fadvise64_64 254 #define __NR_rtas 255 /* Number 256 is reserved for sys_debug_setcontext */ -/* Number 257 is reserved for vserver */ +#define __NR_vserver 257 /* Number 258 is reserved for new sys_remap_file_pages */ /* Number 259 is reserved for new sys_mbind */ /* Number 260 is reserved for new sys_get_mempolicy */ @@ -439,7 +439,6 @@ static inline _syscall3(int, execve, __const__ char *, file, char **, argv, #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, off_t offset); diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h index 541b6da9d..edce41443 100644 --- a/include/asm-s390/atomic.h +++ b/include/asm-s390/atomic.h @@ -145,7 +145,7 @@ static __inline__ long long atomic64_inc_return(volatile atomic64_t * v) } static __inline__ long long atomic64_inc_and_test(volatile atomic64_t * v) { - return __CSG_LOOP(v, 1, "agr") == 0; + return __CSG_LOOP(v, 1, "agr") != 0; } static __inline__ void atomic64_dec(volatile atomic64_t * v) { diff --git a/include/asm-s390/fcntl.h b/include/asm-s390/fcntl.h index 307c01b45..2912944d7 100644 --- a/include/asm-s390/fcntl.h +++ b/include/asm-s390/fcntl.h @@ -27,6 +27,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup (tux) */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 90308137c..8b9bfd227 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -19,6 +19,10 @@ #include #include +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + #define check_pgt_cache() do {} while (0) extern void diag10(unsigned long addr); diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 11b67469b..ebd93e484 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -587,9 +587,6 @@ ptep_establish(struct vm_area_struct *vma, set_pte(ptep, entry); } -#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ - ptep_establish(__vma, __address, __ptep, __entry) - /* * Test and clear dirty bit in storage key. * We can't clear the changed bit atomically. This is a potential @@ -787,7 +784,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define pgtable_cache_init() do { } while (0) #define __HAVE_ARCH_PTEP_ESTABLISH -#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY diff --git a/include/asm-s390/relay.h b/include/asm-s390/relay.h new file mode 100644 index 000000000..502eb3b58 --- /dev/null +++ b/include/asm-s390/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_S390_RELAY_H +#define _ASM_S390_RELAY_H + +#include +#endif diff --git a/include/asm-s390/resource.h b/include/asm-s390/resource.h index bc2520e1d..5ecbcbc57 100644 --- a/include/asm-s390/resource.h +++ b/include/asm-s390/resource.h @@ -45,7 +45,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-s390/rmap.h b/include/asm-s390/rmap.h deleted file mode 100644 index 43d6a87b6..000000000 --- a/include/asm-s390/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _S390_RMAP_H -#define _S390_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h index bc7a8471c..c617ab34f 100644 --- a/include/asm-s390/spinlock.h +++ b/include/asm-s390/spinlock.h @@ -48,7 +48,7 @@ extern inline void _raw_spin_lock(spinlock_t *lp) { #ifndef __s390x__ unsigned int reg1, reg2; - __asm__ __volatile__(" bras %0,1f\n" + __asm__ __volatile(" bras %0,1f\n" "0: diag 0,0,68\n" "1: slr %1,%1\n" " cs %1,%0,0(%3)\n" @@ -58,7 +58,7 @@ extern inline void _raw_spin_lock(spinlock_t *lp) : "cc", "memory" ); #else /* __s390x__ */ unsigned long reg1, reg2; - __asm__ __volatile__(" bras %1,1f\n" + __asm__ __volatile(" bras %1,1f\n" "0: " __DIAG44_INSN " 0,%4\n" "1: slr %0,%0\n" " cs %0,%1,0(%3)\n" @@ -74,7 +74,7 @@ extern inline int _raw_spin_trylock(spinlock_t *lp) unsigned long reg; unsigned int result; - __asm__ __volatile__(" basr %1,0\n" + __asm__ __volatile(" basr %1,0\n" "0: cs %0,%1,0(%3)" : "=d" (result), "=&d" (reg), "=m" (lp->lock) : "a" (&lp->lock), "m" (lp->lock), "0" (0) @@ -86,7 +86,7 @@ extern inline void _raw_spin_unlock(spinlock_t *lp) { unsigned int old; - __asm__ __volatile__("cs %0,%3,0(%4)" + __asm__ __volatile("cs %0,%3,0(%4)" : "=d" (old), "=m" (lp->lock) : "0" (lp->lock), "d" (0), "a" (lp) : "cc", "memory" ); diff --git a/include/asm-s390/types.h b/include/asm-s390/types.h index 3fefd6141..dd57b3f8f 100644 --- a/include/asm-s390/types.h +++ b/include/asm-s390/types.h @@ -79,8 +79,6 @@ typedef unsigned long u64; typedef u32 dma_addr_t; -typedef unsigned int kmem_bufctl_t; - #ifndef __s390x__ typedef union { unsigned long long pair; @@ -96,6 +94,9 @@ typedef u64 sector_t; #endif #endif /* ! __s390x__ */ + +typedef unsigned int kmem_bufctl_t; + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _S390_TYPES_H */ diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index bec57b750..bf4d2fca3 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -65,10 +65,9 @@ #define access_ok(type,addr,size) __access_ok(addr,size) -extern inline int verify_area(int type, const void __user *addr, - unsigned long size) +extern inline int verify_area(int type, const void * addr, unsigned long size) { - return access_ok(type, addr, size) ? 0 : -EFAULT; + return access_ok(type,addr,size)?0:-EFAULT; } /* @@ -148,7 +147,6 @@ struct exception_table_entry }) #endif -#ifndef __CHECKER__ #define __put_user(x, ptr) \ ({ \ __typeof__(*(ptr)) __x = (x); \ @@ -166,14 +164,6 @@ struct exception_table_entry } \ __pu_err; \ }) -#else -#define __put_user(x, ptr) \ -({ \ - void __user *p; \ - p = (ptr); \ - 0; \ -}) -#endif #define put_user(x, ptr) \ ({ \ @@ -212,7 +202,6 @@ extern int __put_user_bad(void); }) #endif -#ifndef __CHECKER__ #define __get_user(x, ptr) \ ({ \ __typeof__(*(ptr)) __x; \ @@ -232,15 +221,6 @@ extern int __put_user_bad(void); (x) = __x; \ __gu_err; \ }) -#else -#define __get_user(x, ptr) \ -({ \ - void __user *p; \ - p = (ptr); \ - 0; \ -}) -#endif - #define get_user(x, ptr) \ ({ \ @@ -250,7 +230,7 @@ extern int __put_user_bad(void); extern int __get_user_bad(void); -extern long __copy_to_user_asm(const void *from, long n, void __user *to); +extern long __copy_to_user_asm(const void *from, long n, void *to); /** * __copy_to_user: - Copy a block of data into user space, with less checking. @@ -294,7 +274,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n) return n; } -extern long __copy_from_user_asm(void *to, long n, const void __user *from); +extern long __copy_from_user_asm(void *to, long n, const void *from); /** * __copy_from_user: - Copy a block of data from user space, with less checking. @@ -346,13 +326,12 @@ copy_from_user(void *to, const void __user *from, unsigned long n) return n; } -extern unsigned long __copy_in_user_asm(const void __user *from, long n, - void __user *to); +extern long __copy_in_user_asm(const void *from, long n, void *to); static inline unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n) { - return __copy_in_user_asm(from, n, to); + __copy_in_user_asm(from, n, to); } static inline unsigned long @@ -367,27 +346,26 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n) /* * Copy a null terminated string from userspace. */ -extern long __strncpy_from_user_asm(long count, char *dst, - const char __user *src); +extern long __strncpy_from_user_asm(char *dst, const char *src, long count); static inline long -strncpy_from_user(char *dst, const char __user *src, long count) +strncpy_from_user(char *dst, const char *src, long count) { long res = -EFAULT; might_sleep(); if (access_ok(VERIFY_READ, src, 1)) - res = __strncpy_from_user_asm(count, dst, src); + res = __strncpy_from_user_asm(dst, src, count); return res; } -extern long __strnlen_user_asm(long count, const char __user *src); +extern long __strnlen_user_asm(const char *src, long count); static inline unsigned long -strnlen_user(const char __user * src, unsigned long n) +strnlen_user(const char * src, unsigned long n) { might_sleep(); - return __strnlen_user_asm(n, src); + return __strnlen_user_asm(src, n); } /** @@ -410,16 +388,16 @@ strnlen_user(const char __user * src, unsigned long n) * Zero Userspace */ -extern long __clear_user_asm(void __user *to, long n); +extern long __clear_user_asm(void *to, long n); static inline unsigned long -__clear_user(void __user *to, unsigned long n) +__clear_user(void *to, unsigned long n) { return __clear_user_asm(to, n); } static inline unsigned long -clear_user(void __user *to, unsigned long n) +clear_user(void *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 4d46012fe..874e25d7f 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -255,7 +255,7 @@ #define __NR_clock_gettime (__NR_timer_create+6) #define __NR_clock_getres (__NR_timer_create+7) #define __NR_clock_nanosleep (__NR_timer_create+8) -/* Number 263 is reserved for vserver */ +#define __NR_vserver 263 #define __NR_fadvise64_64 264 #define __NR_statfs64 265 #define __NR_fstatfs64 266 @@ -530,7 +530,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION # ifndef CONFIG_ARCH_S390X # define __ARCH_WANT_STAT64 # endif diff --git a/include/asm-sh/relay.h b/include/asm-sh/relay.h new file mode 100644 index 000000000..fd8b76416 --- /dev/null +++ b/include/asm-sh/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_SH_RELAY_H +#define _ASM_SH_RELAY_H + +#include +#endif diff --git a/include/asm-sh/resource.h b/include/asm-sh/resource.h index 574b64488..42faf5b28 100644 --- a/include/asm-sh/resource.h +++ b/include/asm-sh/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-sh/rmap.h b/include/asm-sh/rmap.h deleted file mode 100644 index 31db8cc07..000000000 --- a/include/asm-sh/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SH_RMAP_H -#define _SH_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 26ad6dd92..9384ed221 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -422,7 +422,6 @@ __syscall_return(type,__sc0); \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-sparc/fcntl.h b/include/asm-sparc/fcntl.h index aa64cfc1d..4eff92f4c 100644 --- a/include/asm-sparc/fcntl.h +++ b/include/asm-sparc/fcntl.h @@ -20,6 +20,7 @@ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ #define O_LARGEFILE 0x40000 +#define O_ATOMICLOOKUP 0x80000 /* do atomic file lookup */ #define O_DIRECT 0x100000 /* direct disk access hint */ #define F_DUPFD 0 /* dup */ diff --git a/include/asm-sparc/pgalloc.h b/include/asm-sparc/pgalloc.h index 126800acd..8db566203 100644 --- a/include/asm-sparc/pgalloc.h +++ b/include/asm-sparc/pgalloc.h @@ -66,4 +66,8 @@ BTFIXUPDEF_CALL(void, pte_free, struct page *) #define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) #define __pte_free_tlb(tlb, pte) pte_free(pte) +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + #endif /* _SPARC_PGALLOC_H */ diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index fa537363f..291f86233 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -75,10 +75,29 @@ BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len) #define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len) #define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba) +/* + */ +BTFIXUPDEF_SIMM13(pmd_shift) +BTFIXUPDEF_SETHI(pmd_size) +BTFIXUPDEF_SETHI(pmd_mask) + +extern unsigned int pmd_align(unsigned int addr) __attribute_const__; +extern __inline__ unsigned int pmd_align(unsigned int addr) +{ + return ((addr + ~BTFIXUP_SETHI(pmd_mask)) & BTFIXUP_SETHI(pmd_mask)); +} + BTFIXUPDEF_SIMM13(pgdir_shift) BTFIXUPDEF_SETHI(pgdir_size) BTFIXUPDEF_SETHI(pgdir_mask) +extern unsigned int pgdir_align(unsigned int addr) __attribute_const__; +extern __inline__ unsigned int pgdir_align(unsigned int addr) +{ + return ((addr + ~BTFIXUP_SETHI(pgdir_mask)) & BTFIXUP_SETHI(pgdir_mask)); +} + +BTFIXUPDEF_SIMM13(ptrs_per_pte) BTFIXUPDEF_SIMM13(ptrs_per_pmd) BTFIXUPDEF_SIMM13(ptrs_per_pgd) BTFIXUPDEF_SIMM13(user_ptrs_per_pgd) @@ -93,19 +112,19 @@ BTFIXUPDEF_INT(page_copy) BTFIXUPDEF_INT(page_readonly) BTFIXUPDEF_INT(page_kernel) -#define PMD_SHIFT SUN4C_PMD_SHIFT -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) -#define PMD_ALIGN(__addr) (((__addr) + ~PMD_MASK) & PMD_MASK) +#define PMD_SHIFT BTFIXUP_SIMM13(pmd_shift) +#define PMD_SIZE BTFIXUP_SETHI(pmd_size) +#define PMD_MASK BTFIXUP_SETHI(pmd_mask) +#define PMD_ALIGN(addr) pmd_align(addr) #define PGDIR_SHIFT BTFIXUP_SIMM13(pgdir_shift) #define PGDIR_SIZE BTFIXUP_SETHI(pgdir_size) #define PGDIR_MASK BTFIXUP_SETHI(pgdir_mask) -#define PTRS_PER_PTE 1024 +#define PGDIR_ALIGN pgdir_align(addr) +#define PTRS_PER_PTE BTFIXUP_SIMM13(ptrs_per_pte) #define PTRS_PER_PMD BTFIXUP_SIMM13(ptrs_per_pmd) #define PTRS_PER_PGD BTFIXUP_SIMM13(ptrs_per_pgd) #define USER_PTRS_PER_PGD BTFIXUP_SIMM13(user_ptrs_per_pgd) #define FIRST_USER_PGD_NR 0 -#define PTE_SIZE (PTRS_PER_PTE*4) #define PAGE_NONE __pgprot(BTFIXUP_INT(page_none)) #define PAGE_SHARED __pgprot(BTFIXUP_INT(page_shared)) diff --git a/include/asm-sparc/relay.h b/include/asm-sparc/relay.h new file mode 100644 index 000000000..2141eac01 --- /dev/null +++ b/include/asm-sparc/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_SPARC_RELAY_H +#define _ASM_SPARC_RELAY_H + +#include +#endif diff --git a/include/asm-sparc/resource.h b/include/asm-sparc/resource.h index 8237763e5..b6a5aca2a 100644 --- a/include/asm-sparc/resource.h +++ b/include/asm-sparc/resource.h @@ -42,7 +42,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {RLIM_INFINITY, RLIM_INFINITY}, \ + {PAGE_SIZE, PAGE_SIZE}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY} \ } diff --git a/include/asm-sparc/rmap.h b/include/asm-sparc/rmap.h deleted file mode 100644 index 06063cffe..000000000 --- a/include/asm-sparc/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SPARC_RMAP_H -#define _SPARC_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 62eaacd9f..b742c9f4d 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -283,7 +283,7 @@ #define __NR_timer_getoverrun 264 #define __NR_timer_delete 265 #define __NR_timer_create 266 -/* #define __NR_vserver 267 Reserved for VSERVER */ +#define __NR_vserver 267 #define __NR_io_setup 268 #define __NR_io_destroy 269 #define __NR_io_submit 270 diff --git a/include/asm-sparc64/fcntl.h b/include/asm-sparc64/fcntl.h index 0999d6d52..5a9c260ee 100644 --- a/include/asm-sparc64/fcntl.h +++ b/include/asm-sparc64/fcntl.h @@ -20,6 +20,7 @@ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ #define O_LARGEFILE 0x40000 +#define O_ATOMICLOOKUP 0x80000 /* do atomic file lookup */ #define O_DIRECT 0x100000 /* direct disk access hint */ diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index 8354a057b..acc08c228 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h @@ -236,4 +236,8 @@ static __inline__ void free_pte_slow(pte_t *pte) #define pgd_free(pgd) free_pgd_fast(pgd) #define pgd_alloc(mm) get_pgd_fast() +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + #endif /* _SPARC64_PGALLOC_H */ diff --git a/include/asm-sparc64/relay.h b/include/asm-sparc64/relay.h new file mode 100644 index 000000000..72ea16410 --- /dev/null +++ b/include/asm-sparc64/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_SPARC64_RELAY_H +#define _ASM_SPARC64_RELAY_H + +#include +#endif diff --git a/include/asm-sparc64/resource.h b/include/asm-sparc64/resource.h index 06150c09f..0ae54dc7f 100644 --- a/include/asm-sparc64/resource.h +++ b/include/asm-sparc64/resource.h @@ -41,7 +41,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {RLIM_INFINITY, RLIM_INFINITY}, \ + {PAGE_SIZE, PAGE_SIZE }, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY} \ } diff --git a/include/asm-sparc64/rmap.h b/include/asm-sparc64/rmap.h deleted file mode 100644 index 681849b2d..000000000 --- a/include/asm-sparc64/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SPARC64_RMAP_H -#define _SPARC64_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index 0ce57c1b4..0a06763b8 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -285,7 +285,7 @@ #define __NR_timer_getoverrun 264 #define __NR_timer_delete 265 #define __NR_timer_create 266 -/* #define __NR_vserver 267 Reserved for VSERVER */ +#define __NR_vserver 267 #define __NR_io_setup 268 #define __NR_io_destroy 269 #define __NR_io_submit 270 diff --git a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h index a23261baa..85fd03358 100644 --- a/include/asm-um/archparam-i386.h +++ b/include/asm-um/archparam-i386.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -56,6 +56,93 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; pr_reg[16] = PT_REGS_SS(regs); \ } while(0); +#if 0 /* Turn this back on when UML has VSYSCALL working */ +#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) +#else +#define VSYSCALL_BASE 0 +#endif + +#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) +#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) +extern void *__kernel_vsyscall; + +/* + * Architecture-neutral AT_ values in 0-17, leave some room + * for more of them, start the x86-specific ones at 32. + */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ +} while (0) + +/* + * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out + * extra segments containing the vsyscall DSO contents. Dumping its + * contents makes post-mortem fully interpretable later without matching up + * the same kernel and hardware config to see what PC values meant. + * Dumping its extra ELF program headers includes all the other information + * a debugger needs to easily find how the vsyscall DSO was being used. + */ +#if 0 +#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) +#endif + +#undef ELF_CORE_EXTRA_PHDRS + +#if 0 +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + Elf32_Off ofs = 0; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + struct elf_phdr phdr = vsyscall_phdrs[i]; \ + if (phdr.p_type == PT_LOAD) { \ + ofs = phdr.p_offset = offset; \ + offset += phdr.p_filesz; \ + } \ + else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} while (0) +#define ELF_CORE_WRITE_EXTRA_DATA \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + if (vsyscall_phdrs[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ + vsyscall_phdrs[i].p_filesz); \ + } \ +} while (0) +#endif + +#undef ELF_CORE_WRITE_EXTRA_PHDRS +#undef ELF_CORE_WRITE_EXTRA_DATA + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + /********* Bits for asm-um/delay.h **********/ typedef unsigned long um_udelay_t; diff --git a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S index d2517a04c..992315c87 100644 --- a/include/asm-um/common.lds.S +++ b/include/asm-um/common.lds.S @@ -1,3 +1,5 @@ +#include + .fini : { *(.fini) } =0x9090 _etext = .; PROVIDE (etext = .); @@ -13,18 +15,6 @@ RODATA - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - __start___gpl_ksymtab = .; /* Kernel symbol table: GPL-only symbols */ - __gpl_ksymtab : { *(__gpl_ksymtab) } - __stop___gpl_ksymtab = .; - - __start___kallsyms = .; /* All kernel symbols */ - __kallsyms : { *(__kallsyms) } - __stop___kallsyms = .; - .unprotected : { *(.unprotected) } . = ALIGN(4096); PROVIDE (_unprotected_end = .); @@ -67,11 +57,17 @@ } __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + __uml_initcall_start = .; .uml.initcall.init : { *(.uml.initcall.init) } __uml_initcall_end = .; __init_end = .; + SECURITY_INIT + __exitcall_begin = .; .exitcall : { *(.exitcall.exit) } __exitcall_end = .; @@ -80,7 +76,33 @@ .uml.exitcall : { *(.uml.exitcall.exit) } __uml_exitcall_end = .; - . = ALIGN(4096); + . = ALIGN(4); + __alt_instructions = .; + .altinstructions : { *(.altinstructions) } + __alt_instructions_end = .; + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + + __preinit_array_start = .; + .preinit_array : { *(.preinit_array) } + __preinit_array_end = .; + __init_array_start = .; + .init_array : { *(.init_array) } + __init_array_end = .; + __fini_array_start = .; + .fini_array : { *(.fini_array) } + __fini_array_end = .; + + . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) + } + diff --git a/include/asm-um/current.h b/include/asm-um/current.h index adfe568cf..72a4cbd91 100644 --- a/include/asm-um/current.h +++ b/include/asm-um/current.h @@ -16,8 +16,10 @@ struct thread_info; #define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & \ (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER)) -#define current ({ int dummy; \ - ((struct thread_info *) CURRENT_THREAD(dummy))->task; }) +#define current_thread \ + ({ int dummy; ((struct thread_info *) CURRENT_THREAD(dummy)); }) + +#define current (current_thread->task) #endif /* __ASSEMBLY__ */ diff --git a/include/asm-um/dma-mapping.h b/include/asm-um/dma-mapping.h index e7e16901f..2ea882811 100644 --- a/include/asm-um/dma-mapping.h +++ b/include/asm-um/dma-mapping.h @@ -1 +1,119 @@ -#include +#ifndef _ASM_DMA_MAPPING_H +#define _ASM_DMA_MAPPING_H + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + BUG(); + return(0); +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG(); + return(0); +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + int flag) +{ + BUG(); + return((void *) 0); +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d) (1) + +static inline int +dma_get_cache_alignment(void) +{ + BUG(); + return(0); +} + +static inline void +dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +#endif diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h index f33a3533f..c96c5eb92 100644 --- a/include/asm-um/elf.h +++ b/include/asm-um/elf.h @@ -15,4 +15,17 @@ #define USE_ELF_CORE_DUMP +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + #endif diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h index 0e8a4c1ac..ef4890b11 100644 --- a/include/asm-um/fixmap.h +++ b/include/asm-um/fixmap.h @@ -34,6 +34,7 @@ enum fixed_addresses { FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + FIX_VSYSCALL, __end_of_fixed_addresses }; @@ -63,6 +64,13 @@ extern unsigned long get_kmem_end(void); #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) +/* + * This is the range that is readable by user mode, and things + * acting like user mode such as get_user_pages. + */ +#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL)) +#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE) + extern void __this_fixmap_does_not_exist(void); /* diff --git a/include/asm-um/irq.h b/include/asm-um/irq.h index 8300c209a..de389a477 100644 --- a/include/asm-um/irq.h +++ b/include/asm-um/irq.h @@ -1,15 +1,6 @@ #ifndef __UM_IRQ_H #define __UM_IRQ_H -/* The i386 irq.h has a struct task_struct in a prototype without including - * sched.h. This forward declaration kills the resulting warning. - */ -struct task_struct; - -#include "asm/ptrace.h" - -#undef NR_IRQS - #define TIMER_IRQ 0 #define UMN_IRQ 1 #define CONSOLE_IRQ 2 @@ -28,13 +19,4 @@ struct task_struct; #define LAST_IRQ XTERM_IRQ #define NR_IRQS (LAST_IRQ + 1) -extern int um_request_irq(unsigned int irq, int fd, int type, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, - void *dev_id); - -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif diff --git a/include/asm-um/module-i386.h b/include/asm-um/module-i386.h new file mode 100644 index 000000000..5ead4a0b2 --- /dev/null +++ b/include/asm-um/module-i386.h @@ -0,0 +1,13 @@ +#ifndef __UM_MODULE_I386_H +#define __UM_MODULE_I386_H + +/* UML is simple */ +struct mod_arch_specific +{ +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#endif diff --git a/include/asm-um/page.h b/include/asm-um/page.h index ad97bc0a6..4ad178b61 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -1,10 +1,14 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + #ifndef __UM_PAGE_H #define __UM_PAGE_H struct page; #include "asm/arch/page.h" -#include "asm/bug.h" #undef __pa #undef __va @@ -24,25 +28,36 @@ extern unsigned long uml_physmem; #define __va_space (8*1024*1024) -extern unsigned long region_pa(void *virt); -extern void *region_va(unsigned long phys); - -#define __pa(virt) region_pa((void *) (virt)) -#define __va(phys) region_va((unsigned long) (phys)) - -extern unsigned long page_to_pfn(struct page *page); -extern struct page *pfn_to_page(unsigned long pfn); +extern unsigned long to_phys(void *virt); +extern void *to_virt(unsigned long phys); -extern struct page *phys_to_page(unsigned long phys); +#define __pa(virt) to_phys((void *) virt) +#define __va(phys) to_virt((unsigned long) phys) -#define virt_to_page(v) (phys_to_page(__pa(v))) +#define page_to_pfn(page) ((page) - mem_map) +#define pfn_to_page(pfn) (mem_map + (pfn)) -extern struct page *page_mem_map(struct page *page); +#define phys_to_pfn(p) ((p) >> PAGE_SHIFT) +#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -#define pfn_valid(pfn) (page_mem_map(pfn_to_page(pfn)) != NULL) -#define virt_addr_valid(v) pfn_valid(__pa(v) >> PAGE_SHIFT) +#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) extern struct page *arch_validate(struct page *page, int mask, int order); #define HAVE_ARCH_VALIDATE +extern void arch_free_page(struct page *page, int order); +#define HAVE_ARCH_FREE_PAGE + #endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h index 73973aeaf..e56bed37c 100644 --- a/include/asm-um/pgalloc.h +++ b/include/asm-um/pgalloc.h @@ -49,6 +49,10 @@ static inline void pte_free(struct page *pte) #define check_pgt_cache() do { } while (0) +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + #endif /* diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index 148dd8e42..6006b0bf6 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -12,8 +12,6 @@ #include "asm/page.h" #include "asm/fixmap.h" -extern pgd_t swapper_pg_dir[1024]; - extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, pte_t *pte_out); @@ -49,6 +47,8 @@ extern unsigned long *empty_zero_page; #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + /* * pgd entries used up by user/kernel: */ @@ -65,10 +65,10 @@ extern unsigned long *empty_zero_page; * area for the same reason. ;) */ -extern unsigned long high_physmem; +extern unsigned long end_iomem; #define VMALLOC_OFFSET (__va_space) -#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) @@ -78,12 +78,13 @@ extern unsigned long high_physmem; #define _PAGE_PRESENT 0x001 #define _PAGE_NEWPAGE 0x002 -#define _PAGE_PROTNONE 0x004 /* If not present */ -#define _PAGE_RW 0x008 -#define _PAGE_USER 0x010 -#define _PAGE_ACCESSED 0x020 -#define _PAGE_DIRTY 0x040 -#define _PAGE_NEWPROT 0x080 +#define _PAGE_NEWPROT 0x004 +#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */ +#define _PAGE_PROTNONE 0x010 /* If not present */ +#define _PAGE_RW 0x020 +#define _PAGE_USER 0x040 +#define _PAGE_ACCESSED 0x080 +#define _PAGE_DIRTY 0x100 #define REGION_MASK 0xf0000000 #define REGION_SHIFT 28 @@ -143,7 +144,8 @@ extern pte_t * __bad_pagetable(void); #define BAD_PAGETABLE __bad_pagetable() #define BAD_PAGE __bad_page() -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) /* number of bits that fit into a memory pointer */ #define BITS_PER_PTR (8*sizeof(unsigned long)) @@ -164,9 +166,6 @@ extern pte_t * __bad_pagetable(void); #define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0) -#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT) -#define pte_region_index(x) phys_region_index(pte_val(x)) - #define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE)) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) @@ -188,19 +187,25 @@ static inline void pgd_clear(pgd_t * pgdp) { } #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) -extern struct page *pte_mem_map(pte_t pte); -extern struct page *phys_mem_map(unsigned long phys); -extern unsigned long phys_to_pfn(unsigned long p); -extern unsigned long pfn_to_phys(unsigned long pfn); +#define pte_page(pte) phys_to_page(pte_val(pte)) +#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) -#define pte_page(x) pfn_to_page(pte_pfn(x)) -#define pte_address(x) (__va(pte_val(x) & PAGE_MASK)) -#define mk_phys(a, r) ((a) + (r << REGION_SHIFT)) -#define phys_addr(p) ((p) & ~REGION_MASK) -#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT)) #define pte_pfn(x) phys_to_pfn(pte_val(x)) #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) -#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) + +extern struct page *phys_to_page(const unsigned long phys); +extern struct page *__virt_to_page(const unsigned long virt); +#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) + +/* + * Bits 0 through 3 are taken + */ +#define PTE_FILE_MAX_BITS 28 + +#define pte_to_pgoff(pte) ((pte).pte_low >> 4) + +#define pgoff_to_pte(off) \ + ((pte_t) { ((off) << 4) + _PAGE_FILE }) static inline pte_t pte_mknewprot(pte_t pte) { @@ -235,6 +240,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) * The following only work if pte_present() is true. * Undefined behaviour if not.. */ +static inline int pte_user(pte_t pte) +{ + return((pte_val(pte) & _PAGE_USER) && + !(pte_val(pte) & _PAGE_PROTNONE)); +} + static inline int pte_read(pte_t pte) { return((pte_val(pte) & _PAGE_USER) && @@ -252,6 +263,14 @@ static inline int pte_write(pte_t pte) !(pte_val(pte) & _PAGE_PROTNONE)); } +/* + * The following only works if pte_present() is not true. + */ +static inline int pte_file(pte_t pte) +{ + return (pte).pte_low & _PAGE_FILE; +} + static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; } @@ -334,14 +353,7 @@ extern unsigned long page_to_phys(struct page *page); * and a page entry and page directory to the page they refer to. */ -#define mk_pte(page, pgprot) \ -({ \ - pte_t __pte; \ - \ - pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\ - if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \ - __pte; \ -}) +extern pte_t mk_pte(struct page *page, pgprot_t pgprot); static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -351,17 +363,27 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) } #define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) -#define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \ - ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT))) -/* to find an entry in a page-table-directory. */ +/* + * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] + * + * this macro returns the index of the entry in the pgd page which would + * control the given virtual address + */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) -/* to find an entry in a page-table-directory */ +/* + * pgd_offset() returns a (pgd_t *) + * pgd_index() is used get the offset into the pgd page's array of pgd_t's; + */ #define pgd_offset(mm, address) \ ((mm)->pgd + ((address) >> PGDIR_SHIFT)) -/* to find an entry in a kernel page-table-directory */ + +/* + * a shortcut which implies the use of the kernel's pgd, instead + * of a process's + */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) #define pmd_index(address) \ @@ -373,7 +395,12 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) return (pmd_t *) dir; } -/* Find an entry in the third-level page table.. */ +/* + * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] + * + * this macro returns the index of the entry in the pte page which would + * control the given virtual address + */ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, address) \ ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address)) @@ -387,11 +414,11 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) #define update_mmu_cache(vma,address,pte) do ; while (0) /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 3) & 0x7f) -#define __swp_offset(x) ((x).val >> 10) +#define __swp_type(x) (((x).val >> 4) & 0x3f) +#define __swp_offset(x) ((x).val >> 11) #define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 3) | ((offset) << 10) }) + ((swp_entry_t) { ((type) << 4) | ((offset) << 11) }) #define __pte_to_swp_entry(pte) \ ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 618a49030..b2a2bd404 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -11,33 +11,16 @@ struct pt_regs; struct task_struct; #include "linux/config.h" -#include "linux/signal.h" #include "asm/ptrace.h" -#include "asm/siginfo.h" #include "choose-mode.h" struct mm_struct; #define current_text_addr() ((void *) 0) -#define cpu_relax() do ; while (0) +#define cpu_relax() barrier() -#ifdef CONFIG_MODE_TT -struct proc_tt_mode { - int extern_pid; - int tracing; - int switch_pipe[2]; - int singlestep_syscall; - int vm_seq; -}; -#endif - -#ifdef CONFIG_MODE_SKAS -struct proc_skas_mode { - void *switch_buf; - void *fork_buf; -}; -#endif +#define STACK_PAGE_COUNT (4096/PAGE_SIZE) struct thread_struct { int forking; @@ -46,6 +29,7 @@ struct thread_struct { struct pt_regs regs; unsigned long cr2; int err; + unsigned long trap_no; void *fault_addr; void *fault_catcher; struct task_struct *prev_sched; @@ -54,10 +38,20 @@ struct thread_struct { struct arch_thread arch; union { #ifdef CONFIG_MODE_TT - struct proc_tt_mode tt; + struct { + int extern_pid; + int tracing; + int switch_pipe[2]; + int singlestep_syscall; + int vm_seq; + } tt; #endif #ifdef CONFIG_MODE_SKAS - struct proc_skas_mode skas; + struct { + void *switch_buf; + void *fork_buf; + int mm_count; + } skas; #endif } mode; struct { @@ -99,14 +93,19 @@ typedef struct { } mm_segment_t; extern struct task_struct *alloc_task_struct(void); -extern void free_task_struct(struct task_struct *task); extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void dump_thread(struct pt_regs *regs, struct user *u); +extern void prepare_to_copy(struct task_struct *tsk); extern unsigned long thread_saved_pc(struct task_struct *t); +static inline void mm_copy_segments(struct mm_struct *from_mm, + struct mm_struct *new_mm) +{ +} + #define init_stack (init_thread_union.stack) /* @@ -114,6 +113,7 @@ extern unsigned long thread_saved_pc(struct task_struct *t); */ extern unsigned long task_size; +#undef TASK_SIZE #define TASK_SIZE (task_size) /* This decides where the kernel will search for a free chunk of vm diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h index 02decdcc1..0f08c0225 100644 --- a/include/asm-um/processor-i386.h +++ b/include/asm-um/processor-i386.h @@ -6,8 +6,8 @@ #ifndef __UM_PROCESSOR_I386_H #define __UM_PROCESSOR_I386_H -extern int cpu_has_xmm; -extern int cpu_has_cmov; +extern int host_has_xmm; +extern int host_has_cmov; struct arch_thread { unsigned long debugregs[8]; diff --git a/include/asm-um/rmap.h b/include/asm-um/rmap.h deleted file mode 100644 index a244d486b..000000000 --- a/include/asm-um/rmap.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __UM_RMAP_H -#define __UM_RMAP_H - -#include "asm/arch/rmap.h" - -#endif diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h index 4629de866..20c6457f3 100644 --- a/include/asm-um/smp.h +++ b/include/asm-um/smp.h @@ -10,7 +10,7 @@ extern cpumask_t cpu_online_map; -#define smp_processor_id() (current->thread_info->cpu) +#define smp_processor_id() (current_thread->cpu) #define cpu_logical_map(n) (n) #define cpu_number_map(n) (n) #define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ diff --git a/include/asm-um/smplock.h b/include/asm-um/smplock.h deleted file mode 100644 index aacda39c5..000000000 --- a/include/asm-um/smplock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __UM_SMPLOCK_H -#define __UM_SMPLOCK_H - -#include "asm/arch/smplock.h" - -#endif diff --git a/include/asm-um/spinlock.h b/include/asm-um/spinlock.h deleted file mode 100644 index bd6c35d48..000000000 --- a/include/asm-um/spinlock.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __UM_SPINLOCK_H -#define __UM_SPINLOCK_H - -#include "linux/config.h" - -#ifdef CONFIG_SMP -#include "asm/arch/spinlock.h" -#endif - -#endif diff --git a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h index 80b24a31b..5bcfa35e7 100644 --- a/include/asm-um/system-generic.h +++ b/include/asm-um/system-generic.h @@ -23,8 +23,10 @@ extern int get_signals(void); extern void block_signals(void); extern void unblock_signals(void); -#define local_save_flags(flags) do { (flags) = get_signals(); } while(0) -#define local_irq_restore(flags) do { set_signals(flags); } while(0) +#define local_save_flags(flags) do { typecheck(unsigned long, flags); \ + (flags) = get_signals(); } while(0) +#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \ + set_signals(flags); } while(0) #define local_irq_save(flags) do { local_save_flags(flags); \ local_irq_disable(); } while(0) @@ -39,4 +41,7 @@ extern void unblock_signals(void); (flags == 0); \ }) +extern void *_switch_to(void *prev, void *next, void *last); +#define switch_to(prev, next, last) prev = _switch_to(prev, next, last) + #endif diff --git a/include/asm-um/system-i386.h b/include/asm-um/system-i386.h index 4d71ed390..c436263e6 100644 --- a/include/asm-um/system-i386.h +++ b/include/asm-um/system-i386.h @@ -2,36 +2,5 @@ #define __UM_SYSTEM_I386_H #include "asm/system-generic.h" - -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, - unsigned long new, int size) -{ - unsigned long prev; - switch (size) { - case 1: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 2: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 4: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - } - return old; -} - -#define cmpxchg(ptr,o,n)\ - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ - (unsigned long)(n),sizeof(*(ptr)))) #endif diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 6a606bf0b..bb1bc2d47 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -9,6 +9,7 @@ #ifndef __ASSEMBLY__ #include +#include struct thread_info { struct task_struct *task; /* main task structure */ @@ -43,15 +44,18 @@ struct thread_info { static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; - __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL)); + unsigned long mask = PAGE_SIZE * + (1 << CONFIG_KERNEL_STACK_ORDER) - 1; + __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask)); return ti; } /* thread information allocation */ -#define THREAD_SIZE (4*PAGE_SIZE) -#define alloc_thread_info(tsk) ((struct thread_info *) \ - __get_free_pages(GFP_KERNEL,2)) -#define free_thread_info(ti) free_pages((unsigned long) (ti), 2) +#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) +#define alloc_thread_info(tsk) \ + ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL)) +#define free_thread_info(ti) kfree(ti) + #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) @@ -65,11 +69,13 @@ static inline struct thread_info *current_thread_info(void) #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling * TIF_NEED_RESCHED */ +#define TIF_RESTART_BLOCK 4 #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_RESTART_BLOCK (1 << TIF_RESTART_BLOCK) #endif diff --git a/include/asm-um/timex.h b/include/asm-um/timex.h index 6a873133a..580581172 100644 --- a/include/asm-um/timex.h +++ b/include/asm-um/timex.h @@ -1,8 +1,6 @@ #ifndef __UM_TIMEX_H #define __UM_TIMEX_H -#include "linux/time.h" - typedef unsigned long cycles_t; #define cacheflush_time (0) diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index e1dfea108..02e918824 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -6,6 +6,8 @@ #ifndef __UM_UACCESS_H #define __UM_UACCESS_H +#include "linux/sched.h" + #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h index 5850620bb..d6aaacc0b 100644 --- a/include/asm-um/unistd.h +++ b/include/asm-um/unistd.h @@ -34,7 +34,6 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]); #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ @@ -48,7 +47,10 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]); set_fs(KERNEL_DS); \ ret = sys(args); \ set_fs(fs); \ - return ret; + if (ret >= 0) \ + return ret; \ + errno = -(long)ret; \ + return -1; static inline long open(const char *pathname, int flags, int mode) { diff --git a/include/asm-v850/relay.h b/include/asm-v850/relay.h new file mode 100644 index 000000000..869a53890 --- /dev/null +++ b/include/asm-v850/relay.h @@ -0,0 +1,5 @@ +#ifndef __V850_RELAY_H +#define __V850_RELAY_H + +#include +#endif diff --git a/include/asm-v850/resource.h b/include/asm-v850/resource.h index 6f59c85fe..0203d2e7a 100644 --- a/include/asm-v850/resource.h +++ b/include/asm-v850/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE, PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-v850/rmap.h b/include/asm-v850/rmap.h deleted file mode 100644 index c0ebee6f4..000000000 --- a/include/asm-v850/rmap.h +++ /dev/null @@ -1 +0,0 @@ -/* Do not need anything here */ diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index f8163e806..3a2b2a5d8 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h @@ -408,7 +408,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifdef __KERNEL_SYSCALLS__ diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h index c91f028db..ae42bca73 100644 --- a/include/asm-x86_64/bitops.h +++ b/include/asm-x86_64/bitops.h @@ -337,15 +337,16 @@ static __inline__ int find_first_bit(const unsigned long * addr, unsigned size) "repe; scasl\n\t" "jz 1f\n\t" "leaq -4(%%rdi),%%rdi\n\t" - "bsfl (%%rdi),%%eax\n" - "1:\tsubq %%rbx,%%rdi\n\t" + "bsfq (%%rdi),%%rax\n" + "1:\tsubl %%ebx,%%edi\n\t" "shll $3,%%edi\n\t" "addl %%edi,%%eax" :"=a" (res), "=&c" (d0), "=&D" (d1) - :"1" ((size + 31) >> 5), "2" (addr), "b" (addr) : "memory"); + :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); return res; } + /** * find_next_bit - find the first set bit in a memory region * @addr: The address to base the search on diff --git a/include/asm-x86_64/checksum.h b/include/asm-x86_64/checksum.h index abcabbce9..3718a8fbb 100644 --- a/include/asm-x86_64/checksum.h +++ b/include/asm-x86_64/checksum.h @@ -139,9 +139,9 @@ extern unsigned long csum_partial_copy_generic(const char *src, const char *dst, int *src_err_ptr, int *dst_err_ptr); -extern unsigned int csum_partial_copy_from_user(const char __user *src, char *dst, +extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int isum, int *errp); -extern unsigned int csum_partial_copy_to_user(const char *src, char __user *dst, +extern unsigned int csum_partial_copy_to_user(const char *src, char *dst, int len, unsigned int isum, int *errp); extern unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum); diff --git a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h index c1e04aa5a..c4f520987 100644 --- a/include/asm-x86_64/compat.h +++ b/include/asm-x86_64/compat.h @@ -186,15 +186,15 @@ struct compat_shmid64_ds { */ typedef u32 compat_uptr_t; -static inline void __user *compat_ptr(compat_uptr_t uptr) +static inline void *compat_ptr(compat_uptr_t uptr) { - return (void __user *)(unsigned long)uptr; + return (void *)(unsigned long)uptr; } -static __inline__ void __user *compat_alloc_user_space(long len) +static __inline__ void *compat_alloc_user_space(long len) { struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); - return (void __user *)regs->rsp - len; + return (void *)regs->rsp - len; } #endif /* _ASM_X86_64_COMPAT_H */ diff --git a/include/asm-x86_64/fcntl.h b/include/asm-x86_64/fcntl.h index aabf1a30a..dfc17bb6c 100644 --- a/include/asm-x86_64/fcntl.h +++ b/include/asm-x86_64/fcntl.h @@ -20,6 +20,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_ATOMICLOOKUP 01000000 /* TUX */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h index bca9b28a1..2f2df23b6 100644 --- a/include/asm-x86_64/floppy.h +++ b/include/asm-x86_64/floppy.h @@ -170,7 +170,7 @@ static unsigned long vdma_mem_alloc(unsigned long size) static void _fd_dma_mem_free(unsigned long addr, unsigned long size) { if((unsigned long) addr >= (unsigned long) high_memory) - vfree((void *)addr); + return vfree((void *)addr); else free_pages(addr, get_order(size)); } diff --git a/include/asm-x86_64/fpu32.h b/include/asm-x86_64/fpu32.h index 4153db5c0..244ffe2a0 100644 --- a/include/asm-x86_64/fpu32.h +++ b/include/asm-x86_64/fpu32.h @@ -3,8 +3,8 @@ struct _fpstate_ia32; -int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, int fsave); -int save_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, +int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave); +int save_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, struct pt_regs *regs, int fsave); #endif diff --git a/include/asm-x86_64/i387.h b/include/asm-x86_64/i387.h index 10638b850..bb5edc3cd 100644 --- a/include/asm-x86_64/i387.h +++ b/include/asm-x86_64/i387.h @@ -23,7 +23,7 @@ extern void fpu_init(void); extern unsigned int mxcsr_feature_mask; extern void mxcsr_feature_mask_init(void); extern void init_fpu(struct task_struct *child); -extern int save_i387(struct _fpstate __user *buf); +extern int save_i387(struct _fpstate *buf); static inline int need_signal_i387(struct task_struct *me) { @@ -48,7 +48,7 @@ static inline int need_signal_i387(struct task_struct *me) #define clear_fpu(tsk) do { \ if ((tsk)->thread_info->status & TS_USEDFPU) { \ - asm volatile("fnclex ; fwait"); \ + asm volatile("fwait"); \ (tsk)->thread_info->status &= ~TS_USEDFPU; \ stts(); \ } \ @@ -57,10 +57,10 @@ static inline int need_signal_i387(struct task_struct *me) /* * ptrace request handers... */ -extern int get_fpregs(struct user_i387_struct __user *buf, +extern int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk); extern int set_fpregs(struct task_struct *tsk, - struct user_i387_struct __user *buf); + struct user_i387_struct *buf); /* * i387 state interaction @@ -93,7 +93,7 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) return err; } -static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) +static inline int save_i387_checking(struct i387_fxsave_struct *fx) { int err; asm volatile("1: rex64 ; fxsave (%[fx])\n\t" @@ -136,7 +136,7 @@ static inline void save_init_fpu( struct task_struct *tsk ) /* * This restores directly out of user space. Exceptions are handled. */ -static inline int restore_i387(struct _fpstate __user *buf) +static inline int restore_i387(struct _fpstate *buf) { return restore_fpu_checking((struct i387_fxsave_struct *)buf); } diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h index a680d0356..b29899e3c 100644 --- a/include/asm-x86_64/ia32.h +++ b/include/asm-x86_64/ia32.h @@ -168,8 +168,8 @@ struct ustat32 { #ifdef __KERNEL__ struct user_desc; struct siginfo_t; -int do_get_thread_area(struct thread_struct *t, struct user_desc __user *info); -int do_set_thread_area(struct thread_struct *t, struct user_desc __user *info); +int do_get_thread_area(struct thread_struct *t, struct user_desc *u_info); +int do_set_thread_area(struct thread_struct *t, struct user_desc *u_info); int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs); int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from); int ia32_copy_siginfo_to_user(siginfo_t32 __user *to, siginfo_t *from); diff --git a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86_64/ia32_unistd.h index ff0309c2e..5facf5648 100644 --- a/include/asm-x86_64/ia32_unistd.h +++ b/include/asm-x86_64/ia32_unistd.h @@ -288,8 +288,7 @@ #define __NR_ia32_mq_timedreceive (__NR_ia32_mq_open+3) #define __NR_ia32_mq_notify (__NR_ia32_mq_open+4) #define __NR_ia32_mq_getsetattr (__NR_ia32_mq_open+5) -#define __NR_ia32_kexec 283 -#define IA32_NR_syscalls 287 /* must be > than biggest syscall! */ +#define IA32_NR_syscalls 285 /* must be > than biggest syscall! */ #endif /* _ASM_X86_64_IA32_UNISTD_H_ */ diff --git a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h index 4cef0ef61..99e18549c 100644 --- a/include/asm-x86_64/ide.h +++ b/include/asm-x86_64/ide.h @@ -1 +1,67 @@ -#include +/* + * linux/include/asm-x86_64/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +/* + * This file contains the x86_64 architecture specific IDE code. + */ + +#ifndef __ASMx86_64_IDE_H +#define __ASMx86_64_IDE_H + +#ifdef __KERNEL__ + +#include + +#ifndef MAX_HWIFS +# ifdef CONFIG_BLK_DEV_IDEPCI +#define MAX_HWIFS 10 +# else +#define MAX_HWIFS 6 +# endif +#endif + +static __inline__ int ide_default_irq(unsigned long base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + case 0x168: return 10; + case 0x1e0: return 8; + case 0x160: return 12; + default: + return 0; + } +} + +static __inline__ unsigned long ide_default_io_base(int index) +{ + switch (index) { + case 0: return 0x1f0; + case 1: return 0x170; + case 2: return 0x1e8; + case 3: return 0x168; + case 4: return 0x1e0; + case 5: return 0x160; + default: + return 0; + } +} + +#define IDE_ARCH_OBSOLETE_INIT +#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */ + +#ifdef CONFIG_BLK_DEV_IDEPCI +#define ide_init_default_irq(base) (0) +#else +#define ide_init_default_irq(base) ide_default_irq(base) +#endif + +#include + +#endif /* __KERNEL__ */ + +#endif /* __ASMx86_64_IDE_H */ diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index 1ddce4b4a..b0ce61de4 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -195,13 +195,8 @@ extern void iounmap(void *addr); #define __raw_writel writel #define __raw_writeq writeq -void *__memcpy_fromio(void*,unsigned long,unsigned); -void *__memcpy_toio(unsigned long,const void*,unsigned); - -#define memcpy_fromio(to,from,len) \ - __memcpy_fromio((to),(unsigned long)(from),(len)) -#define memcpy_toio(to,from,len) \ - __memcpy_toio((unsigned long)(to),(from),(len)) +void *memcpy_fromio(void*,const void*,unsigned); +void *memcpy_toio(void*,const void*,unsigned); #define memset_io(a,b,c) memset((void *)(a),(b),(c)) /* diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index c5c2b01cf..8f0b0f3d8 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h @@ -65,20 +65,15 @@ extern unsigned long vm_stack_flags, vm_stack_flags32; extern unsigned long vm_data_default_flags, vm_data_default_flags32; extern unsigned long vm_force_exec32; -#define __START_KERNEL 0xffffffff80100000UL -#define __START_KERNEL_map 0xffffffff80000000UL -#define __PAGE_OFFSET 0x0000010000000000UL /* 1 << 40 */ - -#else -#define __START_KERNEL 0xffffffff80100000 -#define __START_KERNEL_map 0xffffffff80000000 -#define __PAGE_OFFSET 0x0000010000000000 /* 1 << 40 */ #endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) /* See Documentation/x86_64/mm.txt for a description of the memory map. */ +#define __START_KERNEL 0xffffffff80100000 +#define __START_KERNEL_map 0xffffffff80000000 +#define __PAGE_OFFSET 0x0000010000000000 /* 1 << 40 */ #define __PHYSICAL_MASK_SHIFT 40 #define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) #define __VIRTUAL_MASK_SHIFT 48 diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h index bebcaab33..d496958a9 100644 --- a/include/asm-x86_64/pgalloc.h +++ b/include/asm-x86_64/pgalloc.h @@ -7,6 +7,11 @@ #include #include +#define arch_add_exec_range(mm, limit) do { ; } while (0) +#define arch_flush_exec_range(mm) do { ; } while (0) +#define arch_remove_exec_range(mm, limit) do { ; } while (0) + + #define pmd_populate_kernel(mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))) #define pgd_populate(mm, pgd, pmd) \ diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 37ebbad00..5555b9cf6 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -124,13 +124,13 @@ static inline void set_pml4(pml4_t *dst, pml4_t val) #ifndef __ASSEMBLY__ -#define VMALLOC_START 0xffffff0000000000UL -#define VMALLOC_END 0xffffff7fffffffffUL -#define MODULES_VADDR 0xffffffffa0000000UL -#define MODULES_END 0xffffffffafffffffUL +#define VMALLOC_START 0xffffff0000000000 +#define VMALLOC_END 0xffffff7fffffffff +#define MODULES_VADDR 0xffffffffa0000000 +#define MODULES_END 0xffffffffafffffff #define MODULES_LEN (MODULES_END - MODULES_VADDR) -#define IOMAP_START 0xfffffe8000000000UL +#define IOMAP_START 0xfffffe8000000000 #define _PAGE_BIT_PRESENT 0 #define _PAGE_BIT_RW 1 @@ -172,7 +172,7 @@ static inline void set_pml4(pml4_t *dst, pml4_t val) #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define __PAGE_KERNEL \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) -#define __PAGE_KERNEL_EXECUTABLE \ +#define __PAGE_KERNEL_EXEC \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) #define __PAGE_KERNEL_NOCACHE \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX) @@ -188,7 +188,7 @@ static inline void set_pml4(pml4_t *dst, pml4_t val) #define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL) #define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL) -#define PAGE_KERNEL_EXECUTABLE MAKE_GLOBAL(__PAGE_KERNEL_EXECUTABLE) +#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC) #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO) #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE) #define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL) @@ -383,20 +383,6 @@ extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define update_mmu_cache(vma,address,pte) do { } while (0) -/* We only update the dirty/accessed state if we set - * the dirty bit by hand in the kernel, since the hardware - * will do the accessed bit for us, and we don't want to - * race with other CPU's that might be updating the dirty - * bit at the same time. */ -#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS -#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ - do { \ - if (__dirty) { \ - set_pte(__ptep, __entry); \ - flush_tlb_page(__vma, __address); \ - } \ - } while (0) - /* Encode and de-code a swap entry */ #define __swp_type(x) (((x).val >> 1) & 0x3f) #define __swp_offset(x) ((x).val >> 8) diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index ec696b271..7a253a830 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -166,7 +166,7 @@ static inline void clear_in_cr4 (unsigned long mask) /* * User space process size: 512GB - 1GB (default). */ -#define TASK_SIZE (0x0000007fc0000000UL) +#define TASK_SIZE (0x0000007fc0000000) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h index cbc19a778..3c5c3a4fc 100644 --- a/include/asm-x86_64/ptrace.h +++ b/include/asm-x86_64/ptrace.h @@ -83,7 +83,7 @@ struct pt_regs { #if defined(__KERNEL__) && !defined(__ASSEMBLY__) #define user_mode(regs) (!!((regs)->cs & 3)) #define instruction_pointer(regs) ((regs)->rip) -void signal_fault(struct pt_regs *regs, void __user *frame, char *where); +void signal_fault(struct pt_regs *regs, void *frame, char *where); enum { EF_CF = 0x00000001, diff --git a/include/asm-x86_64/relay.h b/include/asm-x86_64/relay.h new file mode 100644 index 000000000..d8b1b8859 --- /dev/null +++ b/include/asm-x86_64/relay.h @@ -0,0 +1,5 @@ +#ifndef _ASM_X86_64_RELAY_H +#define _ASM_X86_64_RELAY_H + +#include +#endif diff --git a/include/asm-x86_64/resource.h b/include/asm-x86_64/resource.h index b430c854b..f88aee8af 100644 --- a/include/asm-x86_64/resource.h +++ b/include/asm-x86_64/resource.h @@ -37,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { PAGE_SIZE , PAGE_SIZE }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/asm-x86_64/rmap.h b/include/asm-x86_64/rmap.h deleted file mode 100644 index 24c1783ed..000000000 --- a/include/asm-x86_64/rmap.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _X8664_RMAP_H -#define _X8664_RMAP_H - -/* nothing to see, move along */ -#include - -#endif diff --git a/include/asm-x86_64/semaphore.h b/include/asm-x86_64/semaphore.h index 278883422..5fe25482f 100644 --- a/include/asm-x86_64/semaphore.h +++ b/include/asm-x86_64/semaphore.h @@ -47,12 +47,12 @@ struct semaphore { atomic_t count; int sleepers; wait_queue_head_t wait; -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG long __magic; #endif }; -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG # define __SEM_DEBUG_INIT(name) \ , (int)&(name).__magic #else @@ -83,7 +83,7 @@ static inline void sema_init (struct semaphore *sem, int val) atomic_set(&sem->count, val); sem->sleepers = 0; init_waitqueue_head(&sem->wait); -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG sem->__magic = (int)&sem->__magic; #endif } @@ -115,7 +115,7 @@ asmlinkage void __up(struct semaphore * sem); */ static inline void down(struct semaphore * sem) { -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif might_sleep(); @@ -142,7 +142,7 @@ static inline int down_interruptible(struct semaphore * sem) { int result; -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif might_sleep(); @@ -171,7 +171,7 @@ static inline int down_trylock(struct semaphore * sem) { int result; -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif @@ -199,7 +199,7 @@ static inline int down_trylock(struct semaphore * sem) */ static inline void up(struct semaphore * sem) { -#ifdef WAITQUEUE_DEBUG +#if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif __asm__ __volatile__( diff --git a/include/asm-x86_64/sigcontext.h b/include/asm-x86_64/sigcontext.h index b4e402366..6a624087d 100644 --- a/include/asm-x86_64/sigcontext.h +++ b/include/asm-x86_64/sigcontext.h @@ -2,7 +2,6 @@ #define _ASM_X86_64_SIGCONTEXT_H #include -#include /* FXSAVE frame */ /* Note: reserved1/2 may someday contain valuable data. Always save/restore @@ -48,7 +47,7 @@ struct sigcontext { unsigned long trapno; unsigned long oldmask; unsigned long cr2; - struct _fpstate __user *fpstate; /* zero when no FPU context */ + struct _fpstate *fpstate; /* zero when no FPU context */ unsigned long reserved1[8]; }; diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h index 779c74260..9b4c018aa 100644 --- a/include/asm-x86_64/uaccess.h +++ b/include/asm-x86_64/uaccess.h @@ -24,7 +24,7 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFFFFFFFFFUL) +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFFFFFFFFF) #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) #define get_ds() (KERNEL_DS) @@ -33,16 +33,6 @@ #define segment_eq(a,b) ((a).seg == (b).seg) -#ifdef __CHECKER__ -#define CHECK_UPTR(ptr) do { \ - __typeof__(*(ptr)) *__dummy_check_uptr = \ - (void __user *)&__dummy_check_uptr; \ -} while(0) -#else -#define CHECK_UPTR(ptr) -#endif - - #define __addr_ok(addr) (!((unsigned long)(addr) & (current_thread_info()->addr_limit.seg))) /* @@ -50,16 +40,15 @@ */ #define __range_not_ok(addr,size) ({ \ unsigned long flag,sum; \ - CHECK_UPTR(addr); \ asm("# range_ok\n\r" \ "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \ :"=&r" (flag), "=r" (sum) \ :"1" (addr),"g" ((long)(size)),"g" (current_thread_info()->addr_limit.seg)); \ flag; }) -#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0) +#define access_ok(type,addr,size) (__range_not_ok(addr,size) == 0) -extern inline int verify_area(int type, const void __user * addr, unsigned long size) +extern inline int verify_area(int type, const void * addr, unsigned long size) { return access_ok(type,addr,size) ? 0 : -EFAULT; } @@ -114,7 +103,6 @@ extern void __get_user_8(void); #define get_user(x,ptr) \ ({ long __val_gu; \ int __ret_gu; \ - CHECK_UPTR(ptr); \ switch(sizeof (*(ptr))) { \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ @@ -150,7 +138,6 @@ extern void __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ ({ \ int __pu_err; \ - CHECK_UPTR(ptr); \ __put_user_size((x),(ptr),(size),__pu_err); \ __pu_err; \ }) @@ -206,7 +193,6 @@ struct __large_struct { unsigned long buf[100]; }; ({ \ int __gu_err; \ long __gu_val; \ - CHECK_UPTR(ptr); \ __get_user_size(__gu_val,(ptr),(size),__gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ @@ -249,15 +235,15 @@ do { \ /* Handles exceptions in both to and from, but doesn't do access_ok */ extern unsigned long copy_user_generic(void *to, const void *from, unsigned len); -extern unsigned long copy_to_user(void __user *to, const void *from, unsigned len); -extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len); -extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len); +extern unsigned long copy_to_user(void *to, const void *from, unsigned len); +extern unsigned long copy_from_user(void *to, const void *from, unsigned len); +extern unsigned long copy_in_user(void *to, const void *from, unsigned len); -static inline int __copy_from_user(void *dst, const void __user *src, unsigned size) +static inline int __copy_from_user(void *dst, const void *src, unsigned size) { int ret = 0; if (!__builtin_constant_p(size)) - return copy_user_generic(dst,(void *)src,size); + return copy_user_generic(dst,src,size); switch (size) { case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1); return ret; @@ -278,15 +264,15 @@ static inline int __copy_from_user(void *dst, const void __user *src, unsigned s __get_user_asm(*(u64*)(8+(char*)dst),(u64*)(8+(char*)src),ret,"q","","=r",8); return ret; default: - return copy_user_generic(dst,(void *)src,size); + return copy_user_generic(dst,src,size); } } -static inline int __copy_to_user(void __user *dst, const void *src, unsigned size) +static inline int __copy_to_user(void *dst, const void *src, unsigned size) { int ret = 0; if (!__builtin_constant_p(size)) - return copy_user_generic((void *)dst,src,size); + return copy_user_generic(dst,src,size); switch (size) { case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1); return ret; @@ -309,16 +295,16 @@ static inline int __copy_to_user(void __user *dst, const void *src, unsigned siz __put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8); return ret; default: - return copy_user_generic((void *)dst,src,size); + return copy_user_generic(dst,src,size); } } -static inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size) +static inline int __copy_in_user(void *dst, const void *src, unsigned size) { int ret = 0; if (!__builtin_constant_p(size)) - return copy_user_generic((void *)dst,(void *)src,size); + return copy_user_generic(dst,src,size); switch (size) { case 1: { u8 tmp; @@ -350,15 +336,15 @@ static inline int __copy_in_user(void __user *dst, const void __user *src, unsig return ret; } default: - return copy_user_generic((void *)dst,(void *)src,size); + return copy_user_generic(dst,src,size); } } -long strncpy_from_user(char *dst, const char __user *src, long count); -long __strncpy_from_user(char *dst, const char __user *src, long count); -long strnlen_user(const char __user *str, long n); -long strlen_user(const char __user *str); -unsigned long clear_user(void __user *mem, unsigned long len); -unsigned long __clear_user(void __user *mem, unsigned long len); +long strncpy_from_user(char *dst, const char *src, long count); +long __strncpy_from_user(char *dst, const char *src, long count); +long strnlen_user(const char *str, long n); +long strlen_user(const char *str); +unsigned long clear_user(void *mem, unsigned long len); +unsigned long __clear_user(void *mem, unsigned long len); #endif /* __X86_64_UACCESS_H */ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 26e0aa30b..2ea0cb424 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -591,7 +591,6 @@ do { \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION #endif #ifndef __KERNEL_SYSCALLS__ diff --git a/include/linux/aio.h b/include/linux/aio.h index 93fe78800..b03ebead2 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -59,10 +59,7 @@ struct kiocb { struct list_head ki_list; /* the aio core uses this * for cancellation */ - union { - void __user *user; - struct task_struct *tsk; - } ki_obj; + void __user *ki_user_obj; /* pointer to userland's iocb */ __u64 ki_user_data; /* user's data for completion */ loff_t ki_pos; @@ -79,7 +76,7 @@ struct kiocb { (x)->ki_filp = (filp); \ (x)->ki_ctx = &tsk->active_mm->default_kioctx; \ (x)->ki_cancel = NULL; \ - (x)->ki_obj.tsk = tsk; \ + (x)->ki_user_obj = tsk; \ } while (0) #define AIO_RING_MAGIC 0xa10a10a1 @@ -152,11 +149,11 @@ struct mm_struct; extern void FASTCALL(exit_aio(struct mm_struct *mm)); extern struct kioctx *lookup_ioctx(unsigned long ctx_id); extern int FASTCALL(io_submit_one(struct kioctx *ctx, - struct iocb __user *user_iocb, struct iocb *iocb)); + struct iocb *user_iocb, struct iocb *iocb)); /* semi private, but used by the 32bit emulations: */ struct kioctx *lookup_ioctx(unsigned long ctx_id); -int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, +int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb *user_iocb, struct iocb *iocb)); #define get_ioctx(kioctx) do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0) diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 6d70bd539..0db065c43 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -194,6 +194,7 @@ int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, int generic_cont_expand(struct inode *inode, loff_t size) ; int block_commit_write(struct page *page, unsigned from, unsigned to); int block_sync_page(struct page *); +void flush_inode_pages (struct inode * inode); sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); int generic_commit_write(struct file *, struct page *, unsigned, unsigned); int block_truncate_page(struct address_space *, loff_t, get_block_t *); diff --git a/include/linux/capability.h b/include/linux/capability.h index c96e7b624..7798d2c26 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -235,6 +235,7 @@ typedef __u32 kernel_cap_t; /* Allow enabling/disabling tagged queuing on SCSI controllers and sending arbitrary SCSI commands */ /* Allow setting encryption key on loopback filesystem */ +/* Allow the selection of a security context */ #define CAP_SYS_ADMIN 21 @@ -284,6 +285,11 @@ typedef __u32 kernel_cap_t; #define CAP_LEASE 28 +/* Allow context manipulations */ +/* Allow changing context info on files */ + +#define CAP_CONTEXT 29 + #ifdef __KERNEL__ /* * Bounding set diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 282e9b793..a1727a02c 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -237,9 +237,9 @@ struct cdrom_read struct cdrom_read_audio { union cdrom_addr addr; /* frame address */ - __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ + __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ int nframes; /* number of 2352-byte-frames to read at once */ - __u8 __user *buf; /* frame buffer (size: nframes*2352 bytes) */ + __u8 *buf; /* frame buffer (size: nframes*2352 bytes) */ }; /* This struct is used with the CDROMMULTISESSION ioctl */ diff --git a/include/linux/ckrm.h b/include/linux/ckrm.h new file mode 100644 index 000000000..4ac2c1894 --- /dev/null +++ b/include/linux/ckrm.h @@ -0,0 +1,162 @@ +/* ckrm.h - Class-based Kernel Resource Management (CKRM) + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003,2004 + * (C) Shailabh Nagar, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * + * + * Provides a base header file including macros and basic data structures. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 28 Aug 2003 + * Created. + * 06 Nov 2003 + * Made modifications to suit the new RBCE module. + * 10 Nov 2003 + * Added callbacks_active and surrounding logic. Added task paramter + * for all CE callbacks. + * 19 Nov 2004 + * New Event callback structure + */ + +#ifndef _LINUX_CKRM_H +#define _LINUX_CKRM_H + +#ifdef CONFIG_CKRM + +// Data structure and function to get the list of registered +// resource controllers. + +// #include + +/* CKRM defines a set of events at particular points in the kernel + * at which callbacks registered by various class types are called + */ + +enum ckrm_event { + /* we distinguish various events types + * + * (a) CKRM_LATCHABLE_EVENTS + * events can be latched for event callbacks by classtypes + * + * (b) CKRM_NONLATACHBLE_EVENTS + * events can not be latched but can be used to call classification + * + * (c) event that are used for notification purposes + * range: [ CKRM_EVENT_CANNOT_CLASSIFY .. ) + */ + + /* events (a) */ + + CKRM_LATCHABLE_EVENTS, + + CKRM_EVENT_NEWTASK = CKRM_LATCHABLE_EVENTS, + CKRM_EVENT_FORK, + CKRM_EVENT_EXIT, + CKRM_EVENT_EXEC, + CKRM_EVENT_UID, + CKRM_EVENT_GID, + CKRM_EVENT_LOGIN, + CKRM_EVENT_USERADD, + CKRM_EVENT_USERDEL, + CKRM_EVENT_LISTEN_START, + CKRM_EVENT_LISTEN_STOP, + CKRM_EVENT_APPTAG, + + /* events (b) */ + + CKRM_NONLATCHABLE_EVENTS, + + CKRM_EVENT_RECLASSIFY = CKRM_NONLATCHABLE_EVENTS, + + /* events (c) */ + CKRM_NOTCLASSIFY_EVENTS, + + CKRM_EVENT_MANUAL = CKRM_NOTCLASSIFY_EVENTS, + + CKRM_NUM_EVENTS +}; +#endif + +#ifdef __KERNEL__ +#ifdef CONFIG_CKRM + +extern void ckrm_invoke_event_cb_chain(enum ckrm_event ev, void *arg); + +typedef void (*ckrm_event_cb)(void *arg); + +struct ckrm_hook_cb { + ckrm_event_cb fct; + struct ckrm_hook_cb *next; +}; + +#define CKRM_DEF_CB(EV,fct) \ +static inline void ckrm_cb_##fct(void) \ +{ \ + ckrm_invoke_event_cb_chain(CKRM_EVENT_##EV,NULL); \ +} + +#define CKRM_DEF_CB_ARG(EV,fct,argtp) \ +static inline void ckrm_cb_##fct(argtp arg) \ +{ \ + ckrm_invoke_event_cb_chain(CKRM_EVENT_##EV,(void*)arg); \ +} + +#else // !CONFIG_CKRM + +#define CKRM_DEF_CB(EV,fct) \ +static inline void ckrm_cb_##fct(void) { } + +#define CKRM_DEF_CB_ARG(EV,fct,argtp) \ +static inline void ckrm_cb_##fct(argtp arg) { } + +#define ckrm_cb_newtask(task_struct) +#define ckrm_cb_exit(task_struct) +#define ckrm_init() + +#endif // CONFIG_CKRM + +/*----------------------------------------------------------------- + * define the CKRM event functions + * EVENT FCT ARG + *-----------------------------------------------------------------*/ + +// types we refer at +struct task_struct; +struct sock; +struct user_struct; + +CKRM_DEF_CB_ARG( FORK , fork, struct task_struct *); +CKRM_DEF_CB_ARG( EXEC , exec, const char* ); +CKRM_DEF_CB ( UID , uid ); +CKRM_DEF_CB ( GID , gid ); +CKRM_DEF_CB ( APPTAG , apptag ); +CKRM_DEF_CB ( LOGIN , login ); +CKRM_DEF_CB_ARG( USERADD , useradd, struct user_struct *); +CKRM_DEF_CB_ARG( USERDEL , userdel, struct user_struct *); +CKRM_DEF_CB_ARG( LISTEN_START , listen_start, struct sock * ); +CKRM_DEF_CB_ARG( LISTEN_STOP , listen_stop, struct sock * ); + +#ifdef CONFIG_CKRM +// and a few special one's +void ckrm_cb_newtask(struct task_struct *); +void ckrm_cb_exit(struct task_struct *); + +// some other functions required +extern void ckrm_init(void); +extern int get_exe_path_name(struct task_struct *, char *, int); +#endif // CONFIG_CKRM + +#endif // __KERNEL__ + +#endif // _LINUX_CKRM_H diff --git a/include/linux/ckrm_ce.h b/include/linux/ckrm_ce.h new file mode 100644 index 000000000..0bde15dd3 --- /dev/null +++ b/include/linux/ckrm_ce.h @@ -0,0 +1,91 @@ +/* ckrm_ce.h - Header file to be used by Classification Engine of CKRM + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003 + * (C) Shailabh Nagar, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * + * Provides data structures, macros and kernel API of CKRM for + * classification engine. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 12 Nov 2003 + * Created. + * 22 Apr 2004 + * Adopted to classtypes + */ + +#ifndef _LINUX_CKRM_CE_H +#define _LINUX_CKRM_CE_H + +#ifdef CONFIG_CKRM + +#include "ckrm.h" // getting the event names + +/* Action parameters identifying the cause of a task<->class notify callback + * these can perculate up to user daemon consuming records send by the classification + * engine + */ + +#ifdef __KERNEL__ + +typedef void* (*ce_classify_fct_t)(enum ckrm_event event, void *obj, ... ); +typedef void (*ce_notify_fct_t) (enum ckrm_event event, void *classobj, void *obj); + +typedef struct ckrm_eng_callback { + /* general state information */ + int always_callback; /* set if CE should always be called back regardless of numclasses */ + + /* callbacks which are called without holding locks */ + + unsigned long c_interest; /* set of classification events CE is interested in */ + ce_classify_fct_t classify; /* generic classify */ + + void (*class_add) (const char *name, void *core); /* class added */ + void (*class_delete)(const char *name, void *core); /* class deleted */ + + /* callback which are called while holding task_lock(tsk) */ + unsigned long n_interest; /* set of notification events CE is interested in */ + ce_notify_fct_t notify; /* notify on class switch */ + +} ckrm_eng_callback_t; + +struct inode; +struct dentry; + +typedef struct rbce_eng_callback { + int (*mkdir)(struct inode *, struct dentry *, int); // mkdir + int (*rmdir)(struct inode *, struct dentry *); // rmdir +} rbce_eng_callback_t; + +extern int ckrm_register_engine (const char *name, ckrm_eng_callback_t *); +extern int ckrm_unregister_engine(const char *name); + +extern void *ckrm_classobj(char *, int *classtype); +extern int get_exe_path_name(struct task_struct *t, char *filename, int max_size); + +extern int rcfs_register_engine(rbce_eng_callback_t *); +extern int rcfs_unregister_engine(rbce_eng_callback_t *); + +extern int ckrm_reclassify(int pid); + +#ifndef _LINUX_CKRM_RC_H +// ckrm kernel has inlined functions for this which are exported +extern void ckrm_core_grab(void *); +extern void ckrm_core_drop(void *); +#endif + +#endif // CONFIG_CKRM + +#endif // __KERNEL__ + +#endif // _LINUX_CKRM_CE_H diff --git a/include/linux/ckrm_net.h b/include/linux/ckrm_net.h new file mode 100644 index 000000000..0cbf784bb --- /dev/null +++ b/include/linux/ckrm_net.h @@ -0,0 +1,41 @@ +/* ckrm_rc.h - Header file to be used by Resource controllers of CKRM + * + * Copyright (C) Vivek Kashyap , IBM Corp. 2004 + * + * Provides data structures, macros and kernel API of CKRM for + * resource controllers. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef _LINUX_CKRM_NET_H +#define _LINUX_CKRM_NET_H + +struct ckrm_sock_class; + +struct ckrm_net_struct { + int ns_type; // type of net class + struct sock *ns_sk; // pointer to socket + pid_t ns_tgid; // real process id + pid_t ns_pid; // calling thread's pid + int ns_family; // IPPROTO_IPV4 || IPPROTO_IPV6 + // Currently only IPV4 is supported + union { + __u32 ns_dipv4; // V4 listener's address + } ns_daddr; + __u16 ns_dport; // listener's port + __u16 ns_sport; // sender's port + atomic_t ns_refcnt; + struct ckrm_sock_class *core; + struct list_head ckrm_link; +}; + +#define ns_daddrv4 ns_daddr.ns_dipv4 + +#endif diff --git a/include/linux/ckrm_rc.h b/include/linux/ckrm_rc.h new file mode 100644 index 000000000..e514f1c72 --- /dev/null +++ b/include/linux/ckrm_rc.h @@ -0,0 +1,367 @@ +/* ckrm_rc.h - Header file to be used by Resource controllers of CKRM + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003 + * (C) Shailabh Nagar, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Vivek Kashyap , IBM Corp. 2004 + * + * Provides data structures, macros and kernel API of CKRM for + * resource controllers. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 12 Nov 2003 + * Created. + */ + +#ifndef _LINUX_CKRM_RC_H +#define _LINUX_CKRM_RC_H + +#ifdef __KERNEL__ + +#ifdef CONFIG_CKRM + +#include +#include +#include +#include + + +/* maximum number of class types */ +#define CKRM_MAX_CLASSTYPES 32 +/* maximum classtype name length */ +#define CKRM_MAX_CLASSTYPE_NAME 32 + +/* maximum resource controllers per classtype */ +#define CKRM_MAX_RES_CTLRS 8 +/* maximum resource controller name length */ +#define CKRM_MAX_RES_NAME 128 + + +struct ckrm_core_class; +struct ckrm_classtype; + +/******************************************************************************** + * Share specifications + *******************************************************************************/ + +typedef struct ckrm_shares { + int my_guarantee; + int my_limit; + int total_guarantee; + int max_limit; + int unused_guarantee; // not used as parameters + int cur_max_limit; // not used as parameters +} ckrm_shares_t; + +#define CKRM_SHARE_UNCHANGED (-1) // value to indicate no change +#define CKRM_SHARE_DONTCARE (-2) // value to indicate don't care. +#define CKRM_SHARE_DFLT_TOTAL_GUARANTEE (100) // Start off with these values +#define CKRM_SHARE_DFLT_MAX_LIMIT (100) // to simplify set_res_shares logic + + +/******************************************************************************** + * RESOURCE CONTROLLERS + *******************************************************************************/ + +/* resource controller callback structure */ + +typedef struct ckrm_res_ctlr { + char res_name[CKRM_MAX_RES_NAME]; + int res_hdepth; // maximum hierarchy + int resid; // (for now) same as the enum resid + struct ckrm_classtype *classtype; // classtype owning this resource controller + + /* allocate/free new resource class object for resource controller */ + void *(*res_alloc) (struct ckrm_core_class *this, struct ckrm_core_class *parent); + void (*res_free) (void *); + + /* set/get limits/guarantees for a resource controller class */ + int (*set_share_values) (void* , struct ckrm_shares *shares); + int (*get_share_values) (void* , struct ckrm_shares *shares); + + /* statistics and configuration access */ + int (*get_stats) (void* , struct seq_file *); + int (*reset_stats) (void *); + int (*show_config) (void* , struct seq_file *); + int (*set_config) (void* , const char *cfgstr); + + void (*change_resclass)(void *, void *, void *); + +} ckrm_res_ctlr_t; + +/*************************************************************************************** + * CKRM_CLASSTYPE + * + * A object describes a dimension for CKRM to classify + * along. I needs to provide methods to create and manipulate class objects in + * this dimension + ***************************************************************************************/ + +/* list of predefined class types, we always recognize */ +#define CKRM_CLASSTYPE_TASK_CLASS 0 +#define CKRM_CLASSTYPE_SOCKET_CLASS 1 +#define CKRM_RESV_CLASSTYPES 2 /* always +1 of last known type */ + +#define CKRM_MAX_TYPENAME_LEN 32 + + +typedef struct ckrm_classtype { + /* Hubertus: Rearrange slots so that they are more cache friendly during access */ + + /* resource controllers */ + spinlock_t res_ctlrs_lock; /* protect data below (other than atomics) */ + int max_res_ctlrs; /* maximum number of resource controller allowed */ + int max_resid; /* maximum resid used */ + int resid_reserved; /* maximum number of reserved controllers */ + long bit_res_ctlrs; /* bitmap of resource ID used */ + atomic_t nr_resusers[CKRM_MAX_RES_CTLRS]; + ckrm_res_ctlr_t* res_ctlrs[CKRM_MAX_RES_CTLRS]; + + /* state about my classes */ + + struct ckrm_core_class *default_class; // pointer to default class + struct list_head classes; // listhead to link up all classes of this classtype + int num_classes; // how many classes do exist + + /* state about my ce interaction */ + int ce_regd; // Has a CE been registered for this classtype + int ce_cb_active; // are callbacks active + atomic_t ce_nr_users; // how many transient calls active + struct ckrm_eng_callback ce_callbacks; // callback engine + + // Begin classtype-rcfs private data. No rcfs/fs specific types used. + int mfidx; // Index into genmfdesc array used to initialize + // mfdesc and mfcount + void *mfdesc; // Array of descriptors of root and magic files + int mfcount; // length of above array + void *rootde; // root dentry created by rcfs + // End rcfs private data + + char name[CKRM_MAX_TYPENAME_LEN]; // currently same as mfdesc[0]->name but could be different + int typeID; /* unique TypeID */ + int maxdepth; /* maximum depth supported */ + + /* functions to be called on any class type by external API's */ + struct ckrm_core_class* (*alloc)(struct ckrm_core_class *parent, const char *name); /* alloc class instance */ + int (*free) (struct ckrm_core_class *cls); /* free class instance */ + + int (*show_members)(struct ckrm_core_class *, struct seq_file *); + int (*show_stats) (struct ckrm_core_class *, struct seq_file *); + int (*show_config) (struct ckrm_core_class *, struct seq_file *); + int (*show_shares) (struct ckrm_core_class *, struct seq_file *); + + int (*reset_stats) (struct ckrm_core_class *, const char *resname, + const char *); + int (*set_config) (struct ckrm_core_class *, const char *resname, + const char *cfgstr); + int (*set_shares) (struct ckrm_core_class *, const char *resname, + struct ckrm_shares *shares); + int (*forced_reclassify)(struct ckrm_core_class *, const char *); + + + /* functions to be called on a class type by ckrm internals */ + void (*add_resctrl)(struct ckrm_core_class *, int resid); // class initialization for new RC + +} ckrm_classtype_t; + +/****************************************************************************************** + * CKRM CORE CLASS + * common part to any class structure (i.e. instance of a classtype) + ******************************************************************************************/ + +/* basic definition of a hierarchy that is to be used by the the CORE classes + * and can be used by the resource class objects + */ + +#define CKRM_CORE_MAGIC 0xBADCAFFE + +typedef struct ckrm_hnode { + struct ckrm_core_class *parent; + struct list_head siblings; /* linked list of siblings */ + struct list_head children; /* anchor for children */ +} ckrm_hnode_t; + +typedef struct ckrm_core_class { + struct ckrm_classtype *classtype; // what type does this core class belong to + void* res_class[CKRM_MAX_RES_CTLRS]; // pointer to array of resource classes + spinlock_t class_lock; // to protect the list and the array above + struct list_head objlist; // generic list for any object list to be maintained by class + struct list_head clslist; // to link up all classes in a single list type wrt to type + struct dentry *dentry; // dentry of inode in the RCFS + int magic; + struct ckrm_hnode hnode; // hierarchy + rwlock_t hnode_rwlock; // rw_clock protecting the hnode above. + atomic_t refcnt; + const char *name; + int delayed; // core deletion delayed because of race conditions +} ckrm_core_class_t; + +/* type coerce between derived class types and ckrm core class type */ +#define class_type(type,coreptr) container_of(coreptr,type,core) +#define class_core(clsptr) (&(clsptr)->core) +/* locking classes */ +#define class_lock(coreptr) spin_lock(&(coreptr)->class_lock) +#define class_unlock(coreptr) spin_unlock(&(coreptr)->class_lock) +/* what type is a class of ISA */ +#define class_isa(clsptr) (class_core(clsptr)->classtype) + + +/****************************************************************************************** + * OTHER + ******************************************************************************************/ + +#define ckrm_get_res_class(rescls,resid,type) ((type*)((rescls)->res_class[resid])) + +extern int ckrm_register_res_ctlr (struct ckrm_classtype *, ckrm_res_ctlr_t *); +extern int ckrm_unregister_res_ctlr (ckrm_res_ctlr_t *); + +extern int ckrm_validate_and_grab_core(struct ckrm_core_class *core); +extern int ckrm_init_core_class(struct ckrm_classtype *clstype,struct ckrm_core_class *dcore, + struct ckrm_core_class *parent, const char *name); +extern int ckrm_release_core_class(struct ckrm_core_class *); // Hubertus .. can disappear after cls del debugging +extern struct ckrm_res_ctlr *ckrm_resctlr_lookup(struct ckrm_classtype *type, const char *resname); + +#if 0 + +// Hubertus ... need to straighten out all these I don't think we will even call thsie ore are we + +/* interface to the RCFS filesystem */ +extern struct ckrm_core_class *ckrm_alloc_core_class(struct ckrm_core_class *, const char *, int); + +// Reclassify the given pid to the given core class by force +extern void ckrm_forced_reclassify_pid(int, struct ckrm_core_class *); + +// Reclassify the given net_struct to the given core class by force +extern void ckrm_forced_reclassify_laq(struct ckrm_net_struct *, + struct ckrm_core_class *); + +#endif + +extern void ckrm_lock_hier(struct ckrm_core_class *); +extern void ckrm_unlock_hier(struct ckrm_core_class *); +extern struct ckrm_core_class * ckrm_get_next_child(struct ckrm_core_class *, + struct ckrm_core_class *); + +extern void child_guarantee_changed(struct ckrm_shares *, int, int); +extern void child_maxlimit_changed(struct ckrm_shares *, int); +extern int set_shares(struct ckrm_shares *, struct ckrm_shares *, struct ckrm_shares *); + +/* classtype registration and lookup */ +extern int ckrm_register_classtype (struct ckrm_classtype *clstype); +extern int ckrm_unregister_classtype(struct ckrm_classtype *clstype); +extern struct ckrm_classtype* ckrm_find_classtype_by_name(const char *name); + +/* default functions that can be used in classtypes's function table */ +extern int ckrm_class_show_shares(struct ckrm_core_class *core, struct seq_file *seq); +extern int ckrm_class_show_stats(struct ckrm_core_class *core, struct seq_file *seq); +extern int ckrm_class_show_config(struct ckrm_core_class *core, struct seq_file *seq); +extern int ckrm_class_set_config(struct ckrm_core_class *core, const char *resname, const char *cfgstr); +extern int ckrm_class_set_shares(struct ckrm_core_class *core, const char *resname, struct ckrm_shares *shares); +extern int ckrm_class_reset_stats(struct ckrm_core_class *core, const char *resname, const char *unused); + +#if 0 +extern void ckrm_ns_hold(struct ckrm_net_struct *); +extern void ckrm_ns_put(struct ckrm_net_struct *); +extern void *ckrm_set_rootcore_byname(char *, void *); +#endif + +static inline void ckrm_core_grab(struct ckrm_core_class *core) +{ + if (core) atomic_inc(&core->refcnt); +} + +static inline void ckrm_core_drop(struct ckrm_core_class *core) +{ + // only make definition available in this context + extern void ckrm_free_core_class(struct ckrm_core_class *core); + if (core && (atomic_dec_and_test(&core->refcnt))) + ckrm_free_core_class(core); +} + +static inline unsigned int +ckrm_is_core_valid(ckrm_core_class_t *core) +{ + return (core && (core->magic == CKRM_CORE_MAGIC)); +} + +// iterate through all associate resource controllers: +// requires following arguments (ckrm_core_class *cls, +// ckrm_res_ctrl *ctlr, +// void *robj, +// int bmap) +#define forall_class_resobjs(cls,rcbs,robj,bmap) \ + for ( bmap=((cls->classtype)->bit_res_ctlrs) ; \ + ({ int rid; ((rid=ffs(bmap)-1) >= 0) && \ + (bmap&=~(1<classtype->res_ctlrs[rid]) && (robj=cls->res_class[rid]))); }) ; \ + ) + +extern struct ckrm_classtype* ckrm_classtypes[]; /* should provide a different interface */ + + +/*----------------------------------------------------------------------------- + * CKRM event callback specification for the classtypes or resource controllers + * typically an array is specified using CKRM_EVENT_SPEC terminated with + * CKRM_EVENT_SPEC_LAST and then that array is registered using + * ckrm_register_event_set. + * Individual registration of event_cb is also possible + *-----------------------------------------------------------------------------*/ + +struct ckrm_event_spec { + enum ckrm_event ev; + struct ckrm_hook_cb cb; +}; +#define CKRM_EVENT_SPEC(EV,FCT) { CKRM_EVENT_##EV, { (ckrm_event_cb)FCT, NULL } } + +int ckrm_register_event_set(struct ckrm_event_spec especs[]); +int ckrm_unregister_event_set(struct ckrm_event_spec especs[]); +int ckrm_register_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb); +int ckrm_unregister_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb); + +/****************************************************************************************** + * CE Invocation interface + ******************************************************************************************/ + +#define ce_protect(ctype) (atomic_inc(&((ctype)->ce_nr_users))) +#define ce_release(ctype) (atomic_dec(&((ctype)->ce_nr_users))) + +// CE Classification callbacks with + +#define CE_CLASSIFY_NORET(ctype, event, objs_to_classify...) \ +do { \ + if ((ctype)->ce_cb_active && (test_bit(event,&(ctype)->ce_callbacks.c_interest))) \ + (*(ctype)->ce_callbacks.classify)(event, objs_to_classify); \ +} while (0) + +#define CE_CLASSIFY_RET(ret, ctype, event, objs_to_classify...) \ +do { \ + if ((ctype)->ce_cb_active && (test_bit(event,&(ctype)->ce_callbacks.c_interest))) \ + ret = (*(ctype)->ce_callbacks.classify)(event, objs_to_classify); \ +} while (0) + +#define CE_NOTIFY(ctype, event, cls, objs_to_classify) \ +do { \ + if ((ctype)->ce_cb_active && (test_bit(event,&(ctype)->ce_callbacks.n_interest))) \ + (*(ctype)->ce_callbacks.notify)(event,cls,objs_to_classify); \ +} while (0) + + +#endif // CONFIG_CKRM + +#endif // __KERNEL__ + +#endif // _LINUX_CKRM_RC_H + + + + + diff --git a/include/linux/ckrm_tc.h b/include/linux/ckrm_tc.h new file mode 100644 index 000000000..6a570252b --- /dev/null +++ b/include/linux/ckrm_tc.h @@ -0,0 +1,18 @@ +#include + + + +#define TASK_CLASS_TYPE_NAME "taskclass" + +typedef struct ckrm_task_class { + struct ckrm_core_class core; +} ckrm_task_class_t; + + +// Index into genmfdesc array, defined in rcfs/dir_modules.c, +// which has the mfdesc entry that taskclass wants to use +#define TC_MF_IDX 0 + + +extern int ckrm_forced_reclassify_pid(int pid, struct ckrm_task_class *cls); + diff --git a/include/linux/ckrm_tsk.h b/include/linux/ckrm_tsk.h new file mode 100644 index 000000000..64d20dd27 --- /dev/null +++ b/include/linux/ckrm_tsk.h @@ -0,0 +1,41 @@ +/* ckrm_tsk.h - No. of tasks resource controller for CKRM + * + * Copyright (C) Chandra Seetharaman, IBM Corp. 2003 + * + * Provides No. of tasks resource controller for CKRM + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 31 Mar 2004 + * Created. + */ + +#ifndef _LINUX_CKRM_TSK_H +#define _LINUX_CKRM_TSK_H + +#include + +#ifdef CONFIG_CKRM_RES_NUMTASKS + +extern int numtasks_get_ref(void *, int); +extern int numtasks_get_ref_resid(void *, int, int); +extern void numtasks_put_ref(void *); + +#else + +#define numtasks_get_ref(a, b) 1 +#define numtasks_get_ref_resid(a, b, c) 1 +#define numtasks_put_ref(a) + +#endif + +#endif // _LINUX_CKRM_RES_H diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 356590d44..1e2850e69 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -125,7 +125,6 @@ COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) /* DM */ COMPATIBLE_IOCTL(DM_VERSION_32) -COMPATIBLE_IOCTL(DM_REMOVE_ALL_32) COMPATIBLE_IOCTL(DM_LIST_DEVICES_32) COMPATIBLE_IOCTL(DM_DEV_CREATE_32) COMPATIBLE_IOCTL(DM_DEV_REMOVE_32) diff --git a/include/linux/compiler-gcc+.h b/include/linux/compiler-gcc+.h index 94e677887..5629cf5cd 100644 --- a/include/linux/compiler-gcc+.h +++ b/include/linux/compiler-gcc+.h @@ -13,3 +13,4 @@ #define __attribute_used__ __attribute__((__used__)) #define __attribute_pure__ __attribute__((pure)) #define __attribute_const__ __attribute__((__const__)) +#define __must_check __attribute__((warn_unused_result)) diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h index 265dad4c3..1b109f047 100644 --- a/include/linux/compiler-gcc3.h +++ b/include/linux/compiler-gcc3.h @@ -25,3 +25,8 @@ #if __GNUC_MINOR__ >= 1 #define noinline __attribute__((noinline)) #endif +#define __must_check __attribute__((warn_unused_result)) + +#if __GNUC_MINOR__ >= 1 +#define noinline __attribute__((noinline)) +#endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 151ab34a5..c68809546 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -45,6 +45,10 @@ extern void __chk_user_ptr(void __user *); #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +#ifndef noinline +#define noinline +#endif + /* Optimization barrier */ #ifndef barrier # define barrier() __memory_barrier() @@ -69,6 +73,10 @@ extern void __chk_user_ptr(void __user *); # define __deprecated /* unimplemented */ #endif +#ifndef __must_check +#define __must_check +#endif + /* * Allow us to avoid 'defined but not used' warnings on functions and data, * as well as force them to be emitted to the assembly file. diff --git a/include/linux/config.h b/include/linux/config.h index 9d1c14f7a..83b6c3d14 100644 --- a/include/linux/config.h +++ b/include/linux/config.h @@ -2,5 +2,7 @@ #define _LINUX_CONFIG_H #include - +#ifndef __KERNEL__ +#error including kernel header in userspace; use the glibc headers instead! +#endif #endif diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 4293a465d..ee773803e 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -41,7 +41,6 @@ extern cpumask_t cpu_present_map; #define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define cpu_present(cpu) ({ BUG_ON((cpu) != 0); 1; }) -#define for_each_cpu_mask(cpu, mask) for (cpu = 0; cpu < 1; cpu++) #define for_each_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) #define for_each_online_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) #define for_each_present_cpu(cpu) for (cpu = 0; cpu < 1; cpu++) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 72f48658a..b716f8941 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -103,6 +103,7 @@ struct dentry { struct super_block *d_sb; /* The root of the dentry tree */ int d_mounted; void *d_fsdata; /* fs-specific data */ + void * d_extra_attributes; /* TUX-specific data */ struct rcu_head d_rcu; struct dcookie_struct *d_cookie; /* cookie, if any */ struct hlist_node d_hash; /* lookup hash list */ @@ -210,6 +211,7 @@ extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); extern void shrink_dcache_anon(struct hlist_head *); extern int d_invalidate(struct dentry *); +extern void flush_dentry_attributes(void); /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode *); @@ -253,8 +255,12 @@ extern struct dentry * __d_lookup(struct dentry *, struct qstr *); /* validate "insecure" dentry pointer */ extern int d_validate(struct dentry *, struct dentry *); +char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, + char *buffer, int buflen); + extern char * d_path(struct dentry *, struct vfsmount *, char *, int); - + /* Allocation counts.. */ /** diff --git a/include/linux/delay.h b/include/linux/delay.h index f5610919d..f0b96ae39 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -10,7 +10,7 @@ extern unsigned long loops_per_jiffy; #include - +#include /* * Using udelay() for intervals greater than a few milliseconds can * risk overflow for high loops_per_jiffy (high bogomips) machines. The @@ -25,14 +25,13 @@ extern unsigned long loops_per_jiffy; #define MAX_UDELAY_MS 5 #endif -#ifdef notdef -#define mdelay(n) (\ - {unsigned long __ms=(n); while (__ms--) udelay(1000);}) -#else -#define mdelay(n) (\ - (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \ - ({unsigned long __ms=(n); while (__ms--) udelay(1000);})) -#endif +#define mdelay(n) ( \ + { \ + static int warned=0; \ + unsigned long __ms=(n); \ + WARN_ON(in_irq() && !(warned++)); \ + while (__ms--) udelay(1000); \ + }) #ifndef ndelay #define ndelay(x) udelay(((x)+999)/1000) diff --git a/include/linux/errno.h b/include/linux/errno.h index a1f948f0a..96c53136c 100644 --- a/include/linux/errno.h +++ b/include/linux/errno.h @@ -23,6 +23,9 @@ #define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ #define EIOCBQUEUED 529 /* iocb queued, will get completion event */ +/* Defined for TUX async IO */ +#define EWOULDBLOCKIO 530 /* Would block due to block-IO */ + #endif #endif diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index d701ba88c..7c6f650c9 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -192,6 +192,8 @@ struct ext2_group_desc #define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT2_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define EXT2_IUNLINK_FL 0x08000000 /* Immutable unlink */ #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ @@ -240,7 +242,7 @@ struct ext2_inode { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; + __u16 l_i_xid; /* LRU Context */ __u16 l_i_uid_high; /* these 2 fields */ __u16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; @@ -272,6 +274,7 @@ struct ext2_inode { #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high +#define i_raw_xid osd2.linux2.l_i_xid #define i_reserved2 osd2.linux2.l_i_reserved2 #endif @@ -312,6 +315,7 @@ struct ext2_inode { #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ #define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ #define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ +#define EXT2_MOUNT_TAG_XID (1<<16) /* Enable Context Tags */ #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt #define set_opt(o, opt) o |= EXT2_MOUNT_##opt diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index d90013eb3..6e4497d8d 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -33,11 +33,10 @@ struct statfs; #undef EXT3FS_DEBUG /* - * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files + * Define EXT3_RESERVATION to reserve data blocks for expanding files */ -#undef EXT3_PREALLOCATE /* @@@ Fix this! */ -#define EXT3_DEFAULT_PREALLOC_BLOCKS 8 - +#define EXT3_DEFAULT_RESERVE_BLOCKS 8 +#define EXT3_MAX_RESERVE_BLOCKS 1024 /* * Always enable hashed directories */ @@ -185,6 +184,8 @@ struct ext3_group_desc #define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT3_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define EXT3_IUNLINK_FL 0x08000000 /* Immutable unlink */ #define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ #define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ @@ -195,6 +196,32 @@ struct ext3_group_desc */ #define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ #define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ +#define EXT3_STATE_RESIZE 0x00000004 /* fake inode for resizing */ + + +/* Used to pass group descriptor data when online resize is done */ +struct ext3_new_group_input { + __u32 group; /* Group number for this data */ + __u32 block_bitmap; /* Absolute block number of block bitmap */ + __u32 inode_bitmap; /* Absolute block number of inode bitmap */ + __u32 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; +}; + +/* The struct ext3_new_group_input in kernel space, with free_blocks_count */ +struct ext3_new_group_data { + __u32 group; + __u32 block_bitmap; + __u32 inode_bitmap; + __u32 inode_table; + __u32 blocks_count; + __u16 reserved_blocks; + __u16 unused; + __u32 free_blocks_count; +}; + /* * ioctl commands @@ -203,11 +230,18 @@ struct ext3_group_desc #define EXT3_IOC_SETFLAGS _IOW('f', 2, long) #define EXT3_IOC_GETVERSION _IOR('f', 3, long) #define EXT3_IOC_SETVERSION _IOW('f', 4, long) +#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) #define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) #define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) #ifdef CONFIG_JBD_DEBUG #define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) #endif +#define EXT3_IOC_GETRSVSZ _IOR('r', 1, long) +#define EXT3_IOC_SETRSVSZ _IOW('r', 2, long) +#ifdef CONFIG_VSERVER_LEGACY +#define EXT3_IOC_SETXID FIOC_SETXIDJ +#endif /* * Structure of an inode on the disk @@ -244,7 +278,7 @@ struct ext3_inode { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; + __u16 l_i_xid; /* LRU Context */ __u16 l_i_uid_high; /* these 2 fields */ __u16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; @@ -276,6 +310,7 @@ struct ext3_inode { #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high +#define i_raw_xid osd2.linux2.l_i_xid #define i_reserved2 osd2.linux2.l_i_reserved2 #elif defined(__GNU__) @@ -306,24 +341,26 @@ struct ext3_inode { /* * Mount flags */ -#define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */ -#define EXT3_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ -#define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */ -#define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */ -#define EXT3_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ -#define EXT3_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ -#define EXT3_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ -#define EXT3_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ -#define EXT3_MOUNT_NOLOAD 0x0100 /* Don't use existing journal*/ -#define EXT3_MOUNT_ABORT 0x0200 /* Fatal error detected */ -#define EXT3_MOUNT_DATA_FLAGS 0x0C00 /* Mode for data writes: */ - #define EXT3_MOUNT_JOURNAL_DATA 0x0400 /* Write data to journal */ - #define EXT3_MOUNT_ORDERED_DATA 0x0800 /* Flush data before commit */ - #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ -#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ -#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ -#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ -#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */ +#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ +#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */ +#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */ +#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ +#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ +#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ +#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ +#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ +#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */ +#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ +#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ +#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ +#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ +#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ +#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ +#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ +#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */ +#define EXT3_MOUNT_TAG_XID 0x20000 /* Enable Context Tags */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -417,7 +454,7 @@ struct ext3_super_block { */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __u16 s_padding1; + __u16 s_reserved_gdt_blocks; /* Per group desc for online growth */ /* * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. */ @@ -680,8 +717,7 @@ struct dir_private_info { /* balloc.c */ extern int ext3_bg_has_super(struct super_block *sb, int group); extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); -extern int ext3_new_block (handle_t *, struct inode *, unsigned long, - __u32 *, __u32 *, int *); +extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *); extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long, unsigned long); extern unsigned long ext3_count_free_blocks (struct super_block *); @@ -689,6 +725,7 @@ extern void ext3_check_blocks_bitmap (struct super_block *); extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh); +extern int ext3_should_retry_alloc(struct super_block *sb, int *retries); /* dir.c */ extern int ext3_check_dir_entry(const char *, struct inode *, @@ -728,6 +765,7 @@ extern void ext3_put_inode (struct inode *); extern void ext3_delete_inode (struct inode *); extern int ext3_sync_inode (handle_t *, struct inode *); extern void ext3_discard_prealloc (struct inode *); +extern void ext3_discard_reservation (struct inode *); extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); extern void ext3_truncate (struct inode *); @@ -743,6 +781,13 @@ extern int ext3_orphan_add(handle_t *, struct inode *); extern int ext3_orphan_del(handle_t *, struct inode *); extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash, __u32 *next_hash); + +/* resize.c */ +extern int ext3_group_add(struct super_block *sb, + struct ext3_new_group_data *input); +extern int ext3_group_extend(struct super_block *sb, + struct ext3_super_block *es, + unsigned long n_blocks_count); /* super.c */ extern void ext3_error (struct super_block *, const char *, const char *, ...) diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 7451cdcfb..422fd5156 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -18,8 +18,16 @@ #include +struct reserve_window { + struct list_head rsv_list; + __u32 rsv_start; + __u32 rsv_end; + atomic_t rsv_goal_size; + __u32 rsv_alloc_hit; +}; + /* - * second extended file system inode data in memory + * third extended file system inode data in memory */ struct ext3_inode_info { __u32 i_data[15]; @@ -57,10 +65,9 @@ struct ext3_inode_info { * allocation when we detect linearly ascending requests. */ __u32 i_next_alloc_goal; -#ifdef EXT3_PREALLOCATE - __u32 i_prealloc_block; - __u32 i_prealloc_count; -#endif + /* block reservation window */ + struct reserve_window i_rsv_window; + __u32 i_dir_start_lookup; #ifdef CONFIG_EXT3_FS_XATTR /* diff --git a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h index 8ed3cf7f4..1c3294d94 100644 --- a/include/linux/ext3_fs_sb.h +++ b/include/linux/ext3_fs_sb.h @@ -59,6 +59,10 @@ struct ext3_sb_info { struct percpu_counter s_dirs_counter; struct blockgroup_lock s_blockgroup_lock; + /* head of the per fs reservation window tree */ + spinlock_t s_rsv_window_lock; + struct reserve_window s_rsv_window_head; + /* Journaling */ struct inode * s_journal_inode; struct journal_s * s_journal; diff --git a/include/linux/file.h b/include/linux/file.h index b3fbadf31..1c1e0b38b 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -81,4 +81,6 @@ struct task_struct; struct files_struct *get_files_struct(struct task_struct *); void FASTCALL(put_files_struct(struct files_struct *fs)); +extern int dupfd(struct file *file, unsigned int start); + #endif /* __LINUX_FILE_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 10a69a544..0f6c1e938 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -114,6 +114,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define MS_VERBOSE 32768 #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_ONE_SECOND (1<<17) /* fs has 1 sec a/m/ctime resolution */ +#define MS_TAGXID (1<<24) /* tag inodes with context information */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -140,6 +141,8 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define S_NOQUOTA 64 /* Inode is not counted to quota */ #define S_DIRSYNC 128 /* Directory modifications are synchronous */ #define S_NOCMTIME 256 /* Do not update file c/mtime */ +#define S_BARRIER 512 /* Barrier for chroot() */ +#define S_IUNLINK 1024 /* Immutable unlink */ /* * Note that nosuid etc flags are inode-specific: setting some file-system @@ -167,11 +170,14 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA) #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) +#define IS_IUNLINK(inode) ((inode)->i_flags & S_IUNLINK) +#define IS_IXORUNLINK(inode) ((IS_IUNLINK(inode) ? S_IMMUTABLE : 0) ^ IS_IMMUTABLE(inode)) #define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME)) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) #define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) #define IS_ONE_SECOND(inode) __IS_FLG(inode, MS_ONE_SECOND) +#define IS_BARRIER(inode) (S_ISDIR((inode)->i_mode) && ((inode)->i_flags & S_BARRIER)) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) #define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME) @@ -281,6 +287,9 @@ struct iattr { #define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */ #define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */ +#define ATTR_FLAG_BARRIER 512 /* Barrier for chroot() */ +#define ATTR_FLAG_IUNLINK 1024 /* Immutable unlink */ + /* * Includes for diskquotas. */ @@ -418,6 +427,7 @@ struct inode { unsigned int i_nlink; uid_t i_uid; gid_t i_gid; + xid_t i_xid; dev_t i_rdev; loff_t i_size; struct timespec i_atime; @@ -900,6 +910,7 @@ struct inode_operations { struct inode *, struct dentry *); int (*readlink) (struct dentry *, char __user *,int); int (*follow_link) (struct dentry *, struct nameidata *); + void (*put_link) (struct dentry *, struct nameidata *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, struct nameidata *); int (*setattr) (struct dentry *, struct iattr *); @@ -1403,7 +1414,7 @@ ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void __user *); extern void do_generic_mapping_read(struct address_space *mapping, struct file_ra_state *, struct file *, - loff_t *, read_descriptor_t *, read_actor_t); + loff_t *, read_descriptor_t *, read_actor_t, int); extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, @@ -1419,14 +1430,15 @@ extern int generic_file_open(struct inode * inode, struct file * filp); static inline void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, - read_actor_t actor) + read_actor_t actor, int nonblock) { do_generic_mapping_read(filp->f_mapping, &filp->f_ra, filp, ppos, desc, - actor); + actor, + nonblock); } ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, @@ -1459,12 +1471,17 @@ extern struct file_operations generic_ro_fops; #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) +extern void nd_set_link(struct nameidata *, char *); +extern char *nd_get_link(struct nameidata *); extern int vfs_readlink(struct dentry *, char __user *, int, const char *); extern int vfs_follow_link(struct nameidata *, const char *); extern int page_readlink(struct dentry *, char __user *, int); extern int page_follow_link(struct dentry *, struct nameidata *); +extern int page_follow_link_light(struct dentry *, struct nameidata *); +extern void page_put_link(struct dentry *, struct nameidata *); extern int page_symlink(struct inode *inode, const char *symname, int len); extern struct inode_operations page_symlink_inode_operations; +extern int generic_readlink(struct dentry *, char __user *, int); extern void generic_fillattr(struct inode *, struct kstat *); extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); void inode_add_bytes(struct inode *inode, loff_t bytes); diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 8980d1fd7..e7fb254fa 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -46,7 +46,7 @@ struct vm_area_struct; __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \ __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP) -#define GFP_ATOMIC (__GFP_HIGH) +#define GFP_ATOMIC (__GFP_HIGH | __GFP_NOWARN) #define GFP_NOIO (__GFP_WAIT) #define GFP_NOFS (__GFP_WAIT | __GFP_IO) #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) @@ -73,6 +73,11 @@ struct vm_area_struct; * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets * optimized to &contig_page_data at compile-time. */ + +#ifndef HAVE_ARCH_FREE_PAGE +static inline void arch_free_page(struct page *page, int order) { } +#endif + extern struct page * FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *)); diff --git a/include/linux/ghash.h b/include/linux/ghash.h new file mode 100644 index 000000000..a24798866 --- /dev/null +++ b/include/linux/ghash.h @@ -0,0 +1,236 @@ +/* + * include/linux/ghash.h -- generic hashing with fuzzy retrieval + * + * (C) 1997 Thomas Schoebel-Theuer + * + * The algorithms implemented here seem to be a completely new invention, + * and I'll publish the fundamentals in a paper. + */ + +#ifndef _GHASH_H +#define _GHASH_H +/* HASHSIZE _must_ be a power of two!!! */ + + +#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \ +\ +struct NAME##_table {\ + TYPE * hashtable[HASHSIZE];\ + TYPE * sorted_list;\ + int nr_entries;\ +};\ +\ +struct NAME##_ptrs {\ + TYPE * next_hash;\ + TYPE * prev_hash;\ + TYPE * next_sorted;\ + TYPE * prev_sorted;\ +}; + +#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\ +\ +LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + int ix = HASHFN(elem->KEY);\ + TYPE ** base = &tbl->hashtable[ix];\ + TYPE * ptr = *base;\ + TYPE * prev = NULL;\ +\ + tbl->nr_entries++;\ + while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ + base = &ptr->PTRS.next_hash;\ + prev = ptr;\ + ptr = *base;\ + }\ + elem->PTRS.next_hash = ptr;\ + elem->PTRS.prev_hash = prev;\ + if(ptr) {\ + ptr->PTRS.prev_hash = elem;\ + }\ + *base = elem;\ +\ + ptr = prev;\ + if(!ptr) {\ + ptr = tbl->sorted_list;\ + prev = NULL;\ + } else {\ + prev = ptr->PTRS.prev_sorted;\ + }\ + while(ptr) {\ + TYPE * next = ptr->PTRS.next_hash;\ + if(next && KEYCMP(next->KEY, elem->KEY)) {\ + prev = ptr;\ + ptr = next;\ + } else if(KEYCMP(ptr->KEY, elem->KEY)) {\ + prev = ptr;\ + ptr = ptr->PTRS.next_sorted;\ + } else\ + break;\ + }\ + elem->PTRS.next_sorted = ptr;\ + elem->PTRS.prev_sorted = prev;\ + if(ptr) {\ + ptr->PTRS.prev_sorted = elem;\ + }\ + if(prev) {\ + prev->PTRS.next_sorted = elem;\ + } else {\ + tbl->sorted_list = elem;\ + }\ +}\ +\ +LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + TYPE * next = elem->PTRS.next_hash;\ + TYPE * prev = elem->PTRS.prev_hash;\ +\ + tbl->nr_entries--;\ + if(next)\ + next->PTRS.prev_hash = prev;\ + if(prev)\ + prev->PTRS.next_hash = next;\ + else {\ + int ix = HASHFN(elem->KEY);\ + tbl->hashtable[ix] = next;\ + }\ +\ + next = elem->PTRS.next_sorted;\ + prev = elem->PTRS.prev_sorted;\ + if(next)\ + next->PTRS.prev_sorted = prev;\ + if(prev)\ + prev->PTRS.next_sorted = next;\ + else\ + tbl->sorted_list = next;\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix = hashfn(pos);\ + TYPE * ptr = tbl->hashtable[ix];\ + while(ptr && KEYCMP(ptr->KEY, pos))\ + ptr = ptr->PTRS.next_hash;\ + if(ptr && !KEYEQ(ptr->KEY, pos))\ + ptr = NULL;\ + return ptr;\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix;\ + int offset;\ + TYPE * ptr;\ + TYPE * next;\ +\ + ptr = tbl->sorted_list;\ + if(!ptr || KEYCMP(pos, ptr->KEY))\ + return NULL;\ + ix = HASHFN(pos);\ + offset = HASHSIZE;\ + do {\ + offset >>= 1;\ + next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\ + if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\ + && KEYCMP(ptr->KEY, next->KEY))\ + ptr = next;\ + } while(offset);\ +\ + for(;;) {\ + next = ptr->PTRS.next_hash;\ + if(next) {\ + if(KEYCMP(next->KEY, pos)) {\ + ptr = next;\ + continue;\ + }\ + }\ + next = ptr->PTRS.next_sorted;\ + if(next && KEYCMP(next->KEY, pos)) {\ + ptr = next;\ + continue;\ + }\ + return ptr;\ + }\ + return NULL;\ +} + +/* LINKAGE - empty or "static", depending on whether you want the definitions to + * be public or not + * NAME - a string to stick in names to make this hash table type distinct from + * any others + * HASHSIZE - number of buckets + * TYPE - type of data contained in the buckets - must be a structure, one + * field is of type NAME_ptrs, another is the hash key + * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that + * field + * KEYTYPE - type of the key field within TYPE + * KEY - name of the key field within TYPE + * KEYCMP - pointer to function that compares KEYTYPEs to each other - the + * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, + * non-zero for not equal + * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE), + * it returns a number in the range 0 ... HASHSIZE - 1 + * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call + * DEF_HASH. + */ + +#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \ +\ +struct NAME##_table {\ + TYPE * hashtable[HASHSIZE];\ + int nr_entries;\ +};\ +\ +struct NAME##_ptrs {\ + TYPE * next_hash;\ + TYPE * prev_hash;\ +}; + +#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\ +\ +LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + int ix = HASHFN(elem->KEY);\ + TYPE ** base = &tbl->hashtable[ix];\ + TYPE * ptr = *base;\ + TYPE * prev = NULL;\ +\ + tbl->nr_entries++;\ + while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ + base = &ptr->PTRS.next_hash;\ + prev = ptr;\ + ptr = *base;\ + }\ + elem->PTRS.next_hash = ptr;\ + elem->PTRS.prev_hash = prev;\ + if(ptr) {\ + ptr->PTRS.prev_hash = elem;\ + }\ + *base = elem;\ +}\ +\ +LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + TYPE * next = elem->PTRS.next_hash;\ + TYPE * prev = elem->PTRS.prev_hash;\ +\ + tbl->nr_entries--;\ + if(next)\ + next->PTRS.prev_hash = prev;\ + if(prev)\ + prev->PTRS.next_hash = next;\ + else {\ + int ix = HASHFN(elem->KEY);\ + tbl->hashtable[ix] = next;\ + }\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix = HASHFN(pos);\ + TYPE * ptr = tbl->hashtable[ix];\ + while(ptr && KEYCMP(ptr->KEY, pos))\ + ptr = ptr->PTRS.next_hash;\ + return ptr;\ +} + +#endif diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 232d8fdb5..e334a5fdd 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -28,9 +28,10 @@ static inline void *kmap(struct page *page) #define kunmap(page) do { (void) (page); } while (0) -#define kmap_atomic(page, idx) page_address(page) -#define kunmap_atomic(addr, idx) do { } while (0) -#define kmap_atomic_to_page(ptr) virt_to_page(ptr) +#define kmap_atomic(page, idx) page_address(page) +#define kmap_atomic_nocache_pfn(pfn, idx) pfn_to_kaddr(pfn) +#define kunmap_atomic(addr, idx) do { } while (0) +#define kmap_atomic_to_page(ptr) virt_to_page(ptr) #endif /* CONFIG_HIGHMEM */ diff --git a/include/linux/hpet.h b/include/linux/hpet.h new file mode 100644 index 000000000..9ab04e988 --- /dev/null +++ b/include/linux/hpet.h @@ -0,0 +1,133 @@ +#ifndef __HPET__ +#define __HPET__ 1 + +/* + * Offsets into HPET Registers + */ + +struct hpet { + u64 hpet_cap; /* capabilities */ + u64 res0; /* reserved */ + u64 hpet_config; /* configuration */ + u64 res1; /* reserved */ + u64 hpet_isr; /* interrupt status reg */ + u64 res2[25]; /* reserved */ + union { /* main counter */ + u64 _hpet_mc64; + u32 _hpet_mc32; + unsigned long _hpet_mc; + } _u0; + u64 res3; /* reserved */ + struct hpet_timer { + u64 hpet_config; /* configuration/cap */ + union { /* timer compare register */ + u64 _hpet_hc64; + u32 _hpet_hc32; + unsigned long _hpet_compare; + } _u1; + u64 hpet_fsb[2]; /* FSB route */ + } hpet_timers[1]; +}; + +#define hpet_mc _u0._hpet_mc +#define hpet_compare _u1._hpet_compare + +#define HPET_MAX_TIMERS (32) + +/* + * HPET general capabilities register + */ + +#define HPET_COUNTER_CLK_PERIOD_MASK (0xffffffff00000000ULL) +#define HPET_COUNTER_CLK_PERIOD_SHIFT (32UL) +#define HPET_VENDOR_ID_MASK (0x00000000ffff0000ULL) +#define HPET_VENDOR_ID_SHIFT (16ULL) +#define HPET_LEG_RT_CAP_MASK (0x8000) +#define HPET_COUNTER_SIZE_MASK (0x2000) +#define HPET_NUM_TIM_CAP_MASK (0x1f00) +#define HPET_NUM_TIM_CAP_SHIFT (8ULL) + +/* + * HPET general configuration register + */ + +#define HPET_LEG_RT_CNF_MASK (2UL) +#define HPET_ENABLE_CNF_MASK (1UL) + +/* + * HPET interrupt status register + */ + +#define HPET_ISR_CLEAR(HPET, TIMER) \ + (HPET)->hpet_isr |= (1UL << TIMER) + +/* + * Timer configuration register + */ + +#define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL) +#define Tn_INI_ROUTE_CAP_SHIFT (32UL) +#define Tn_FSB_INT_DELCAP_MASK (0x8000UL) +#define Tn_FSB_INT_DELCAP_SHIFT (15) +#define Tn_FSB_EN_CNF_MASK (0x4000UL) +#define Tn_FSB_EN_CNF_SHIFT (14) +#define Tn_INT_ROUTE_CNF_MASK (0x3e00UL) +#define Tn_INT_ROUTE_CNF_SHIFT (9) +#define Tn_32MODE_CNF_MASK (0x0100UL) +#define Tn_VAL_SET_CNF_MASK (0x0040UL) +#define Tn_SIZE_CAP_MASK (0x0020UL) +#define Tn_PER_INT_CAP_MASK (0x0010UL) +#define Tn_TYPE_CNF_MASK (0x0008UL) +#define Tn_INT_ENB_CNF_MASK (0x0004UL) +#define Tn_INT_TYPE_CNF_MASK (0x0002UL) + +/* + * Timer FSB Interrupt Route Register + */ + +#define Tn_FSB_INT_ADDR_MASK (0xffffffff00000000ULL) +#define Tn_FSB_INT_ADDR_SHIFT (32UL) +#define Tn_FSB_INT_VAL_MASK (0x00000000ffffffffULL) + +struct hpet_info { + unsigned long hi_ireqfreq; /* Hz */ + unsigned long hi_flags; /* information */ + unsigned short hi_hpet; + unsigned short hi_timer; +}; + +#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */ + +#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ +#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ +#define HPET_INFO _IOR('h', 0x03, struct hpet_info) +#define HPET_EPI _IO('h', 0x04) /* enable periodic */ +#define HPET_DPI _IO('h', 0x05) /* disable periodic */ +#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ + +/* + * exported interfaces + */ + +struct hpet_task { + void (*ht_func) (void *); + void *ht_data; + void *ht_opaque; +}; + +struct hpet_data { + unsigned long hd_address; + unsigned short hd_nirqs; + unsigned short hd_flags; + unsigned int hd_state; /* timer allocated */ + unsigned int hd_irq[HPET_MAX_TIMERS]; +}; + +#define HPET_DATA_PLATFORM 0x0001 /* platform call to hpet_alloc */ + +int hpet_alloc(struct hpet_data *); +int hpet_register(struct hpet_task *, int); +int hpet_unregister(struct hpet_task *); +int hpet_control(struct hpet_task *, unsigned int, unsigned long); + +#endif /* !__HPET__ */ diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 6908f29d3..3098500ff 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -12,7 +12,7 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) return vma->vm_flags & VM_HUGETLB; } -int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *); +int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void *, size_t *); int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); void zap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); @@ -32,7 +32,6 @@ void free_huge_page(struct page *); extern unsigned long max_huge_pages; extern const unsigned long hugetlb_zero, hugetlb_infinity; -extern int sysctl_hugetlb_shm_group; static inline void mark_mm_hugetlb(struct mm_struct *mm, struct vm_area_struct *vma) diff --git a/include/linux/ide.h b/include/linux/ide.h index ade3bb869..8a773de2c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -690,6 +690,7 @@ typedef union { typedef enum { ide_stopped, /* no drive operation was started */ ide_started, /* a drive operation was started, handler was set */ + ide_released, /* as ide_started, but bus also released */ } ide_startstop_t; struct ide_driver_s; @@ -723,6 +724,7 @@ typedef struct ide_drive_s { u8 keep_settings; /* restore settings after drive reset */ u8 autodma; /* device can safely use dma on host */ u8 using_dma; /* disk is using dma for read/write */ + u8 using_tcq; /* disk is using queueing */ u8 retry_pio; /* retrying dma capable host in pio */ u8 state; /* retry state */ u8 waiting_for_dma; /* dma currently in progress */ @@ -749,7 +751,6 @@ typedef struct ide_drive_s { unsigned remap_0_to_1 : 1; /* 0=noremap, 1=remap 0->1 (for EZDrive) */ unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */ unsigned vdma : 1; /* 1=doing PIO over DMA 0=doing normal DMA */ - unsigned stroke : 1; /* from: hdx=stroke */ unsigned addressing; /* : 3; * 0=28-bit * 1=48-bit @@ -780,6 +781,7 @@ typedef struct ide_drive_s { u8 sect; /* "real" sectors per track */ u8 bios_head; /* BIOS/fdisk/LILO number of heads */ u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */ + u8 queue_depth; /* max queue depth */ unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ @@ -1093,6 +1095,7 @@ typedef struct ide_settings_s { extern struct semaphore ide_setting_sem; extern int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); +extern void ide_remove_setting(ide_drive_t *drive, char *name); extern ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); extern int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); extern int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); @@ -1113,6 +1116,7 @@ extern struct proc_dir_entry *proc_ide_root; extern void proc_ide_create(void); extern void proc_ide_destroy(void); +extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_drives(ide_hwif_t *); extern void create_proc_ide_interfaces(void); extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *); @@ -1355,8 +1359,6 @@ extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t); */ extern void ide_end_drive_cmd(ide_drive_t *, u8, u8); -extern void try_to_flush_leftover_data(ide_drive_t *); - /* * Issue ATA command and wait for completion. * Use for implementing commands in kernel @@ -1620,6 +1622,14 @@ extern int __ide_dma_lostirq(ide_drive_t *); extern int __ide_dma_timeout(ide_drive_t *); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +#ifdef CONFIG_BLK_DEV_IDE_TCQ +extern int __ide_dma_queued_on(ide_drive_t *drive); +extern int __ide_dma_queued_off(ide_drive_t *drive); +extern ide_startstop_t __ide_dma_queued_read(ide_drive_t *drive); +extern ide_startstop_t __ide_dma_queued_write(ide_drive_t *drive); +extern ide_startstop_t __ide_dma_queued_start(ide_drive_t *drive); +#endif + #else static inline int __ide_dma_off(ide_drive_t *drive) { return 0; } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -1688,6 +1698,28 @@ extern struct semaphore ide_cfg_sem; #define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable(); } while (0) +#define IDE_MAX_TAG 32 +#ifdef CONFIG_BLK_DEV_IDE_TCQ +static inline int ata_pending_commands(ide_drive_t *drive) +{ + if (drive->using_tcq) + return blk_queue_tag_depth(drive->queue); + + return 0; +} + +static inline int ata_can_queue(ide_drive_t *drive) +{ + if (drive->using_tcq) + return blk_queue_tag_queue(drive->queue); + + return 1; +} +#else +#define ata_pending_commands(drive) (0) +#define ata_can_queue(drive) (1) +#endif + extern struct bus_type ide_bus_type; #endif /* _IDE_H */ diff --git a/include/linux/if.h b/include/linux/if.h index 296a6c21e..fbe010691 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -147,7 +147,7 @@ struct ifreq struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; - void __user * ifru_data; + char __user * ifru_data; struct if_settings ifru_settings; } ifr_ifru; }; @@ -182,8 +182,8 @@ struct ifconf int ifc_len; /* size of buffer */ union { - char __user *ifcu_buf; - struct ifreq __user *ifcu_req; + char * ifcu_buf; + struct ifreq *ifcu_req; } ifc_ifcu; }; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 58d6e606d..6af157c97 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -104,7 +104,7 @@ struct __fdb_entry #include -extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *)); +extern void brioctl_set(int (*ioctl_hook)(unsigned int, unsigned long)); extern int (*br_handle_frame_hook)(struct sk_buff *skb); extern int (*br_should_route_hook)(struct sk_buff **pskb); diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 29189706e..3ba25d682 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -112,6 +112,10 @@ extern struct group_info init_groups; .proc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \ + .xid = 0, \ + .nid = 0, \ + .vx_info = NULL, \ + .nx_info = NULL, \ } diff --git a/include/linux/ip.h b/include/linux/ip.h index ab799b48b..5ea190d1b 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -111,6 +111,7 @@ struct inet_opt { /* Socket demultiplex comparisons on incoming packets. */ __u32 daddr; /* Foreign IPv4 addr */ __u32 rcv_saddr; /* Bound local IPv4 addr */ + __u32 rcv_saddr2; /* Second bound ipv4 addr, for ipv4root */ __u16 dport; /* Destination port */ __u16 num; /* Local port */ __u32 saddr; /* Sending source */ diff --git a/include/linux/ipc.h b/include/linux/ipc.h index b29118973..079c2feb3 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h @@ -66,6 +66,7 @@ struct kern_ipc_perm mode_t mode; unsigned long seq; void *security; + xid_t xid; }; #endif /* __KERNEL__ */ diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 0a625c3cd..dec393a59 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -1006,6 +1006,7 @@ int __log_space_left(journal_t *); /* Called with journal locked */ int log_start_commit(journal_t *journal, tid_t tid); int __log_start_commit(journal_t *journal, tid_t tid); int journal_start_commit(journal_t *journal, tid_t *tid); +int journal_force_commit_nested(journal_t *journal); int log_wait_commit(journal_t *journal, tid_t tid); int log_do_checkpoint(journal_t *journal); diff --git a/include/linux/klog.h b/include/linux/klog.h new file mode 100644 index 000000000..cb79beaa5 --- /dev/null +++ b/include/linux/klog.h @@ -0,0 +1,24 @@ +/* + * KLOG Generic Logging facility built upon the relayfs infrastructure + * + * Authors: Hubertus Frankeh (frankeh@us.ibm.com) + * Tom Zanussi (zanussi@us.ibm.com) + * + * Please direct all questions/comments to zanussi@us.ibm.com + * + * Copyright (C) 2003, IBM Corp + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _LINUX_KLOG_H +#define _LINUX_KLOG_H + +extern int klog(const char *fmt, ...); +extern int klog_raw(const char *buf,int len); + +#endif /* _LINUX_KLOG_H */ diff --git a/include/linux/kmalloc_sizes.h b/include/linux/kmalloc_sizes.h index d82d4c05c..32e45b72a 100644 --- a/include/linux/kmalloc_sizes.h +++ b/include/linux/kmalloc_sizes.h @@ -12,6 +12,7 @@ CACHE(256) CACHE(512) CACHE(1024) + CACHE(1620) CACHE(2048) CACHE(4096) CACHE(8192) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 2aeecaf71..775c41590 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -153,6 +153,9 @@ void mpol_free_shared_policy(struct shared_policy *p); struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx); +extern void numa_default_policy(void); +extern void numa_policy_init(void); + #else struct mempolicy {}; @@ -215,6 +218,14 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx) #define vma_policy(vma) NULL #define vma_set_policy(vma, pol) do {} while(0) +static inline void numa_policy_init(void) +{ +} + +static inline void numa_default_policy(void) +{ +} + #endif /* CONFIG_NUMA */ #endif /* __KERNEL__ */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 8f8a8a3a3..134cefbd6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -12,6 +12,7 @@ #include #include #include +#include #include struct mempolicy; @@ -495,9 +496,19 @@ int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new); struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, unsigned long addr); struct file *shmem_file_setup(char * name, loff_t size, unsigned long flags); -void shmem_lock(struct file * file, int lock); +int shmem_lock(struct file * file, int lock); int shmem_zero_setup(struct vm_area_struct *); +static inline int can_do_mlock(void) +{ + if (capable(CAP_IPC_LOCK)) + return 1; + if (current->rlim[RLIMIT_MEMLOCK].rlim_cur != 0) + return 1; + return 0; +} + + /* * Parameter block passed down to zap_pte_range in exceptional cases. */ @@ -564,6 +575,9 @@ int clear_page_dirty_for_io(struct page *page); */ typedef int (*shrinker_t)(int nr_to_scan, unsigned int gfp_mask); +extern long do_mprotect(struct mm_struct *mm, unsigned long start, + size_t len, unsigned long prot); + /* * Add an aging callback. The int is the number of 'seeks' it takes * to recreate one of the objects that these functions age. @@ -630,11 +644,12 @@ extern struct vm_area_struct *copy_vma(struct vm_area_struct **, unsigned long addr, unsigned long len, pgoff_t pgoff); extern void exit_mmap(struct mm_struct *); -extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); +extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flag, unsigned long pgoff); +extern unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file *file, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flag, + unsigned long pgoff); static inline unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, @@ -644,7 +659,8 @@ static inline unsigned long do_mmap(struct file *file, unsigned long addr, if ((offset + PAGE_ALIGN(len)) < offset) goto out; if (!(offset & ~PAGE_MASK)) - ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT); + ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, + offset >> PAGE_SHIFT); out: return ret; } @@ -710,6 +726,8 @@ extern unsigned int nr_used_zone_pages(void); extern struct page * vmalloc_to_page(void *addr); extern struct page * follow_page(struct mm_struct *mm, unsigned long address, int write); +extern struct page * follow_page_pfn(struct mm_struct *mm, + unsigned long address, int write, unsigned long *pfn); extern int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot); diff --git a/include/linux/module.h b/include/linux/module.h index 2709330e8..3311af6eb 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -525,29 +525,8 @@ struct obsolete_modparm { struct obsolete_modparm __parm_##var __attribute__((section("__obsparm"))) = \ { __stringify(var), type }; -static inline void __deprecated MOD_INC_USE_COUNT(struct module *module) -{ - __unsafe(module); - -#if defined(CONFIG_MODULE_UNLOAD) && defined(MODULE) - local_inc(&module->ref[get_cpu()].count); - put_cpu(); -#else - (void)try_module_get(module); -#endif -} - -static inline void __deprecated MOD_DEC_USE_COUNT(struct module *module) -{ - module_put(module); -} - -#define MOD_INC_USE_COUNT MOD_INC_USE_COUNT(THIS_MODULE) -#define MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT(THIS_MODULE) #else #define MODULE_PARM(var,type) -#define MOD_INC_USE_COUNT do { } while (0) -#define MOD_DEC_USE_COUNT do { } while (0) #endif #define __MODULE_STRING(x) __stringify(x) diff --git a/include/linux/mroute.h b/include/linux/mroute.h index e05d54a90..e11cd45a7 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -130,7 +130,7 @@ struct igmpmsg extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); -extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); +extern int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg); extern void ip_mr_init(void); diff --git a/include/linux/namei.h b/include/linux/namei.h index 4117cd90a..3d51a4ad1 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -10,12 +10,15 @@ struct open_intent { int create_mode; }; +enum { MAX_NESTED_LINKS = 5 }; + struct nameidata { struct dentry *dentry; struct vfsmount *mnt; struct qstr last; unsigned int flags; int last_type; + char *saved_names[MAX_NESTED_LINKS + 1]; /* Intent data */ union { @@ -41,6 +44,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_CONTINUE 4 #define LOOKUP_PARENT 16 #define LOOKUP_NOALT 32 +#define LOOKUP_ATOMIC 64 + /* * Intent data */ diff --git a/include/linux/namespace.h b/include/linux/namespace.h index fdd8abb07..ae9c17d6e 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -13,6 +13,7 @@ struct namespace { }; extern void umount_tree(struct vfsmount *); +extern void umount_unused(struct vfsmount *, struct fs_struct *); extern int copy_namespace(int, struct task_struct *); void __put_namespace(struct namespace *namespace); diff --git a/include/linux/net.h b/include/linux/net.h index a4684166d..1f531a9b5 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -60,6 +60,8 @@ typedef enum { #define SOCK_ASYNC_NOSPACE 0 #define SOCK_ASYNC_WAITDATA 1 #define SOCK_NOSPACE 2 +#define SOCK_PASS_CRED 16 +#define SOCK_USER_SOCKET 17 /** * struct socket - general BSD socket @@ -82,7 +84,6 @@ struct socket { struct sock *sk; wait_queue_head_t wait; short type; - unsigned char passcred; }; struct vm_area_struct; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a55f97a34..d2c25ff41 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -943,7 +943,7 @@ extern int weight_p; extern unsigned long netdev_fc_xoff; extern atomic_t netdev_dropping; extern int netdev_set_master(struct net_device *dev, struct net_device *master); -extern int skb_checksum_help(struct sk_buff **pskb, int inward); +extern struct sk_buff * skb_checksum_help(struct sk_buff *skb); #ifdef CONFIG_NET_FASTROUTE extern int netdev_fastroute; extern int netdev_fastroute_obstacles; diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b20c79258..1de5c779a 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -171,12 +171,6 @@ extern void nf_reinject(struct sk_buff *skb, struct nf_info *info, unsigned int verdict); -extern inline struct ipt_target * -ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex); -extern inline struct ip6t_target * -ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex); -extern inline struct arpt_target * -arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex); extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *); #ifdef CONFIG_NETFILTER_DEBUG diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0fd3f8178..6246101b6 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -306,7 +306,7 @@ nfs_file_cred(struct file *file) */ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, unsigned long); -extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, +extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos); extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos); diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 6bad4766d..b1a6f23b5 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -124,7 +124,8 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, int err; exp_get(exp); expkey_put(&ek->h, &svc_expkey_cache); - if ((err = cache_check(&svc_export_cache, &exp->h, reqp))) + if (exp && + (err = cache_check(&svc_export_cache, &exp->h, reqp))) exp = ERR_PTR(err); return exp; } else diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index e18185256..2997e2306 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -281,7 +281,7 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ - | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ + | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ diff --git a/include/linux/ninline.h b/include/linux/ninline.h new file mode 100644 index 000000000..d07fc8438 --- /dev/null +++ b/include/linux/ninline.h @@ -0,0 +1,159 @@ +#ifndef _NX_INLINE_H +#define _NX_INLINE_H + + +// #define NX_DEBUG + +#include +#include +#include + +#include "vserver/network.h" + +#if defined(NX_DEBUG) +#define nxdprintk(x...) printk("nxd: " x) +#else +#define nxdprintk(x...) +#endif + + +extern int proc_pid_nx_info(struct task_struct *, char *); + + +#define get_nx_info(i) __get_nx_info(i,__FILE__,__LINE__) + +static inline struct nx_info *__get_nx_info(struct nx_info *nxi, + const char *_file, int _line) +{ + if (!nxi) + return NULL; + nxdprintk("get_nx_info(%p[#%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0, + _file, _line); + atomic_inc(&nxi->nx_usecnt); + return nxi; +} + + +#define free_nx_info(nxi) \ + call_rcu(&nxi->nx_rcu, rcu_free_nx_info, nxi); + +#define put_nx_info(i) __put_nx_info(i,__FILE__,__LINE__) + +static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line) +{ + if (!nxi) + return; + nxdprintk("put_nx_info(%p[#%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0, + _file, _line); + if (atomic_dec_and_test(&nxi->nx_usecnt)) + free_nx_info(nxi); +} + + +#define set_nx_info(p,i) __set_nx_info(p,i,__FILE__,__LINE__) + +static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi, + const char *_file, int _line) +{ + BUG_ON(*nxp); + if (!nxi) + return; + nxdprintk("set_nx_info(%p[#%d.%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, + nxi?atomic_read(&nxi->nx_usecnt):0, + nxi?atomic_read(&nxi->nx_refcnt):0, + _file, _line); + atomic_inc(&nxi->nx_refcnt); + *nxp = __get_nx_info(nxi, _file, _line); +} + +#define clr_nx_info(p) __clr_nx_info(p,__FILE__,__LINE__) + +static inline void __clr_nx_info(struct nx_info **nxp, + const char *_file, int _line) +{ + struct nx_info *nxo = *nxp; + + if (!nxo) + return; + nxdprintk("clr_nx_info(%p[#%d.%d.%d])\t%s:%d\n", + nxo, nxo?nxo->nx_id:0, + nxo?atomic_read(&nxo->nx_usecnt):0, + nxo?atomic_read(&nxo->nx_refcnt):0, + _file, _line); + *nxp = NULL; + wmb(); + if (nxo && atomic_dec_and_test(&nxo->nx_refcnt)) + unhash_nx_info(nxo); + __put_nx_info(nxo, _file, _line); +} + + +#define task_get_nx_info(i) __task_get_nx_info(i,__FILE__,__LINE__) + +static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p, + const char *_file, int _line) +{ + struct nx_info *nxi; + + task_lock(p); + nxi = __get_nx_info(p->nx_info, _file, _line); + task_unlock(p); + return nxi; +} + +#define nx_verify_info(p,i) \ + __nx_verify_info((p)->nx_info,i,__FILE__,__LINE__) + +static __inline__ void __nx_verify_info( + struct nx_info *ipa, struct nx_info *ipb, + const char *_file, int _line) +{ + if (ipa == ipb) + return; + printk(KERN_ERR "ip bad assumption (%p==%p) at %s:%d\n", + ipa, ipb, _file, _line); +} + + +#define nx_task_nid(t) ((t)->nid) + +#define nx_current_nid() nx_task_nid(current) + +#define nx_check(c,m) __nx_check(nx_current_nid(),c,m) + +#define nx_weak_check(c,m) ((m) ? nx_check(c,m) : 1) + +#undef nxdprintk +#define nxdprintk(x...) + + +#define __nx_flags(v,m,f) (((v) & (m)) ^ (f)) + +#define __nx_task_flags(t,m,f) \ + (((t) && ((t)->nx_info)) ? \ + __nx_flags((t)->nx_info->nx_flags,(m),(f)) : 0) + +#define nx_current_flags() \ + ((current->nx_info) ? current->nx_info->nx_flags : 0) + +#define nx_flags(m,f) __nx_flags(nx_current_flags(),(m),(f)) + + +#define nx_current_ncaps() \ + ((current->nx_info) ? current->nx_info->nx_ncaps : 0) + +#define nx_ncaps(c) (nx_current_ncaps() & (c)) + + + +#define sock_nx_init(s) do { \ + (s)->sk_nid = 0; \ + (s)->sk_nx_info = NULL; \ + } while (0) + + + +#endif diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 1d376d042..40028bc59 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -133,16 +133,12 @@ struct page_state { unsigned long allocstall; /* direct reclaim calls */ unsigned long pgrotated; /* pages rotated to tail of the LRU */ -}; +} ____cacheline_aligned; DECLARE_PER_CPU(struct page_state, page_states); extern void get_page_state(struct page_state *ret); extern void get_full_page_state(struct page_state *ret); -extern unsigned long __read_page_state(unsigned offset); - -#define read_page_state(member) \ - __read_page_state(offsetof(struct page_state, member)) #define mod_page_state(member, delta) \ do { \ diff --git a/include/linux/pci.h b/include/linux/pci.h index 2662f462b..1eabe03c8 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -726,11 +726,11 @@ int pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); #define HAVE_PCI_SET_MWI -int pci_set_mwi(struct pci_dev *dev); +int __must_check pci_set_mwi(struct pci_dev *dev); void pci_clear_mwi(struct pci_dev *dev); -int pci_set_dma_mask(struct pci_dev *dev, u64 mask); +int __must_check pci_set_dma_mask(struct pci_dev *dev, u64 mask); int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); +int __must_check pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); int pci_assign_resource(struct pci_dev *dev, int i); /* Power management related routines */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2a1a53f90..b43a7f89f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -730,7 +730,6 @@ #define PCI_DEVICE_ID_TI_1410 0xac50 #define PCI_DEVICE_ID_TI_1420 0xac51 #define PCI_DEVICE_ID_TI_1451A 0xac52 -#define PCI_DEVICE_ID_TI_1620 0xac54 #define PCI_DEVICE_ID_TI_1520 0xac55 #define PCI_DEVICE_ID_TI_1510 0xac56 @@ -1854,11 +1853,8 @@ #define PCI_DEVICE_ID_TIGON3_5750 0x1676 #define PCI_DEVICE_ID_TIGON3_5751 0x1677 #define PCI_DEVICE_ID_TIGON3_5750M 0x167c -#define PCI_DEVICE_ID_TIGON3_5751M 0x167d -#define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5788 0x169c -#define PCI_DEVICE_ID_TIGON3_5789 0x169d #define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 #define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 diff --git a/include/linux/poll.h b/include/linux/poll.h index b4bb681fd..a44feb552 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -82,10 +82,14 @@ int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) } static inline -void set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) +int set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) { + int ret = 0; if (ufdset) - __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); + ret = __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); + if (ret) + return -EFAULT; + return 0; } static inline diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 2d439a839..3c3226075 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -55,6 +55,7 @@ struct proc_dir_entry { nlink_t nlink; uid_t uid; gid_t gid; + int vx_flags; unsigned long size; struct inode_operations * proc_iops; struct file_operations * proc_fops; @@ -237,9 +238,11 @@ extern struct kcore_list *kclist_del(void *); struct proc_inode { struct task_struct *task; int type; + int vx_flags; union { int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); int (*proc_read)(struct task_struct *task, char *page); + int (*proc_vid_read)(int vid, char *page); } op; struct proc_dir_entry *pde; struct inode vfs_inode; diff --git a/include/linux/proc_mm.h b/include/linux/proc_mm.h new file mode 100644 index 000000000..254f8b4b8 --- /dev/null +++ b/include/linux/proc_mm.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PROC_MM_H +#define __PROC_MM_H + +#include "linux/sched.h" + +#define MM_MMAP 54 +#define MM_MUNMAP 55 +#define MM_MPROTECT 56 +#define MM_COPY_SEGMENTS 57 + +struct mm_mmap { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +struct mm_munmap { + unsigned long addr; + unsigned long len; +}; + +struct mm_mprotect { + unsigned long addr; + unsigned long len; + unsigned int prot; +}; + +struct proc_mm_op { + int op; + union { + struct mm_mmap mmap; + struct mm_munmap munmap; + struct mm_mprotect mprotect; + int copy_segments; + } u; +}; + +extern struct mm_struct *proc_mm_get_mm(int fd); + +#endif diff --git a/include/linux/rcfs.h b/include/linux/rcfs.h new file mode 100644 index 000000000..a2a65e8a6 --- /dev/null +++ b/include/linux/rcfs.h @@ -0,0 +1,98 @@ +#ifndef _LINUX_RCFS_H +#define _LINUX_RCFS_H + +#include +#include +#include +#include +#include + + + +/* The following declarations cannot be included in any of ckrm*.h files without + jumping hoops. Remove later when rearrangements done */ + +// Hubertus .. taken out +//extern ckrm_res_callback_t ckrm_res_ctlrs[CKRM_MAX_RES_CTLRS]; + +#define RCFS_MAGIC 0x4feedbac +#define RCFS_MAGF_NAMELEN 20 +extern int RCFS_IS_MAGIC; + +#define rcfs_is_magic(dentry) ((dentry)->d_fsdata == &RCFS_IS_MAGIC) + +typedef struct rcfs_inode_info { + ckrm_core_class_t *core; + char *name; + struct inode vfs_inode; +} rcfs_inode_info_t; + +#define RCFS_DEFAULT_DIR_MODE (S_IFDIR | S_IRUGO | S_IXUGO) +#define RCFS_DEFAULT_FILE_MODE (S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP |S_IROTH) + + +struct rcfs_magf { + char name[RCFS_MAGF_NAMELEN]; + int mode; + struct inode_operations *i_op; + struct file_operations *i_fop; +}; + +struct rcfs_mfdesc { + struct rcfs_magf *rootmf; // Root directory and its magic files + int rootmflen; // length of above array + // Can have a different magf describing magic files for non-root entries too +}; + +extern struct rcfs_mfdesc *genmfdesc[]; + +inline struct rcfs_inode_info *RCFS_I(struct inode *inode); + +int rcfs_empty(struct dentry *); +struct inode *rcfs_get_inode(struct super_block *, int, dev_t); +int rcfs_mknod(struct inode *, struct dentry *, int, dev_t); +int _rcfs_mknod(struct inode *, struct dentry *, int , dev_t); +int rcfs_mkdir(struct inode *, struct dentry *, int); +ckrm_core_class_t *rcfs_make_core(struct dentry *, struct ckrm_core_class *); +struct dentry *rcfs_set_magf_byname(char *, void *); + +struct dentry * rcfs_create_internal(struct dentry *, struct rcfs_magf *, int); +int rcfs_delete_internal(struct dentry *); +int rcfs_create_magic(struct dentry *, struct rcfs_magf *, int); +int rcfs_clear_magic(struct dentry *); + + +extern struct super_operations rcfs_super_ops; +extern struct address_space_operations rcfs_aops; + +extern struct inode_operations rcfs_dir_inode_operations; +extern struct inode_operations rcfs_rootdir_inode_operations; +extern struct inode_operations rcfs_file_inode_operations; + + +extern struct file_operations target_fileops; +extern struct file_operations shares_fileops; +extern struct file_operations stats_fileops; +extern struct file_operations config_fileops; +extern struct file_operations members_fileops; +extern struct file_operations rcfs_file_operations; + +// Callbacks into rcfs from ckrm + +typedef struct rcfs_functions { + int (* mkroot)(struct rcfs_magf *,int, struct dentry **); + int (* rmroot)(struct dentry *); + int (* register_classtype)(ckrm_classtype_t *); + int (* deregister_classtype)(ckrm_classtype_t *); +} rcfs_fn_t; + +int rcfs_register_classtype(ckrm_classtype_t *); +int rcfs_deregister_classtype(ckrm_classtype_t *); +int rcfs_mkroot(struct rcfs_magf *, int , struct dentry **); +int rcfs_rmroot(struct dentry *); + +#define RCFS_ROOT "/rcfs" // Hubertus .. we should use the mount point instead of hardcoded +extern struct dentry *rcfs_rootde; + + +#endif /* _LINUX_RCFS_H */ diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 8132a6ec9..2eb4e7974 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -888,6 +888,13 @@ struct stat_data_v1 #define REISERFS_COMPR_FL EXT2_COMPR_FL #define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL +/* unfortunately reiserfs sdattr is only 16 bit */ +#define REISERFS_BARRIER_FL (EXT2_BARRIER_FL >> 16) +#define REISERFS_IUNLINK_FL (EXT2_IUNLINK_FL >> 16) + +#define REISERFS_FL_USER_VISIBLE 0x80FF +#define REISERFS_FL_USER_MODIFYABLE 0x80FF + /* persistent flags that file inherits from the parent directory */ #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ REISERFS_SYNC_FL | \ diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h new file mode 100644 index 000000000..2c52874ab --- /dev/null +++ b/include/linux/relayfs_fs.h @@ -0,0 +1,686 @@ +/* + * linux/include/linux/relayfs_fs.h + * + * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp + * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) + * + * RelayFS definitions and declarations + * + * Please see Documentation/filesystems/relayfs.txt for more info. + */ + +#ifndef _LINUX_RELAYFS_FS_H +#define _LINUX_RELAYFS_FS_H + +#include +#include +#include +#include +#include +#include + +/* + * Tracks changes to rchan struct + */ +#define RELAYFS_CHANNEL_VERSION 1 + +/* + * Maximum number of simultaneously open channels + */ +#define RELAY_MAX_CHANNELS 256 + +/* + * Relay properties + */ +#define RELAY_MIN_BUFS 2 +#define RELAY_MIN_BUFSIZE 4096 +#define RELAY_MAX_BUFS 256 +#define RELAY_MAX_BUF_SIZE 0x1000000 +#define RELAY_MAX_TOTAL_BUF_SIZE 0x8000000 + +/* + * Lockless scheme utility macros + */ +#define RELAY_MAX_BUFNO(bufno_bits) (1UL << (bufno_bits)) +#define RELAY_BUF_SIZE(offset_bits) (1UL << (offset_bits)) +#define RELAY_BUF_OFFSET_MASK(offset_bits) (RELAY_BUF_SIZE(offset_bits) - 1) +#define RELAY_BUFNO_GET(index, offset_bits) ((index) >> (offset_bits)) +#define RELAY_BUF_OFFSET_GET(index, mask) ((index) & (mask)) +#define RELAY_BUF_OFFSET_CLEAR(index, mask) ((index) & ~(mask)) + +/* + * Flags returned by relay_reserve() + */ +#define RELAY_BUFFER_SWITCH_NONE 0x0 +#define RELAY_WRITE_DISCARD_NONE 0x0 +#define RELAY_BUFFER_SWITCH 0x1 +#define RELAY_WRITE_DISCARD 0x2 +#define RELAY_WRITE_TOO_LONG 0x4 + +/* + * Relay attribute flags + */ +#define RELAY_DELIVERY_BULK 0x1 +#define RELAY_DELIVERY_PACKET 0x2 +#define RELAY_SCHEME_LOCKLESS 0x4 +#define RELAY_SCHEME_LOCKING 0x8 +#define RELAY_SCHEME_ANY 0xC +#define RELAY_TIMESTAMP_TSC 0x10 +#define RELAY_TIMESTAMP_GETTIMEOFDAY 0x20 +#define RELAY_TIMESTAMP_ANY 0x30 +#define RELAY_USAGE_SMP 0x40 +#define RELAY_USAGE_GLOBAL 0x80 +#define RELAY_MODE_CONTINUOUS 0x100 +#define RELAY_MODE_NO_OVERWRITE 0x200 + +/* + * Flags for needs_resize() callback + */ +#define RELAY_RESIZE_NONE 0x0 +#define RELAY_RESIZE_EXPAND 0x1 +#define RELAY_RESIZE_SHRINK 0x2 +#define RELAY_RESIZE_REPLACE 0x4 +#define RELAY_RESIZE_REPLACED 0x8 + +/* + * Values for fileop_notify() callback + */ +enum relay_fileop +{ + RELAY_FILE_OPEN, + RELAY_FILE_CLOSE, + RELAY_FILE_MAP, + RELAY_FILE_UNMAP +}; + +/* + * Data structure returned by relay_info() + */ +struct rchan_info +{ + u32 flags; /* relay attribute flags for channel */ + u32 buf_size; /* channel's sub-buffer size */ + char *buf_addr; /* address of channel start */ + u32 alloc_size; /* total buffer size actually allocated */ + u32 n_bufs; /* number of sub-buffers in channel */ + u32 cur_idx; /* current write index into channel */ + u32 bufs_produced; /* current count of sub-buffers produced */ + u32 bufs_consumed; /* current count of sub-buffers consumed */ + u32 buf_id; /* buf_id of current sub-buffer */ + int buffer_complete[RELAY_MAX_BUFS]; /* boolean per sub-buffer */ + int unused_bytes[RELAY_MAX_BUFS]; /* count per sub-buffer */ +}; + +/* + * Relay channel client callbacks + */ +struct rchan_callbacks +{ + /* + * buffer_start - called at the beginning of a new sub-buffer + * @rchan_id: the channel id + * @current_write_pos: position in sub-buffer client should write to + * @buffer_id: the id of the new sub-buffer + * @start_time: the timestamp associated with the start of sub-buffer + * @start_tsc: the TSC associated with the timestamp, if using_tsc + * @using_tsc: boolean, indicates whether start_tsc is valid + * + * Return value should be the number of bytes written by the client. + * + * See Documentation/filesystems/relayfs.txt for details. + */ + int (*buffer_start) (int rchan_id, + char *current_write_pos, + u32 buffer_id, + struct timeval start_time, + u32 start_tsc, + int using_tsc); + + /* + * buffer_end - called at the end of a sub-buffer + * @rchan_id: the channel id + * @current_write_pos: position in sub-buffer of end of data + * @end_of_buffer: the position of the end of the sub-buffer + * @end_time: the timestamp associated with the end of the sub-buffer + * @end_tsc: the TSC associated with the end_time, if using_tsc + * @using_tsc: boolean, indicates whether end_tsc is valid + * + * Return value should be the number of bytes written by the client. + * + * See Documentation/filesystems/relayfs.txt for details. + */ + int (*buffer_end) (int rchan_id, + char *current_write_pos, + char *end_of_buffer, + struct timeval end_time, + u32 end_tsc, + int using_tsc); + + /* + * deliver - called when data is ready for the client + * @rchan_id: the channel id + * @from: the start of the delivered data + * @len: the length of the delivered data + * + * See Documentation/filesystems/relayfs.txt for details. + */ + void (*deliver) (int rchan_id, char *from, u32 len); + + /* + * user_deliver - called when data has been written from userspace + * @rchan_id: the channel id + * @from: the start of the delivered data + * @len: the length of the delivered data + * + * See Documentation/filesystems/relayfs.txt for details. + */ + void (*user_deliver) (int rchan_id, char *from, u32 len); + + /* + * needs_resize - called when a resizing event occurs + * @rchan_id: the channel id + * @resize_type: the type of resizing event + * @suggested_buf_size: the suggested new sub-buffer size + * @suggested_buf_size: the suggested new number of sub-buffers + * + * See Documentation/filesystems/relayfs.txt for details. + */ + void (*needs_resize)(int rchan_id, + int resize_type, + u32 suggested_buf_size, + u32 suggested_n_bufs); + + /* + * fileop_notify - called on open/close/mmap/munmap of a relayfs file + * @rchan_id: the channel id + * @filp: relayfs file pointer + * @fileop: which file operation is in progress + * + * The return value can direct the outcome of the operation. + * + * See Documentation/filesystems/relayfs.txt for details. + */ + int (*fileop_notify)(int rchan_id, + struct file *filp, + enum relay_fileop fileop); + + /* + * ioctl - called in ioctl context from userspace + * @rchan_id: the channel id + * @cmd: ioctl cmd + * @arg: ioctl cmd arg + * + * The return value is returned as the value from the ioctl call. + * + * See Documentation/filesystems/relayfs.txt for details. + */ + int (*ioctl) (int rchan_id, unsigned int cmd, unsigned long arg); +}; + +/* + * Lockless scheme-specific data + */ +struct lockless_rchan +{ + u8 bufno_bits; /* # bits used for sub-buffer id */ + u8 offset_bits; /* # bits used for offset within sub-buffer */ + u32 index; /* current index = sub-buffer id and offset */ + u32 offset_mask; /* used to obtain offset portion of index */ + u32 index_mask; /* used to mask off unused bits index */ + atomic_t fill_count[RELAY_MAX_BUFS]; /* fill count per sub-buffer */ +}; + +/* + * Locking scheme-specific data + */ +struct locking_rchan +{ + char *write_buf; /* start of write sub-buffer */ + char *write_buf_end; /* end of write sub-buffer */ + char *current_write_pos; /* current write pointer */ + char *write_limit; /* takes reserves into account */ + char *in_progress_event_pos; /* used for interrupted writes */ + u16 in_progress_event_size; /* used for interrupted writes */ + char *interrupted_pos; /* used for interrupted writes */ + u16 interrupting_size; /* used for interrupted writes */ + spinlock_t lock; /* channel lock for locking scheme */ +}; + +struct relay_ops; + +/* + * Offset resizing data structure + */ +struct resize_offset +{ + u32 ge; + u32 le; + int delta; +}; + +/* + * Relay channel data structure + */ +struct rchan +{ + u32 version; /* the version of this struct */ + char *buf; /* the channel buffer */ + union + { + struct lockless_rchan lockless; + struct locking_rchan locking; + } scheme; /* scheme-specific channel data */ + + int id; /* the channel id */ + struct rchan_callbacks *callbacks; /* client callbacks */ + u32 flags; /* relay channel attributes */ + u32 buf_id; /* current sub-buffer id */ + u32 buf_idx; /* current sub-buffer index */ + + atomic_t mapped; /* map count */ + + atomic_t suspended; /* channel suspended i.e full? */ + int half_switch; /* used internally for suspend */ + + struct timeval buf_start_time; /* current sub-buffer start time */ + u32 buf_start_tsc; /* current sub-buffer start TSC */ + + u32 buf_size; /* sub-buffer size */ + u32 alloc_size; /* total buffer size allocated */ + u32 n_bufs; /* number of sub-buffers */ + + u32 bufs_produced; /* count of sub-buffers produced */ + u32 bufs_consumed; /* count of sub-buffers consumed */ + u32 bytes_consumed; /* bytes consumed in cur sub-buffer */ + + int initialized; /* first buffer initialized? */ + int finalized; /* channel finalized? */ + + u32 start_reserve; /* reserve at start of sub-buffers */ + u32 end_reserve; /* reserve at end of sub-buffers */ + u32 rchan_start_reserve; /* additional reserve sub-buffer 0 */ + + struct dentry *dentry; /* channel file dentry */ + + wait_queue_head_t read_wait; /* VFS read wait queue */ + wait_queue_head_t write_wait; /* VFS write wait queue */ + struct work_struct wake_readers; /* reader wake-up work struct */ + struct work_struct wake_writers; /* reader wake-up work struct */ + atomic_t refcount; /* channel refcount */ + + struct relay_ops *relay_ops; /* scheme-specific channel ops */ + + int unused_bytes[RELAY_MAX_BUFS]; /* unused count per sub-buffer */ + + struct semaphore resize_sem; /* serializes alloc/repace */ + struct work_struct work; /* resize allocation work struct */ + + struct list_head open_readers; /* open readers for this channel */ + rwlock_t open_readers_lock; /* protection for open_readers list */ + + char *init_buf; /* init channel buffer, if non-NULL */ + + u32 resize_min; /* minimum resized total buffer size */ + u32 resize_max; /* maximum resized total buffer size */ + char *resize_buf; /* for autosize alloc/free */ + u32 resize_buf_size; /* resized sub-buffer size */ + u32 resize_n_bufs; /* resized number of sub-buffers */ + u32 resize_alloc_size; /* resized actual total size */ + int resizing; /* is resizing in progress? */ + int resize_err; /* resizing err code */ + int resize_failures; /* number of resize failures */ + int replace_buffer; /* is the alloced buffer ready? */ + struct resize_offset resize_offset; /* offset change */ + struct timer_list shrink_timer; /* timer used for shrinking */ + int resize_order; /* size of last resize */ + u32 expand_buf_id; /* subbuf id expand will occur at */ + + struct page **buf_page_array; /* array of current buffer pages */ + int buf_page_count; /* number of current buffer pages */ + struct page **expand_page_array;/* new pages to be inserted */ + int expand_page_count; /* number of new pages */ + struct page **shrink_page_array;/* old pages to be freed */ + int shrink_page_count; /* number of old pages */ + struct page **resize_page_array;/* will become current pages */ + int resize_page_count; /* number of resize pages */ + struct page **old_buf_page_array; /* hold for freeing */ +} ____cacheline_aligned; + +/* + * Relay channel reader struct + */ +struct rchan_reader +{ + struct list_head list; /* for list inclusion */ + struct rchan *rchan; /* the channel we're reading from */ + int auto_consume; /* does this reader auto-consume? */ + u32 bufs_consumed; /* buffers this reader has consumed */ + u32 bytes_consumed; /* bytes consumed in cur sub-buffer */ + int offset_changed; /* have channel offsets changed? */ + int vfs_reader; /* are we a VFS reader? */ + int map_reader; /* are we an mmap reader? */ + + union + { + struct file *file; + u32 f_pos; + } pos; /* current read offset */ +}; + +/* + * These help make union member access less tedious + */ +#define channel_buffer(rchan) ((rchan)->buf) +#define idx(rchan) ((rchan)->scheme.lockless.index) +#define bufno_bits(rchan) ((rchan)->scheme.lockless.bufno_bits) +#define offset_bits(rchan) ((rchan)->scheme.lockless.offset_bits) +#define offset_mask(rchan) ((rchan)->scheme.lockless.offset_mask) +#define idx_mask(rchan) ((rchan)->scheme.lockless.index_mask) +#define bulk_delivery(rchan) (((rchan)->flags & RELAY_DELIVERY_BULK) ? 1 : 0) +#define packet_delivery(rchan) (((rchan)->flags & RELAY_DELIVERY_PACKET) ? 1 : 0) +#define using_lockless(rchan) (((rchan)->flags & RELAY_SCHEME_LOCKLESS) ? 1 : 0) +#define using_locking(rchan) (((rchan)->flags & RELAY_SCHEME_LOCKING) ? 1 : 0) +#define using_tsc(rchan) (((rchan)->flags & RELAY_TIMESTAMP_TSC) ? 1 : 0) +#define using_gettimeofday(rchan) (((rchan)->flags & RELAY_TIMESTAMP_GETTIMEOFDAY) ? 1 : 0) +#define usage_smp(rchan) (((rchan)->flags & RELAY_USAGE_SMP) ? 1 : 0) +#define usage_global(rchan) (((rchan)->flags & RELAY_USAGE_GLOBAL) ? 1 : 0) +#define mode_continuous(rchan) (((rchan)->flags & RELAY_MODE_CONTINUOUS) ? 1 : 0) +#define fill_count(rchan, i) ((rchan)->scheme.lockless.fill_count[(i)]) +#define write_buf(rchan) ((rchan)->scheme.locking.write_buf) +#define read_buf(rchan) ((rchan)->scheme.locking.read_buf) +#define write_buf_end(rchan) ((rchan)->scheme.locking.write_buf_end) +#define read_buf_end(rchan) ((rchan)->scheme.locking.read_buf_end) +#define cur_write_pos(rchan) ((rchan)->scheme.locking.current_write_pos) +#define read_limit(rchan) ((rchan)->scheme.locking.read_limit) +#define write_limit(rchan) ((rchan)->scheme.locking.write_limit) +#define in_progress_event_pos(rchan) ((rchan)->scheme.locking.in_progress_event_pos) +#define in_progress_event_size(rchan) ((rchan)->scheme.locking.in_progress_event_size) +#define interrupted_pos(rchan) ((rchan)->scheme.locking.interrupted_pos) +#define interrupting_size(rchan) ((rchan)->scheme.locking.interrupting_size) +#define channel_lock(rchan) ((rchan)->scheme.locking.lock) + + +/** + * calc_time_delta - utility function for time delta calculation + * @now: current time + * @start: start time + * + * Returns the time delta produced by subtracting start time from now. + */ +static inline u32 +calc_time_delta(struct timeval *now, + struct timeval *start) +{ + return (now->tv_sec - start->tv_sec) * 1000000 + + (now->tv_usec - start->tv_usec); +} + +/** + * recalc_time_delta - utility function for time delta recalculation + * @now: current time + * @new_delta: the new time delta calculated + * @cpu: the associated CPU id + */ +static inline void +recalc_time_delta(struct timeval *now, + u32 *new_delta, + struct rchan *rchan) +{ + if (using_tsc(rchan) == 0) + *new_delta = calc_time_delta(now, &rchan->buf_start_time); +} + +/** + * have_cmpxchg - does this architecture have a cmpxchg? + * + * Returns 1 if this architecture has a cmpxchg useable by + * the lockless scheme, 0 otherwise. + */ +static inline int +have_cmpxchg(void) +{ +#if defined(__HAVE_ARCH_CMPXCHG) + return 1; +#else + return 0; +#endif +} + +/** + * relay_write_direct - write data directly into destination buffer + */ +#define relay_write_direct(DEST, SRC, SIZE) \ +do\ +{\ + memcpy(DEST, SRC, SIZE);\ + DEST += SIZE;\ +} while (0); + +/** + * relay_lock_channel - lock the relay channel if applicable + * + * This macro only affects the locking scheme. If the locking scheme + * is in use and the channel usage is SMP, does a local_irq_save. If the + * locking sheme is in use and the channel usage is GLOBAL, uses + * spin_lock_irqsave. FLAGS is initialized to 0 since we know that + * it is being initialized prior to use and we avoid the compiler warning. + */ +#define relay_lock_channel(RCHAN, FLAGS) \ +do\ +{\ + FLAGS = 0;\ + if (using_locking(RCHAN)) {\ + if (usage_smp(RCHAN)) {\ + local_irq_save(FLAGS); \ + } else {\ + spin_lock_irqsave(&(RCHAN)->scheme.locking.lock, FLAGS); \ + }\ + }\ +} while (0); + +/** + * relay_unlock_channel - unlock the relay channel if applicable + * + * This macro only affects the locking scheme. See relay_lock_channel. + */ +#define relay_unlock_channel(RCHAN, FLAGS) \ +do\ +{\ + if (using_locking(RCHAN)) {\ + if (usage_smp(RCHAN)) {\ + local_irq_restore(FLAGS); \ + } else {\ + spin_unlock_irqrestore(&(RCHAN)->scheme.locking.lock, FLAGS); \ + }\ + }\ +} while (0); + +/* + * Define cmpxchg if we don't have it + */ +#ifndef __HAVE_ARCH_CMPXCHG +#define cmpxchg(p,o,n) 0 +#endif + +/* + * High-level relayfs kernel API, fs/relayfs/relay.c + */ +extern int +relay_open(const char *chanpath, + int bufsize, + int nbufs, + u32 flags, + struct rchan_callbacks *channel_callbacks, + u32 start_reserve, + u32 end_reserve, + u32 rchan_start_reserve, + u32 resize_min, + u32 resize_max, + int mode, + char *init_buf, + u32 init_buf_size); + +extern int +relay_close(int rchan_id); + +extern int +relay_write(int rchan_id, + const void *data_ptr, + size_t count, + int td_offset, + void **wrote_pos); + +extern ssize_t +relay_read(struct rchan_reader *reader, + char *buf, + size_t count, + int wait, + u32 *actual_read_offset); + +extern int +relay_discard_init_buf(int rchan_id); + +extern struct rchan_reader * +add_rchan_reader(int rchan_id, int autoconsume); + +extern int +remove_rchan_reader(struct rchan_reader *reader); + +extern struct rchan_reader * +add_map_reader(int rchan_id); + +extern int +remove_map_reader(struct rchan_reader *reader); + +extern int +relay_info(int rchan_id, struct rchan_info *rchan_info); + +extern void +relay_buffers_consumed(struct rchan_reader *reader, u32 buffers_consumed); + +extern void +relay_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset); + +extern ssize_t +relay_bytes_avail(struct rchan_reader *reader); + +extern int +relay_realloc_buffer(int rchan_id, u32 new_nbufs, int in_background); + +extern int +relay_replace_buffer(int rchan_id); + +extern int +rchan_empty(struct rchan_reader *reader); + +extern int +rchan_full(struct rchan_reader *reader); + +extern void +update_readers_consumed(struct rchan *rchan, u32 bufs_consumed, u32 bytes_consumed); + +extern int +__relay_mmap_buffer(struct rchan *rchan, struct vm_area_struct *vma); + +extern struct rchan_reader * +__add_rchan_reader(struct rchan *rchan, struct file *filp, int auto_consume, int map_reader); + +extern void +__remove_rchan_reader(struct rchan_reader *reader); + +/* + * Low-level relayfs kernel API, fs/relayfs/relay.c + */ +extern struct rchan * +rchan_get(int rchan_id); + +extern void +rchan_put(struct rchan *rchan); + +extern char * +relay_reserve(struct rchan *rchan, + u32 data_len, + struct timeval *time_stamp, + u32 *time_delta, + int *errcode, + int *interrupting); + +extern void +relay_commit(struct rchan *rchan, + char *from, + u32 len, + int reserve_code, + int interrupting); + +extern u32 +relay_get_offset(struct rchan *rchan, u32 *max_offset); + +extern int +relay_reset(int rchan_id); + +/* + * VFS functions, fs/relayfs/inode.c + */ +extern int +relayfs_create_dir(const char *name, + struct dentry *parent, + struct dentry **dentry); + +extern int +relayfs_create_file(const char * name, + struct dentry *parent, + struct dentry **dentry, + void * data, + int mode); + +extern int +relayfs_remove_file(struct dentry *dentry); + +extern int +reset_index(struct rchan *rchan, u32 old_index); + + +/* + * klog functions, fs/relayfs/klog.c + */ +extern int +create_klog_channel(void); + +extern int +remove_klog_channel(void); + +/* + * Scheme-specific channel ops + */ +struct relay_ops +{ + char * (*reserve) (struct rchan *rchan, + u32 slot_len, + struct timeval *time_stamp, + u32 *tsc, + int * errcode, + int * interrupting); + + void (*commit) (struct rchan *rchan, + char *from, + u32 len, + int deliver, + int interrupting); + + u32 (*get_offset) (struct rchan *rchan, + u32 *max_offset); + + void (*resume) (struct rchan *rchan); + void (*finalize) (struct rchan *rchan); + void (*reset) (struct rchan *rchan, + int init); + int (*reset_index) (struct rchan *rchan, + u32 old_index); +}; + +#endif /* _LINUX_RELAYFS_FS_H */ + + + + + diff --git a/include/linux/resource.h b/include/linux/resource.h index 94494789e..f43560d88 100644 --- a/include/linux/resource.h +++ b/include/linux/resource.h @@ -52,8 +52,11 @@ struct rlimit { /* * Limit the stack by to some sane default: root can always * increase this limit if needed.. 8MB seems reasonable. + * + * (2MB more to cover randomization effects.) */ -#define _STK_LIM (8*1024*1024) +#define _STK_LIM (10*1024*1024) +#define EXEC_STACK_BIAS (2*1024*1024) /* * Due to binary compatibility, the actual resource numbers diff --git a/include/linux/sched.h b/include/linux/sched.h index 6d8d111ec..fa44ce4f3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -31,6 +31,9 @@ #include struct exec_domain; +extern int exec_shield; +extern int exec_shield_randomize; +extern int print_fatal_signals; /* * cloning flags: @@ -102,6 +105,7 @@ extern unsigned long nr_iowait(void); #include #include +#include #define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 @@ -109,6 +113,7 @@ extern unsigned long nr_iowait(void); #define TASK_STOPPED 4 #define TASK_ZOMBIE 8 #define TASK_DEAD 16 +#define TASK_ONHOLD 32 #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) @@ -133,6 +138,7 @@ struct sched_param { #ifdef __KERNEL__ +#include #include /* @@ -196,6 +202,8 @@ struct mm_struct { struct rb_root mm_rb; struct vm_area_struct * mmap_cache; /* last find_vma result */ unsigned long free_area_cache; /* first hole */ + unsigned long non_executable_cache; /* last hole top */ + unsigned long mmap_top; /* top of mmap area */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ @@ -224,6 +232,7 @@ struct mm_struct { /* Architecture-specific MM context */ mm_context_t context; + struct vx_info *mm_vx_info; /* coredumping support */ int core_waiters; @@ -318,9 +327,10 @@ struct user_struct { /* Hash table maintenance information */ struct list_head uidhash_list; uid_t uid; + xid_t xid; }; -extern struct user_struct *find_user(uid_t); +extern struct user_struct *find_user(xid_t, uid_t); extern struct user_struct root_user; #define INIT_USER (&root_user) @@ -481,10 +491,23 @@ struct task_struct { int (*notifier)(void *priv); void *notifier_data; sigset_t *notifier_mask; + + /* TUX state */ + void *tux_info; + void (*tux_exit)(void); + void *security; struct audit_context *audit_context; +/* vserver context data */ + xid_t xid; + struct vx_info *vx_info; + +/* vserver network data */ + nid_t nid; + struct nx_info *nx_info; + /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; @@ -513,6 +536,18 @@ struct task_struct { struct mempolicy *mempolicy; short il_next; /* could be shared with used_math */ #endif + +#ifdef CONFIG_CKRM + spinlock_t ckrm_tsklock; + void *ce_data; +#ifdef CONFIG_CKRM_TYPE_TASKCLASS + // .. Hubertus should change to CONFIG_CKRM_TYPE_TASKCLASS + struct ckrm_task_class *taskclass; + struct list_head taskclass_link; +#endif // CONFIG_CKRM_TYPE_TASKCLASS +#endif // CONFIG_CKRM + + struct task_delay_info delays; }; static inline pid_t process_group(struct task_struct *tsk) @@ -549,6 +584,11 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_SWAPOFF 0x00080000 /* I am in swapoff */ #define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */ #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ +#define PF_RELOCEXEC 0x00400000 /* relocate shared libraries */ + + +#define PF_MEMIO 0x00400000 /* I am potentially doing I/O for mem */ +#define PF_IOWAIT 0x00800000 /* I am waiting on disk I/O */ #ifdef CONFIG_SMP #define SCHED_LOAD_SCALE 128UL /* increase resolution of load */ @@ -718,7 +758,7 @@ extern void set_special_pids(pid_t session, pid_t pgrp); extern void __set_special_pids(pid_t session, pid_t pgrp); /* per-UID process charging. */ -extern struct user_struct * alloc_uid(uid_t); +extern struct user_struct * alloc_uid(xid_t, uid_t); extern void free_uid(struct user_struct *); extern void switch_uid(struct user_struct *); @@ -738,7 +778,7 @@ extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk)); static inline void kick_process(struct task_struct *tsk) { } static inline void wake_up_forked_thread(struct task_struct * tsk) { - wake_up_forked_process(tsk); + return wake_up_forked_process(tsk); } #endif extern void FASTCALL(sched_fork(task_t * p)); @@ -1067,6 +1107,60 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) #endif /* CONFIG_SMP */ + +/* API for registering delay info */ +#ifdef CONFIG_DELAY_ACCT + +#define test_delay_flag(tsk,flg) ((tsk)->flags & (flg)) +#define set_delay_flag(tsk,flg) ((tsk)->flags |= (flg)) +#define clear_delay_flag(tsk,flg) ((tsk)->flags &= ~(flg)) + +#define def_delay_var(var) unsigned long long var +#define get_delay(tsk,field) ((tsk)->delays.field) +#define delay_value(x) (((unsigned long)(x))/1000) + +#define start_delay(var) ((var) = sched_clock()) +#define start_delay_set(var,flg) (set_delay_flag(current,flg),(var) = sched_clock()) + +#define inc_delay(tsk,field) (((tsk)->delays.field)++) +#define add_delay_ts(tsk,field,start_ts,end_ts) ((tsk)->delays.field += delay_value((end_ts)-(start_ts))) +#define add_delay_clear(tsk,field,start_ts,flg) (add_delay_ts(tsk,field,start_ts,sched_clock()),clear_delay_flag(tsk,flg)) + +static inline void add_io_delay(unsigned long dstart) +{ + struct task_struct * tsk = current; + unsigned long val = delay_value(sched_clock()-dstart); + if (test_delay_flag(tsk,PF_MEMIO)) { + tsk->delays.mem_iowait_total += val; + tsk->delays.num_memwaits++; + } else { + tsk->delays.iowait_total += val; + tsk->delays.num_iowaits++; + } + clear_delay_flag(tsk,PF_IOWAIT); +} + + +#else + +#define test_delay_flag(tsk,flg) (0) +#define set_delay_flag(tsk,flg) do { } while (0) +#define clear_delay_flag(tsk,flg) do { } while (0) + +#define def_delay_var(var) +#define get_delay(tsk,field) (0) + +#define start_delay(var) do { } while (0) +#define start_delay_set(var,flg) do { } while (0) + +#define inc_delay(tsk,field) do { } while (0) +#define add_delay_ts(tsk,field,start_ts,now) do { } while (0) +#define add_delay_clear(tsk,field,start_ts,flg) do { } while (0) +#define add_io_delay(dstart) do { } while (0) +#endif + + + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7bf6501a9..b29326a03 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1038,6 +1038,8 @@ extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_init(void); extern void skb_add_mtu(int mtu); +struct tux_req_struct; + #ifdef CONFIG_NETFILTER static inline void nf_conntrack_put(struct nf_ct_info *nfct) { diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 9a20995c5..803315fce 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h @@ -5,7 +5,9 @@ #include #include -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) +#define BKL_DEBUG /* For testing for sleep_on() abuse */ + +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) || defined(BKL_DEBUG) extern spinlock_t kernel_flag; diff --git a/include/linux/socket.h b/include/linux/socket.h index 3a18d6e0a..4cd4850d7 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -288,6 +288,11 @@ extern int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __us extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); +struct socket; +struct file * sock_map_file(struct socket *sock); +extern int sock_map_fd(struct socket *sock); +extern struct socket *sockfd_lookup(int fd, int *err); + #endif #endif /* not kernel and not glibc */ #endif /* _LINUX_SOCKET_H */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index ef193874f..a7fea38ae 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -165,8 +165,7 @@ asmlinkage long sys_wait4(pid_t pid, unsigned int __user *stat_addr, asmlinkage long sys_waitpid(pid_t pid, unsigned int __user *stat_addr, int options); asmlinkage long sys_set_tid_address(int __user *tidptr); asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, - struct timespec __user *utime, u32 __user *uaddr2, - int val3); + struct timespec __user *utime, u32 __user *uaddr2); asmlinkage long sys_init_module(void __user *umod, unsigned long len, const char __user *uargs); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index f70f7fc14..0c923ca54 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -133,6 +133,7 @@ enum KERN_NGROUPS_MAX=63, /* int: NGROUPS_MAX */ KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */ KERN_HZ_TIMER=65, /* int: hz timer on or off */ + KERN_VSHELPER=66, /* string: path to vshelper policy agent */ }; @@ -163,7 +164,6 @@ enum VM_MAX_MAP_COUNT=22, /* int: Maximum number of mmaps/address-space */ VM_LAPTOP_MODE=23, /* vm laptop mode */ VM_BLOCK_DUMP=24, /* block dump mode */ - VM_HUGETLB_GROUP=25, /* permitted hugetlb group */ }; @@ -187,6 +187,7 @@ enum NET_DECNET=15, NET_ECONET=16, NET_SCTP=17, + NET_TUX=18, }; /* /proc/sys/kernel/random */ @@ -625,6 +626,55 @@ enum { NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4, }; +/* /proc/sys/net/tux/ */ +enum { + NET_TUX_DOCROOT = 1, + NET_TUX_LOGFILE = 2, + NET_TUX_EXTCGI = 3, + NET_TUX_STOP = 4, + NET_TUX_CLIENTPORT = 5, + NET_TUX_LOGGING = 6, + NET_TUX_SERVERPORT = 7, + NET_TUX_THREADS = 8, + NET_TUX_KEEPALIVE_TIMEOUT = 9, + NET_TUX_MAX_KEEPALIVE_BW = 10, + NET_TUX_DEFER_ACCEPT = 11, + NET_TUX_MAX_FREE_REQUESTS = 12, + NET_TUX_MAX_CONNECT = 13, + NET_TUX_MAX_BACKLOG = 14, + NET_TUX_MODE_FORBIDDEN = 15, + NET_TUX_MODE_ALLOWED = 16, + NET_TUX_MODE_USERSPACE = 17, + NET_TUX_MODE_CGI = 18, + NET_TUX_CGI_UID = 19, + NET_TUX_CGI_GID = 20, + NET_TUX_CGIROOT = 21, + NET_TUX_LOGENTRY_ALIGN_ORDER = 22, + NET_TUX_NONAGLE = 23, + NET_TUX_ACK_PINGPONG = 24, + NET_TUX_PUSH_ALL = 25, + NET_TUX_ZEROCOPY_PARSE = 26, + NET_CONFIG_TUX_DEBUG_BLOCKING = 27, + NET_TUX_PAGE_AGE_START = 28, + NET_TUX_PAGE_AGE_ADV = 29, + NET_TUX_PAGE_AGE_MAX = 30, + NET_TUX_VIRTUAL_SERVER = 31, + NET_TUX_MAX_OBJECT_SIZE = 32, + NET_TUX_COMPRESSION = 33, + NET_TUX_NOID = 34, + NET_TUX_CGI_INHERIT_CPU = 35, + NET_TUX_CGI_CPU_MASK = 36, + NET_TUX_ZEROCOPY_HEADER = 37, + NET_TUX_ZEROCOPY_SENDFILE = 38, + NET_TUX_ALL_USERSPACE = 39, + NET_TUX_REDIRECT_LOGGING = 40, + NET_TUX_REFERER_LOGGING = 41, + NET_TUX_MAX_HEADER_LEN = 42, + NET_TUX_404_PAGE = 43, + NET_TUX_MAX_KEEPALIVES = 44, + NET_TUX_IGNORE_QUERY = 45, +}; + /* CTL_PROC names: */ /* CTL_FS names: */ diff --git a/include/linux/taskdelays.h b/include/linux/taskdelays.h new file mode 100644 index 000000000..698b23b61 --- /dev/null +++ b/include/linux/taskdelays.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_TASKDELAYS_H +#define _LINUX_TASKDELAYS_H + +#include + +struct task_delay_info { +#ifdef CONFIG_DELAY_ACCT + /* delay statistics in usecs */ + unsigned long runs; + unsigned long waitcpu_total; + unsigned long runcpu_total; + unsigned long iowait_total; + unsigned long mem_iowait_total; + unsigned long num_iowaits; + unsigned long num_memwaits; +#endif +}; + +#endif // _LINUX_TASKDELAYS_H + diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 39e2d2261..eae8b73f7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -128,6 +128,10 @@ enum { #define TCP_INFO 11 /* Information about this connection. */ #define TCP_QUICKACK 12 /* Block/reenable quick acks */ +#ifdef CONFIG_ACCEPT_QUEUES +#define TCP_ACCEPTQ_SHARE 13 /* Set accept queue share */ +#endif + #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 #define TCPI_OPT_WSCALE 4 @@ -183,10 +187,19 @@ struct tcp_info __u32 tcpi_snd_cwnd; __u32 tcpi_advmss; __u32 tcpi_reordering; +}; - __u32 tcpi_rcv_rtt; - __u32 tcpi_rcv_space; +#ifdef CONFIG_ACCEPT_QUEUES + +#define NUM_ACCEPT_QUEUES 8 /* Must be power of 2 */ + +struct tcp_acceptq_info { + unsigned char acceptq_shares; + unsigned long acceptq_wait_time; + unsigned int acceptq_qcount; + unsigned int acceptq_count; }; +#endif #ifdef __KERNEL__ @@ -354,11 +367,11 @@ struct tcp_opt { __u8 urg_mode; /* In urgent mode */ __u32 snd_up; /* Urgent pointer */ - /* The syn_wait_lock is necessary only to avoid proc interface having + /* The syn_wait_lock is necessary only to avoid tcp_get_info having * to grab the main lock sock while browsing the listening hash * (otherwise it's deadlock prone). - * This lock is acquired in read mode only from listening_get_next() - * and it's acquired in write mode _only_ from code that is actively + * This lock is acquired in read mode only from tcp_get_info() and + * it's acquired in write mode _only_ from code that is actively * changing the syn_wait_queue. All readers that are holding * the master sock lock don't need to grab this lock in read mode * too as the syn_wait_queue writes are always protected from @@ -369,8 +382,9 @@ struct tcp_opt { /* FIFO of established children */ struct open_request *accept_queue; - struct open_request *accept_queue_tail; - +#ifndef CONFIG_ACCEPT_QUEUES + struct open_request *accept_queue_tail; +#endif int write_pending; /* A write to socket waits to start. */ unsigned int keepalive_time; /* time before keep alive takes place */ @@ -424,6 +438,22 @@ struct tcp_opt { __u32 last_max_cwnd; /* last maximium snd_cwnd */ __u32 last_cwnd; /* the last snd_cwnd */ } bictcp; + +#ifdef CONFIG_ACCEPT_QUEUES + /* move to listen opt... */ + char class_index; + struct { + struct open_request *aq_head; + struct open_request *aq_tail; + unsigned int aq_cnt; + unsigned int aq_ratio; + unsigned int aq_count; + unsigned int aq_qcount; + unsigned int aq_backlog; + unsigned int aq_wait_time; + int aq_valid; + } acceptq[NUM_ACCEPT_QUEUES]; +#endif }; /* WARNING: don't change the layout of the members in tcp_sock! */ diff --git a/include/linux/time.h b/include/linux/time.h index d24a690cb..bdf1da986 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -41,7 +41,7 @@ struct timezone { * Have the 32 bit jiffies value wrap 5 minutes after boot * so jiffies wrap bugs show up earlier. */ -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +#define INITIAL_JIFFIES ((unsigned long)(0)) /* * Change timeval to jiffies, trying to avoid the @@ -184,7 +184,7 @@ struct timezone { * Avoid unnecessary multiplications/divisions in the * two most common HZ cases: */ -static inline unsigned int jiffies_to_msecs(const unsigned long j) +static inline unsigned int jiffies_to_msecs(unsigned long j) { #if HZ <= 1000 && !(1000 % HZ) return (1000 / HZ) * j; @@ -194,7 +194,7 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j) return (j * 1000) / HZ; #endif } -static inline unsigned long msecs_to_jiffies(const unsigned int m) +static inline unsigned long msecs_to_jiffies(unsigned int m) { #if HZ <= 1000 && !(1000 % HZ) return (m + (1000 / HZ) - 1) / (1000 / HZ); @@ -217,7 +217,7 @@ static inline unsigned long msecs_to_jiffies(const unsigned int m) * value to a scaled second value. */ static __inline__ unsigned long -timespec_to_jiffies(const struct timespec *value) +timespec_to_jiffies(struct timespec *value) { unsigned long sec = value->tv_sec; long nsec = value->tv_nsec + TICK_NSEC - 1; @@ -233,7 +233,7 @@ timespec_to_jiffies(const struct timespec *value) } static __inline__ void -jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) +jiffies_to_timespec(unsigned long jiffies, struct timespec *value) { /* * Convert jiffies to nanoseconds and separate with @@ -256,7 +256,7 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) * instruction above the way it was done above. */ static __inline__ unsigned long -timeval_to_jiffies(const struct timeval *value) +timeval_to_jiffies(struct timeval *value) { unsigned long sec = value->tv_sec; long usec = value->tv_usec; @@ -271,7 +271,7 @@ timeval_to_jiffies(const struct timeval *value) } static __inline__ void -jiffies_to_timeval(const unsigned long jiffies, struct timeval *value) +jiffies_to_timeval(unsigned long jiffies, struct timeval *value) { /* * Convert jiffies to nanoseconds and separate with diff --git a/include/linux/types.h b/include/linux/types.h index 23c414f11..288ab653e 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -36,6 +36,8 @@ typedef __kernel_uid32_t uid_t; typedef __kernel_gid32_t gid_t; typedef __kernel_uid16_t uid16_t; typedef __kernel_gid16_t gid16_t; +typedef unsigned int xid_t; +typedef unsigned int nid_t; #ifdef CONFIG_UID16 /* This is defined by include/asm-{arch}/posix_types.h */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 4013919ef..cf243917d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -334,7 +334,6 @@ extern void usb_put_dev(struct usb_device *dev); /* mostly for devices emulating SCSI over USB */ extern int usb_reset_device(struct usb_device *dev); -extern int __usb_reset_device(struct usb_device *dev); extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); diff --git a/include/linux/vinline.h b/include/linux/vinline.h new file mode 100644 index 000000000..ce2bf36c1 --- /dev/null +++ b/include/linux/vinline.h @@ -0,0 +1,471 @@ +#ifndef _VX_INLINE_H +#define _VX_INLINE_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" +#include "vserver/limit.h" +#include "vserver/cvirt.h" + +#if defined(VX_DEBUG) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + + +extern int proc_pid_vx_info(struct task_struct *, char *); + + +#define get_vx_info(i) __get_vx_info(i,__FILE__,__LINE__) + +static inline struct vx_info *__get_vx_info(struct vx_info *vxi, + const char *_file, int _line) +{ + if (!vxi) + return NULL; + vxdprintk("get_vx_info(%p[#%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0, + _file, _line); + atomic_inc(&vxi->vx_usecnt); + return vxi; +} + + +#define free_vx_info(vxi) \ + call_rcu(&vxi->vx_rcu, rcu_free_vx_info, vxi); + +#define put_vx_info(i) __put_vx_info(i,__FILE__,__LINE__) + +static inline void __put_vx_info(struct vx_info *vxi, const char *_file, int _line) +{ + if (!vxi) + return; + vxdprintk("put_vx_info(%p[#%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0, + _file, _line); + if (atomic_dec_and_test(&vxi->vx_usecnt)) + free_vx_info(vxi); +} + +#define set_vx_info(p,i) __set_vx_info(p,i,__FILE__,__LINE__) + +static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi, + const char *_file, int _line) +{ + BUG_ON(*vxp); + if (!vxi) + return; + vxdprintk("set_vx_info(%p[#%d.%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, + vxi?atomic_read(&vxi->vx_usecnt):0, + vxi?atomic_read(&vxi->vx_refcnt):0, + _file, _line); + atomic_inc(&vxi->vx_refcnt); + *vxp = __get_vx_info(vxi, _file, _line); +} + +#define clr_vx_info(p) __clr_vx_info(p,__FILE__,__LINE__) + +static inline void __clr_vx_info(struct vx_info **vxp, + const char *_file, int _line) +{ + struct vx_info *vxo = *vxp; + + if (!vxo) + return; + vxdprintk("clr_vx_info(%p[#%d.%d.%d])\t%s:%d\n", + vxo, vxo?vxo->vx_id:0, + vxo?atomic_read(&vxo->vx_usecnt):0, + vxo?atomic_read(&vxo->vx_refcnt):0, + _file, _line); + *vxp = NULL; + wmb(); + if (vxo && atomic_dec_and_test(&vxo->vx_refcnt)) + unhash_vx_info(vxo); + __put_vx_info(vxo, _file, _line); +} + + +#define task_get_vx_info(i) __task_get_vx_info(i,__FILE__,__LINE__) + +static __inline__ struct vx_info *__task_get_vx_info(struct task_struct *p, + const char *_file, int _line) +{ + struct vx_info *vxi; + + task_lock(p); + vxi = __get_vx_info(p->vx_info, _file, _line); + task_unlock(p); + return vxi; +} + + +#define vx_verify_info(p,i) \ + __vx_verify_info((p)->vx_info,i,__FILE__,__LINE__) + +static __inline__ void __vx_verify_info( + struct vx_info *vxa, struct vx_info *vxb, + const char *_file, int _line) +{ + if (vxa == vxb) + return; + printk(KERN_ERR "vx bad assumption (%p==%p) at %s:%d\n", + vxa, vxb, _file, _line); +} + + +#define vx_task_xid(t) ((t)->xid) + +#define vx_current_xid() vx_task_xid(current) + +#define vx_check(c,m) __vx_check(vx_current_xid(),c,m) + +#define vx_weak_check(c,m) ((m) ? vx_check(c,m) : 1) + + +/* + * check current context for ADMIN/WATCH and + * optionally agains supplied argument + */ +static __inline__ int __vx_check(xid_t cid, xid_t id, unsigned int mode) +{ + if (mode & VX_ARG_MASK) { + if ((mode & VX_IDENT) && + (id == cid)) + return 1; + } + if (mode & VX_ATR_MASK) { + if ((mode & VX_DYNAMIC) && + (id >= MIN_D_CONTEXT) && + (id <= MAX_S_CONTEXT)) + return 1; + if ((mode & VX_STATIC) && + (id > 1) && (id < MIN_D_CONTEXT)) + return 1; + } + return (((mode & VX_ADMIN) && (cid == 0)) || + ((mode & VX_WATCH) && (cid == 1))); +} + + +#define __vx_flags(v,m,f) (((v) & (m)) ^ (f)) + +#define __vx_task_flags(t,m,f) \ + (((t) && ((t)->vx_info)) ? \ + __vx_flags((t)->vx_info->vx_flags,(m),(f)) : 0) + +#define vx_current_flags() \ + ((current->vx_info) ? current->vx_info->vx_flags : 0) + +#define vx_flags(m,f) __vx_flags(vx_current_flags(),(m),(f)) + + +#define vx_current_ccaps() \ + ((current->vx_info) ? current->vx_info->vx_ccaps : 0) + +#define vx_ccaps(c) (vx_current_ccaps() & (c)) + +#define vx_current_bcaps() \ + (((current->vx_info) && !vx_flags(VXF_STATE_SETUP, 0)) ? \ + current->vx_info->vx_bcaps : cap_bset) + + +#define VX_DEBUG_ACC_RSS 0 +#define VX_DEBUG_ACC_VM 0 +#define VX_DEBUG_ACC_VML 0 + +#undef vxdprintk +#if (VX_DEBUG_ACC_RSS) || (VX_DEBUG_ACC_VM) || (VX_DEBUG_ACC_VML) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + +#define vx_acc_page(m, d, v, r) \ + __vx_acc_page(&(m->v), m->mm_vx_info, r, d, __FILE__, __LINE__) + +static inline void __vx_acc_page(unsigned long *v, struct vx_info *vxi, + int res, int dir, char *file, int line) +{ + if (v) { + if (dir > 0) + ++(*v); + else + --(*v); + } + if (vxi) { + if (dir > 0) + atomic_inc(&vxi->limit.res[res]); + else + atomic_dec(&vxi->limit.res[res]); + } +} + + +#define vx_acc_pages(m, p, v, r) \ + __vx_acc_pages(&(m->v), m->mm_vx_info, r, p, __FILE__, __LINE__) + +static inline void __vx_acc_pages(unsigned long *v, struct vx_info *vxi, + int res, int pages, char *file, int line) +{ + if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) || + (res == RLIMIT_AS && VX_DEBUG_ACC_VM) || + (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML)) + vxdprintk("vx_acc_pages [%5d,%2d]: %5d += %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?atomic_read(&vxi->limit.res[res]):0), + pages, file, line); + if (pages == 0) + return; + if (v) + *v += pages; + if (vxi) + atomic_add(pages, &vxi->limit.res[res]); +} + + + +#define vx_acc_vmpage(m,d) vx_acc_page(m, d, total_vm, RLIMIT_AS) +#define vx_acc_vmlpage(m,d) vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_rsspage(m,d) vx_acc_page(m, d, rss, RLIMIT_RSS) + +#define vx_acc_vmpages(m,p) vx_acc_pages(m, p, total_vm, RLIMIT_AS) +#define vx_acc_vmlpages(m,p) vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_rsspages(m,p) vx_acc_pages(m, p, rss, RLIMIT_RSS) + +#define vx_pages_add(s,r,p) __vx_acc_pages(0, s, r, p, __FILE__, __LINE__) +#define vx_pages_sub(s,r,p) __vx_pages_add(s, r, -(p)) + +#define vx_vmpages_inc(m) vx_acc_vmpage(m, 1) +#define vx_vmpages_dec(m) vx_acc_vmpage(m,-1) +#define vx_vmpages_add(m,p) vx_acc_vmpages(m, p) +#define vx_vmpages_sub(m,p) vx_acc_vmpages(m,-(p)) + +#define vx_vmlocked_inc(m) vx_acc_vmlpage(m, 1) +#define vx_vmlocked_dec(m) vx_acc_vmlpage(m,-1) +#define vx_vmlocked_add(m,p) vx_acc_vmlpages(m, p) +#define vx_vmlocked_sub(m,p) vx_acc_vmlpages(m,-(p)) + +#define vx_rsspages_inc(m) vx_acc_rsspage(m, 1) +#define vx_rsspages_dec(m) vx_acc_rsspage(m,-1) +#define vx_rsspages_add(m,p) vx_acc_rsspages(m, p) +#define vx_rsspages_sub(m,p) vx_acc_rsspages(m,-(p)) + + + +#define vx_pages_avail(m, p, r) \ + __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__) + +static inline int __vx_pages_avail(struct vx_info *vxi, + int res, int pages, char *file, int line) +{ + if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) || + (res == RLIMIT_AS && VX_DEBUG_ACC_VM) || + (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML)) + printk("vx_pages_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?vxi->limit.rlim[res]:1), + (vxi?atomic_read(&vxi->limit.res[res]):0), + pages, file, line); + if (!vxi) + return 1; + if (vxi->limit.rlim[res] == RLIM_INFINITY) + return 1; + if (atomic_read(&vxi->limit.res[res]) + pages < vxi->limit.rlim[res]) + return 1; + return 0; +} + +#define vx_vmpages_avail(m,p) vx_pages_avail(m, p, RLIMIT_AS) +#define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) +#define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS) + +/* file limits */ + +#define VX_DEBUG_ACC_FILE 0 +#define VX_DEBUG_ACC_OPENFD 0 + +#undef vxdprintk +#if (VX_DEBUG_ACC_FILE) || (VX_DEBUG_ACC_OPENFD) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + +#define vx_acc_cres(v,d,r) \ + __vx_acc_cres((v), (r), (d), __FILE__, __LINE__) + +static inline void __vx_acc_cres(struct vx_info *vxi, + int res, int dir, char *file, int line) +{ + if (vxi) { + if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) || + (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD)) + printk("vx_acc_cres[%5d,%2d]: %5d%s in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?atomic_read(&vxi->limit.res[res]):0), + (dir>0)?"++":"--", file, line); + if (dir > 0) + atomic_inc(&vxi->limit.res[res]); + else + atomic_dec(&vxi->limit.res[res]); + } +} + +#define vx_files_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_NOFILE) +#define vx_files_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_NOFILE) + +#define vx_openfd_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_OPENFD) +#define vx_openfd_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_OPENFD) + +#define vx_cres_avail(v,n,r) \ + __vx_cres_avail((v), (r), (n), __FILE__, __LINE__) + +static inline int __vx_cres_avail(struct vx_info *vxi, + int res, int num, char *file, int line) +{ + if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) || + (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD)) + printk("vx_cres_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?vxi->limit.rlim[res]:1), + (vxi?atomic_read(&vxi->limit.res[res]):0), + num, file, line); + if (!vxi) + return 1; + if (vxi->limit.rlim[res] == RLIM_INFINITY) + return 1; + if (vxi->limit.rlim[res] < atomic_read(&vxi->limit.res[res]) + num) + return 0; + return 1; +} + +#define vx_files_avail(n) \ + vx_cres_avail(current->vx_info, (n), RLIMIT_NOFILE) + +#define vx_openfd_avail(n) \ + vx_cres_avail(current->vx_info, (n), RLIMIT_OPENFD) + +/* socket limits */ + +#define vx_sock_inc(f) vx_acc_cres(current->vx_info, 1, VLIMIT_SOCK) +#define vx_sock_dec(f) vx_acc_cres(current->vx_info,-1, VLIMIT_SOCK) + +#define vx_sock_avail(n) \ + vx_cres_avail(current->vx_info, (n), VLIMIT_SOCK) + +/* procfs ioctls */ + +#define FIOC_GETXFLG _IOR('x', 5, long) +#define FIOC_SETXFLG _IOW('x', 6, long) + +/* utsname virtualization */ + +static inline struct new_utsname *vx_new_utsname(void) +{ + if (current->vx_info) + return ¤t->vx_info->cvirt.utsname; + return &system_utsname; +} + +#define vx_new_uts(x) ((vx_new_utsname())->x) + +/* generic flag merging */ + +#define vx_mask_flags(v,f,m) (((v) & ~(m)) | ((f) & (m))) + +#define vx_mask_mask(v,f,m) (((v) & ~(m)) | ((v) & (f) & (m))) + + +/* socket accounting */ + +#include + +static inline int vx_sock_type(int family) +{ + int type = 4; + + if (family > 0 && family < 3) + type = family; + else if (family == PF_INET6) + type = 3; + return type; +} + +#define vx_acc_sock(v,f,p,s) \ + __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__) + +static inline void __vx_acc_sock(struct vx_info *vxi, + int family, int pos, int size, char *file, int line) +{ + if (vxi) { + int type = vx_sock_type(family); + + atomic_inc(&vxi->cacct.sock[type][pos].count); + atomic_add(size, &vxi->cacct.sock[type][pos].total); + } +} + +#define vx_sock_recv(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s)) +#define vx_sock_send(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s)) +#define vx_sock_fail(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s)) + + +#define sock_vx_init(s) do { \ + (s)->sk_xid = 0; \ + (s)->sk_vx_info = NULL; \ + } while (0) + + +/* pid faking stuff */ + + +#define vx_map_tgid(v,p) \ + __vx_map_tgid((v), (p), __FILE__, __LINE__) + +static inline int __vx_map_tgid(struct vx_info *vxi, int pid, + char *file, int line) +{ + if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) { + vxdprintk("vx_map_tgid: %p/%llx: %d -> %d in %s:%d\n", + vxi, vxi->vx_flags, pid, + (pid == vxi->vx_initpid)?1:pid, + file, line); + if (pid == vxi->vx_initpid) + return 1; + } + return pid; +} + +#define vx_rmap_tgid(v,p) \ + __vx_rmap_tgid((v), (p), __FILE__, __LINE__) + +static inline int __vx_rmap_tgid(struct vx_info *vxi, int pid, + char *file, int line) +{ + if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) { + vxdprintk("vx_rmap_tgid: %p/%llx: %d -> %d in %s:%d\n", + vxi, vxi->vx_flags, pid, + (pid == 1)?vxi->vx_initpid:pid, + file, line); + if ((pid == 1) && vxi->vx_initpid) + return vxi->vx_initpid; + } + return pid; +} + +#undef vxdprintk +#define vxdprintk(x...) + +#endif diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 570778dde..bad993c16 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -23,6 +23,7 @@ struct vm_struct { * Highlevel APIs for driver use */ extern void *vmalloc(unsigned long size); +extern void *vmalloc_exec(unsigned long size); extern void *vmalloc_32(unsigned long size); extern void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot); extern void vfree(void *addr); diff --git a/include/linux/vs_base.h b/include/linux/vs_base.h new file mode 100644 index 000000000..4f04513ff --- /dev/null +++ b/include/linux/vs_base.h @@ -0,0 +1,78 @@ +#ifndef _VX_VS_BASE_H +#define _VX_VS_BASE_H + +#include "vserver/context.h" + +// #define VX_DEBUG + + +#if defined(VX_DEBUG) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + +#define vx_task_xid(t) ((t)->xid) + +#define vx_current_xid() vx_task_xid(current) + +#define vx_check(c,m) __vx_check(vx_current_xid(),c,m) + +#define vx_weak_check(c,m) ((m) ? vx_check(c,m) : 1) + + +/* + * check current context for ADMIN/WATCH and + * optionally agains supplied argument + */ +static __inline__ int __vx_check(xid_t cid, xid_t id, unsigned int mode) +{ + if (mode & VX_ARG_MASK) { + if ((mode & VX_IDENT) && + (id == cid)) + return 1; + } + if (mode & VX_ATR_MASK) { + if ((mode & VX_DYNAMIC) && + (id >= MIN_D_CONTEXT) && + (id <= MAX_S_CONTEXT)) + return 1; + if ((mode & VX_STATIC) && + (id > 1) && (id < MIN_D_CONTEXT)) + return 1; + } + return (((mode & VX_ADMIN) && (cid == 0)) || + ((mode & VX_WATCH) && (cid == 1))); +} + + +#define __vx_flags(v,m,f) (((v) & (m)) ^ (f)) + +#define __vx_task_flags(t,m,f) \ + (((t) && ((t)->vx_info)) ? \ + __vx_flags((t)->vx_info->vx_flags,(m),(f)) : 0) + +#define vx_current_flags() \ + ((current->vx_info) ? current->vx_info->vx_flags : 0) + +#define vx_flags(m,f) __vx_flags(vx_current_flags(),(m),(f)) + + +#define vx_current_ccaps() \ + ((current->vx_info) ? current->vx_info->vx_ccaps : 0) + +#define vx_ccaps(c) (vx_current_ccaps() & (c)) + +#define vx_current_bcaps() \ + (((current->vx_info) && !vx_flags(VXF_STATE_SETUP, 0)) ? \ + current->vx_info->vx_bcaps : cap_bset) + + +/* generic flag merging */ + +#define vx_mask_flags(v,f,m) (((v) & ~(m)) | ((f) & (m))) + +#define vx_mask_mask(v,f,m) (((v) & ~(m)) | ((v) & (f) & (m))) + +#endif diff --git a/include/linux/vs_context.h b/include/linux/vs_context.h new file mode 100644 index 000000000..727a16cdc --- /dev/null +++ b/include/linux/vs_context.h @@ -0,0 +1,128 @@ +#ifndef _VX_VS_CONTEXT_H +#define _VX_VS_CONTEXT_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" + +#undef vxdprintk +#if defined(VX_DEBUG) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + + +extern int proc_pid_vx_info(struct task_struct *, char *); + + +#define get_vx_info(i) __get_vx_info(i,__FILE__,__LINE__) + +static inline struct vx_info *__get_vx_info(struct vx_info *vxi, + const char *_file, int _line) +{ + if (!vxi) + return NULL; + vxdprintk("get_vx_info(%p[#%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0, + _file, _line); + atomic_inc(&vxi->vx_usecnt); + return vxi; +} + + +#define free_vx_info(i) \ + call_rcu(&i->vx_rcu, rcu_free_vx_info, i); + +#define put_vx_info(i) __put_vx_info(i,__FILE__,__LINE__) + +static inline void __put_vx_info(struct vx_info *vxi, const char *_file, int _line) +{ + if (!vxi) + return; + vxdprintk("put_vx_info(%p[#%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0, + _file, _line); + if (atomic_dec_and_test(&vxi->vx_usecnt)) + free_vx_info(vxi); +} + +#define set_vx_info(p,i) __set_vx_info(p,i,__FILE__,__LINE__) + +static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi, + const char *_file, int _line) +{ + BUG_ON(*vxp); + if (!vxi) + return; + vxdprintk("set_vx_info(%p[#%d.%d.%d])\t%s:%d\n", + vxi, vxi?vxi->vx_id:0, + vxi?atomic_read(&vxi->vx_usecnt):0, + vxi?atomic_read(&vxi->vx_refcnt):0, + _file, _line); + atomic_inc(&vxi->vx_refcnt); + *vxp = __get_vx_info(vxi, _file, _line); +} + +#define clr_vx_info(p) __clr_vx_info(p,__FILE__,__LINE__) + +static inline void __clr_vx_info(struct vx_info **vxp, + const char *_file, int _line) +{ + struct vx_info *vxo = *vxp; + + if (!vxo) + return; + vxdprintk("clr_vx_info(%p[#%d.%d.%d])\t%s:%d\n", + vxo, vxo?vxo->vx_id:0, + vxo?atomic_read(&vxo->vx_usecnt):0, + vxo?atomic_read(&vxo->vx_refcnt):0, + _file, _line); + *vxp = NULL; + wmb(); + if (vxo && atomic_dec_and_test(&vxo->vx_refcnt)) + unhash_vx_info(vxo); + __put_vx_info(vxo, _file, _line); +} + + +#define task_get_vx_info(i) __task_get_vx_info(i,__FILE__,__LINE__) + +static __inline__ struct vx_info *__task_get_vx_info(struct task_struct *p, + const char *_file, int _line) +{ + struct vx_info *vxi; + + task_lock(p); + vxi = __get_vx_info(p->vx_info, _file, _line); + task_unlock(p); + return vxi; +} + + +#define vx_verify_info(p,i) \ + __vx_verify_info((p)->vx_info,i,__FILE__,__LINE__) + +static __inline__ void __vx_verify_info( + struct vx_info *vxa, struct vx_info *vxb, + const char *_file, int _line) +{ + if (vxa == vxb) + return; + printk(KERN_ERR "vx bad assumption (%p==%p) at %s:%d\n", + vxa, vxb, _file, _line); +} + + +#undef vxdprintk +#define vxdprintk(x...) + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_cvirt.h b/include/linux/vs_cvirt.h new file mode 100644 index 000000000..65f430362 --- /dev/null +++ b/include/linux/vs_cvirt.h @@ -0,0 +1,71 @@ +#ifndef _VX_VS_CVIRT_H +#define _VX_VS_CVIRT_H + + +// #define VX_DEBUG + +#include "vserver/cvirt.h" +#include "vs_base.h" + +#if defined(VX_DEBUG) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + +/* utsname virtualization */ + +static inline struct new_utsname *vx_new_utsname(void) +{ + if (current->vx_info) + return ¤t->vx_info->cvirt.utsname; + return &system_utsname; +} + +#define vx_new_uts(x) ((vx_new_utsname())->x) + + +/* pid faking stuff */ + + +#define vx_map_tgid(v,p) \ + __vx_map_tgid((v), (p), __FILE__, __LINE__) + +static inline int __vx_map_tgid(struct vx_info *vxi, int pid, + char *file, int line) +{ + if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) { + vxdprintk("vx_map_tgid: %p/%llx: %d -> %d in %s:%d\n", + vxi, vxi->vx_flags, pid, + (pid == vxi->vx_initpid)?1:pid, + file, line); + if (pid == vxi->vx_initpid) + return 1; + } + return pid; +} + +#define vx_rmap_tgid(v,p) \ + __vx_rmap_tgid((v), (p), __FILE__, __LINE__) + +static inline int __vx_rmap_tgid(struct vx_info *vxi, int pid, + char *file, int line) +{ + if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) { + vxdprintk("vx_rmap_tgid: %p/%llx: %d -> %d in %s:%d\n", + vxi, vxi->vx_flags, pid, + (pid == 1)?vxi->vx_initpid:pid, + file, line); + if ((pid == 1) && vxi->vx_initpid) + return vxi->vx_initpid; + } + return pid; +} + +#undef vxdprintk +#define vxdprintk(x...) + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_dlimit.h b/include/linux/vs_dlimit.h new file mode 100644 index 000000000..d80c563f6 --- /dev/null +++ b/include/linux/vs_dlimit.h @@ -0,0 +1,169 @@ +#ifndef _VX_VS_DLIMIT_H +#define _VX_VS_DLIMIT_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" +#include "vserver/dlimit.h" + +#if defined(VX_DEBUG) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + +#define get_dl_info(i) __get_dl_info(i,__FILE__,__LINE__) + +static inline struct dl_info *__get_dl_info(struct dl_info *dli, + const char *_file, int _line) +{ + if (!dli) + return NULL; + vxdprintk("get_dl_info(%p[#%d.%d])\t%s:%d\n", + dli, dli?dli->dl_xid:0, dli?atomic_read(&dli->dl_usecnt):0, + _file, _line); + atomic_inc(&dli->dl_usecnt); + return dli; +} + + +#define free_dl_info(i) \ + call_rcu(&i->dl_rcu, rcu_free_dl_info, i); + +#define put_dl_info(i) __put_dl_info(i,__FILE__,__LINE__) + +static inline void __put_dl_info(struct dl_info *dli, const char *_file, int _line) +{ + if (!dli) + return; + vxdprintk("put_dl_info(%p[#%d.%d])\t%s:%d\n", + dli, dli?dli->dl_xid:0, dli?atomic_read(&dli->dl_usecnt):0, + _file, _line); + if (atomic_dec_and_test(&dli->dl_usecnt)) + free_dl_info(dli); +} + + +extern int vx_debug_dlimit; + +#define __dlimit_char(d) ((d)?'*':' ') + +static inline int __dl_alloc_space(struct super_block *sb, + xid_t xid, dlsize_t nr, const char *file, int line) +{ + struct dl_info *dli = NULL; + int ret = 0; + + if (nr == 0) + goto out; + dli = locate_dl_info(sb, xid); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + ret = (dli->dl_space_used + nr > dli->dl_space_total); + if (!ret) + dli->dl_space_used += nr; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + if (vx_debug_dlimit) + printk("ALLOC (%p,#%d)%c %lld bytes (%d)@ %s:%d\n", + sb, xid, __dlimit_char(dli), nr, ret, file, line); + return ret; +} + +static inline void __dl_free_space(struct super_block *sb, + xid_t xid, dlsize_t nr, const char *file, int line) +{ + struct dl_info *dli = NULL; + + if (nr == 0) + goto out; + dli = locate_dl_info(sb, xid); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + dli->dl_space_used -= nr; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + if (vx_debug_dlimit) + printk("FREE (%p,#%d)%c %lld bytes @ %s:%d\n", + sb, xid, __dlimit_char(dli), nr, file, line); +} + +static inline int __dl_alloc_inode(struct super_block *sb, + xid_t xid, const char *file, int line) +{ + struct dl_info *dli; + int ret = 0; + + dli = locate_dl_info(sb, xid); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + ret = (dli->dl_inodes_used >= dli->dl_inodes_total); + if (!ret) + dli->dl_inodes_used++; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + if (vx_debug_dlimit) + printk("ALLOC (%p,#%d)%c inode (%d)@ %s:%d\n", + sb, xid, __dlimit_char(dli), ret, file, line); + return ret; +} + +static inline void __dl_free_inode(struct super_block *sb, + xid_t xid, const char *file, int line) +{ + struct dl_info *dli; + + dli = locate_dl_info(sb, xid); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + dli->dl_inodes_used--; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + if (vx_debug_dlimit) + printk("FREE (%p,#%d)%c inode @ %s:%d\n", + sb, xid, __dlimit_char(dli), file, line); +} + + + +#define DLIMIT_ALLOC_BLOCK(sb, xid, nr) \ + __dl_alloc_space(sb, xid, \ + ((dlsize_t)(nr)) << (sb)->s_blocksize_bits, \ + __FILE__, __LINE__ ) + +#define DLIMIT_FREE_BLOCK(sb, xid, nr) \ + __dl_free_space(sb, xid, \ + ((dlsize_t)(nr)) << (sb)->s_blocksize_bits, \ + __FILE__, __LINE__ ) + +#define DLIMIT_ALLOC_INODE(sb, xid) \ + __dl_alloc_inode(sb, xid, __FILE__, __LINE__ ) + +#define DLIMIT_FREE_INODE(sb, xid) \ + __dl_free_inode(sb, xid, __FILE__, __LINE__ ) + + +#define DLIMIT_ADJUST_BLOCK(sb, xid, fb, rb) + + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_limit.h b/include/linux/vs_limit.h new file mode 100644 index 000000000..82e8de4ec --- /dev/null +++ b/include/linux/vs_limit.h @@ -0,0 +1,119 @@ +#ifndef _VX_VS_LIMIT_H +#define _VX_VS_LIMIT_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" +#include "vserver/limit.h" + + +/* file limits */ + +#define VX_DEBUG_ACC_FILE 0 +#define VX_DEBUG_ACC_OPENFD 0 + +#if (VX_DEBUG_ACC_FILE) || (VX_DEBUG_ACC_OPENFD) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + + +#define vx_acc_cres(v,d,r) \ + __vx_acc_cres((v), (r), (d), __FILE__, __LINE__) + +static inline void __vx_acc_cres(struct vx_info *vxi, + int res, int dir, char *file, int line) +{ + if (vxi) { + if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) || + (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD)) + printk("vx_acc_cres[%5d,%2d]: %5d%s in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?atomic_read(&vxi->limit.rcur[res]):0), + (dir>0)?"++":"--", file, line); + if (dir > 0) + atomic_inc(&vxi->limit.rcur[res]); + else + atomic_dec(&vxi->limit.rcur[res]); + } +} + +#define vx_nproc_inc(p) vx_acc_cres(current->vx_info, 1, RLIMIT_NPROC) +#define vx_nproc_dec(p) vx_acc_cres(current->vx_info,-1, RLIMIT_NPROC) + +#define vx_files_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_NOFILE) +#define vx_files_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_NOFILE) + +#define vx_openfd_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_OPENFD) +#define vx_openfd_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_OPENFD) + +/* +#define vx_openfd_inc(f) do { \ + vx_acc_cres(current->vx_info, 1, RLIMIT_OPENFD); \ + printk("vx_openfd_inc: %d[#%d] in %s:%d\n", \ + f, current->xid, __FILE__, __LINE__); \ + } while (0) + +#define vx_openfd_dec(f) do { \ + vx_acc_cres(current->vx_info,-1, RLIMIT_OPENFD); \ + printk("vx_openfd_dec: %d[#%d] in %s:%d\n", \ + f, current->xid, __FILE__, __LINE__); \ + } while (0) +*/ + +#define vx_cres_avail(v,n,r) \ + __vx_cres_avail((v), (r), (n), __FILE__, __LINE__) + +static inline int __vx_cres_avail(struct vx_info *vxi, + int res, int num, char *file, int line) +{ + unsigned long value; + + if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) || + (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD)) + printk("vx_cres_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?vxi->limit.rlim[res]:1), + (vxi?atomic_read(&vxi->limit.rcur[res]):0), + num, file, line); + if (!vxi) + return 1; + value = atomic_read(&vxi->limit.rcur[res]); + if (value > vxi->limit.rmax[res]) + vxi->limit.rmax[res] = value; + if (vxi->limit.rlim[res] == RLIM_INFINITY) + return 1; + if (value + num <= vxi->limit.rlim[res]) + return 1; + atomic_inc(&vxi->limit.lhit[res]); + return 0; +} + +#define vx_nproc_avail(n) \ + vx_cres_avail(current->vx_info, (n), RLIMIT_NPROC) + +#define vx_files_avail(n) \ + vx_cres_avail(current->vx_info, (n), RLIMIT_NOFILE) + +#define vx_openfd_avail(n) \ + vx_cres_avail(current->vx_info, (n), RLIMIT_OPENFD) + + +/* socket limits */ + +#define vx_sock_inc(f) vx_acc_cres(current->vx_info, 1, VLIMIT_SOCK) +#define vx_sock_dec(f) vx_acc_cres(current->vx_info,-1, VLIMIT_SOCK) + +#define vx_sock_avail(n) \ + vx_cres_avail(current->vx_info, (n), VLIMIT_SOCK) + + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_memory.h b/include/linux/vs_memory.h new file mode 100644 index 000000000..2fe9c0809 --- /dev/null +++ b/include/linux/vs_memory.h @@ -0,0 +1,132 @@ +#ifndef _VX_VS_MEMORY_H +#define _VX_VS_MEMORY_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" +#include "vserver/limit.h" + + +#define VX_DEBUG_ACC_RSS 0 +#define VX_DEBUG_ACC_VM 0 +#define VX_DEBUG_ACC_VML 0 + +#if (VX_DEBUG_ACC_RSS) || (VX_DEBUG_ACC_VM) || (VX_DEBUG_ACC_VML) +#define vxdprintk(x...) printk("vxd: " x) +#else +#define vxdprintk(x...) +#endif + +#define vx_acc_page(m, d, v, r) \ + __vx_acc_page(&(m->v), m->mm_vx_info, r, d, __FILE__, __LINE__) + +static inline void __vx_acc_page(unsigned long *v, struct vx_info *vxi, + int res, int dir, char *file, int line) +{ + if (v) { + if (dir > 0) + ++(*v); + else + --(*v); + } + if (vxi) { + if (dir > 0) + atomic_inc(&vxi->limit.rcur[res]); + else + atomic_dec(&vxi->limit.rcur[res]); + } +} + + +#define vx_acc_pages(m, p, v, r) \ + __vx_acc_pages(&(m->v), m->mm_vx_info, r, p, __FILE__, __LINE__) + +static inline void __vx_acc_pages(unsigned long *v, struct vx_info *vxi, + int res, int pages, char *file, int line) +{ + if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) || + (res == RLIMIT_AS && VX_DEBUG_ACC_VM) || + (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML)) + vxdprintk("vx_acc_pages [%5d,%2d]: %5d += %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?atomic_read(&vxi->limit.res[res]):0), + pages, file, line); + if (pages == 0) + return; + if (v) + *v += pages; + if (vxi) + atomic_add(pages, &vxi->limit.rcur[res]); +} + + + +#define vx_acc_vmpage(m,d) vx_acc_page(m, d, total_vm, RLIMIT_AS) +#define vx_acc_vmlpage(m,d) vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_rsspage(m,d) vx_acc_page(m, d, rss, RLIMIT_RSS) + +#define vx_acc_vmpages(m,p) vx_acc_pages(m, p, total_vm, RLIMIT_AS) +#define vx_acc_vmlpages(m,p) vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_rsspages(m,p) vx_acc_pages(m, p, rss, RLIMIT_RSS) + +#define vx_pages_add(s,r,p) __vx_acc_pages(0, s, r, p, __FILE__, __LINE__) +#define vx_pages_sub(s,r,p) __vx_pages_add(s, r, -(p)) + +#define vx_vmpages_inc(m) vx_acc_vmpage(m, 1) +#define vx_vmpages_dec(m) vx_acc_vmpage(m,-1) +#define vx_vmpages_add(m,p) vx_acc_vmpages(m, p) +#define vx_vmpages_sub(m,p) vx_acc_vmpages(m,-(p)) + +#define vx_vmlocked_inc(m) vx_acc_vmlpage(m, 1) +#define vx_vmlocked_dec(m) vx_acc_vmlpage(m,-1) +#define vx_vmlocked_add(m,p) vx_acc_vmlpages(m, p) +#define vx_vmlocked_sub(m,p) vx_acc_vmlpages(m,-(p)) + +#define vx_rsspages_inc(m) vx_acc_rsspage(m, 1) +#define vx_rsspages_dec(m) vx_acc_rsspage(m,-1) +#define vx_rsspages_add(m,p) vx_acc_rsspages(m, p) +#define vx_rsspages_sub(m,p) vx_acc_rsspages(m,-(p)) + + + +#define vx_pages_avail(m, p, r) \ + __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__) + +static inline int __vx_pages_avail(struct vx_info *vxi, + int res, int pages, char *file, int line) +{ + unsigned long value; + + if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) || + (res == RLIMIT_AS && VX_DEBUG_ACC_VM) || + (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML)) + printk("vx_pages_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n", + (vxi?vxi->vx_id:-1), res, + (vxi?vxi->limit.rlim[res]:1), + (vxi?atomic_read(&vxi->limit.rcur[res]):0), + pages, file, line); + if (!vxi) + return 1; + value = atomic_read(&vxi->limit.rcur[res]); + if (value > vxi->limit.rmax[res]) + vxi->limit.rmax[res] = value; + if (vxi->limit.rlim[res] == RLIM_INFINITY) + return 1; + if (value + pages <= vxi->limit.rlim[res]) + return 1; + atomic_inc(&vxi->limit.lhit[res]); + return 0; +} + +#define vx_vmpages_avail(m,p) vx_pages_avail(m, p, RLIMIT_AS) +#define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) +#define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS) + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_network.h b/include/linux/vs_network.h new file mode 100644 index 000000000..0a3349c09 --- /dev/null +++ b/include/linux/vs_network.h @@ -0,0 +1,154 @@ +#ifndef _NX_VS_NETWORK_H +#define _NX_VS_NETWORK_H + + +// #define NX_DEBUG + +#include +#include +#include + +#include "vserver/network.h" + +#if defined(NX_DEBUG) +#define nxdprintk(x...) printk("nxd: " x) +#else +#define nxdprintk(x...) +#endif + + +extern int proc_pid_nx_info(struct task_struct *, char *); + + +#define get_nx_info(i) __get_nx_info(i,__FILE__,__LINE__) + +static inline struct nx_info *__get_nx_info(struct nx_info *nxi, + const char *_file, int _line) +{ + if (!nxi) + return NULL; + nxdprintk("get_nx_info(%p[#%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0, + _file, _line); + atomic_inc(&nxi->nx_usecnt); + return nxi; +} + + +#define free_nx_info(nxi) \ + call_rcu(&nxi->nx_rcu, rcu_free_nx_info, nxi); + +#define put_nx_info(i) __put_nx_info(i,__FILE__,__LINE__) + +static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line) +{ + if (!nxi) + return; + nxdprintk("put_nx_info(%p[#%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0, + _file, _line); + if (atomic_dec_and_test(&nxi->nx_usecnt)) + free_nx_info(nxi); +} + + +#define set_nx_info(p,i) __set_nx_info(p,i,__FILE__,__LINE__) + +static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi, + const char *_file, int _line) +{ + BUG_ON(*nxp); + if (!nxi) + return; + nxdprintk("set_nx_info(%p[#%d.%d.%d])\t%s:%d\n", + nxi, nxi?nxi->nx_id:0, + nxi?atomic_read(&nxi->nx_usecnt):0, + nxi?atomic_read(&nxi->nx_refcnt):0, + _file, _line); + atomic_inc(&nxi->nx_refcnt); + *nxp = __get_nx_info(nxi, _file, _line); +} + +#define clr_nx_info(p) __clr_nx_info(p,__FILE__,__LINE__) + +static inline void __clr_nx_info(struct nx_info **nxp, + const char *_file, int _line) +{ + struct nx_info *nxo = *nxp; + + if (!nxo) + return; + nxdprintk("clr_nx_info(%p[#%d.%d.%d])\t%s:%d\n", + nxo, nxo?nxo->nx_id:0, + nxo?atomic_read(&nxo->nx_usecnt):0, + nxo?atomic_read(&nxo->nx_refcnt):0, + _file, _line); + *nxp = NULL; + wmb(); + if (nxo && atomic_dec_and_test(&nxo->nx_refcnt)) + unhash_nx_info(nxo); + __put_nx_info(nxo, _file, _line); +} + + +#define task_get_nx_info(i) __task_get_nx_info(i,__FILE__,__LINE__) + +static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p, + const char *_file, int _line) +{ + struct nx_info *nxi; + + task_lock(p); + nxi = __get_nx_info(p->nx_info, _file, _line); + task_unlock(p); + return nxi; +} + +#define nx_verify_info(p,i) \ + __nx_verify_info((p)->nx_info,i,__FILE__,__LINE__) + +static __inline__ void __nx_verify_info( + struct nx_info *ipa, struct nx_info *ipb, + const char *_file, int _line) +{ + if (ipa == ipb) + return; + printk(KERN_ERR "ip bad assumption (%p==%p) at %s:%d\n", + ipa, ipb, _file, _line); +} + + +#define nx_task_nid(t) ((t)->nid) + +#define nx_current_nid() nx_task_nid(current) + +#define nx_check(c,m) __nx_check(nx_current_nid(),c,m) + +#define nx_weak_check(c,m) ((m) ? nx_check(c,m) : 1) + +#undef nxdprintk +#define nxdprintk(x...) + + +#define __nx_flags(v,m,f) (((v) & (m)) ^ (f)) + +#define __nx_task_flags(t,m,f) \ + (((t) && ((t)->nx_info)) ? \ + __nx_flags((t)->nx_info->nx_flags,(m),(f)) : 0) + +#define nx_current_flags() \ + ((current->nx_info) ? current->nx_info->nx_flags : 0) + +#define nx_flags(m,f) __nx_flags(nx_current_flags(),(m),(f)) + + +#define nx_current_ncaps() \ + ((current->nx_info) ? current->nx_info->nx_ncaps : 0) + +#define nx_ncaps(c) (nx_current_ncaps() & (c)) + + + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vs_socket.h b/include/linux/vs_socket.h new file mode 100644 index 000000000..499245822 --- /dev/null +++ b/include/linux/vs_socket.h @@ -0,0 +1,65 @@ +#ifndef _VX_VS_LIMIT_H +#define _VX_VS_LIMIT_H + + +// #define VX_DEBUG + +#include +#include +#include + +#include "vserver/context.h" +#include "vserver/network.h" + + +/* socket accounting */ + +#include + +static inline int vx_sock_type(int family) +{ + int type = 4; + + if (family > 0 && family < 3) + type = family; + else if (family == PF_INET6) + type = 3; + return type; +} + +#define vx_acc_sock(v,f,p,s) \ + __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__) + +static inline void __vx_acc_sock(struct vx_info *vxi, + int family, int pos, int size, char *file, int line) +{ + if (vxi) { + int type = vx_sock_type(family); + + atomic_inc(&vxi->cacct.sock[type][pos].count); + atomic_add(size, &vxi->cacct.sock[type][pos].total); + } +} + +#define vx_sock_recv(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s)) +#define vx_sock_send(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s)) +#define vx_sock_fail(sk,s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s)) + + +#define sock_vx_init(s) do { \ + (s)->sk_xid = 0; \ + (s)->sk_vx_info = NULL; \ + } while (0) + +#define sock_nx_init(s) do { \ + (s)->sk_nid = 0; \ + (s)->sk_nx_info = NULL; \ + } while (0) + + +#else +#warning duplicate inclusion +#endif diff --git a/include/linux/vserver.h b/include/linux/vserver.h new file mode 100644 index 000000000..db88b5e06 --- /dev/null +++ b/include/linux/vserver.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_VSERVER_H +#define _LINUX_VSERVER_H + +#include +#include + +extern long vs_reboot(unsigned int, void *); + +#define hlist_for_each_rcu(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +#endif diff --git a/include/linux/vserver/context.h b/include/linux/vserver/context.h new file mode 100644 index 000000000..7bc7f9373 --- /dev/null +++ b/include/linux/vserver/context.h @@ -0,0 +1,179 @@ +#ifndef _VX_CONTEXT_H +#define _VX_CONTEXT_H + +#include + +#define MAX_S_CONTEXT 65535 /* Arbitrary limit */ +#define MIN_D_CONTEXT 49152 /* dynamic contexts start here */ + +#define VX_DYNAMIC_ID ((uint32_t)-1) /* id for dynamic context */ + +#ifdef __KERNEL__ + +#include +#include +#include + +#define _VX_INFO_DEF_ +#include "cvirt.h" +#include "limit.h" +#include "sched.h" +#undef _VX_INFO_DEF_ + +struct vx_info { + struct hlist_node vx_hlist; /* linked list of contexts */ + struct rcu_head vx_rcu; /* the rcu head */ + xid_t vx_id; /* context id */ + atomic_t vx_usecnt; /* usage count */ + atomic_t vx_refcnt; /* reference count */ + struct vx_info *vx_parent; /* parent context */ + + struct namespace *vx_namespace; /* private namespace */ + struct fs_struct *vx_fs; /* private namespace fs */ + uint64_t vx_flags; /* VX_INFO_xxx */ + uint64_t vx_bcaps; /* bounding caps (system) */ + uint64_t vx_ccaps; /* context caps (vserver) */ + + pid_t vx_initpid; /* PID of fake init process */ + + struct _vx_limit limit; /* vserver limits */ + struct _vx_sched sched; /* vserver scheduler */ + struct _vx_cvirt cvirt; /* virtual/bias stuff */ + struct _vx_cacct cacct; /* context accounting */ + + char vx_name[65]; /* vserver name */ +}; + + +#define VX_ADMIN 0x0001 +#define VX_WATCH 0x0002 +#define VX_DUMMY 0x0008 + +#define VX_IDENT 0x0010 +#define VX_EQUIV 0x0020 +#define VX_PARENT 0x0040 +#define VX_CHILD 0x0080 + +#define VX_ARG_MASK 0x00F0 + +#define VX_DYNAMIC 0x0100 +#define VX_STATIC 0x0200 + +#define VX_ATR_MASK 0x0F00 + + +extern void rcu_free_vx_info(void *); +extern void unhash_vx_info(struct vx_info *); + +extern struct vx_info *locate_vx_info(int); +extern struct vx_info *locate_or_create_vx_info(int); + +extern int get_xid_list(int, unsigned int *, int); +extern int vx_info_is_hashed(xid_t); + +extern int vx_migrate_task(struct task_struct *, struct vx_info *); + +#endif /* __KERNEL__ */ + +#include "switch.h" + +/* vinfo commands */ + +#define VCMD_task_xid VC_CMD(VINFO, 1, 0) +#define VCMD_task_nid VC_CMD(VINFO, 2, 0) + +#ifdef __KERNEL__ +extern int vc_task_xid(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_vx_info VC_CMD(VINFO, 5, 0) +#define VCMD_nx_info VC_CMD(VINFO, 6, 0) + +struct vcmd_vx_info_v0 { + uint32_t xid; + uint32_t initpid; + /* more to come */ +}; + +#ifdef __KERNEL__ +extern int vc_vx_info(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_ctx_create VC_CMD(VPROC, 1, 0) +#define VCMD_ctx_migrate VC_CMD(PROCMIG, 1, 0) + +#ifdef __KERNEL__ +extern int vc_ctx_create(uint32_t, void __user *); +extern int vc_ctx_migrate(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_get_cflags VC_CMD(FLAGS, 1, 0) +#define VCMD_set_cflags VC_CMD(FLAGS, 2, 0) + +struct vcmd_ctx_flags_v0 { + uint64_t flagword; + uint64_t mask; +}; + +#ifdef __KERNEL__ +extern int vc_get_cflags(uint32_t, void __user *); +extern int vc_set_cflags(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VXF_INFO_LOCK 0x00000001 +#define VXF_INFO_SCHED 0x00000002 +#define VXF_INFO_NPROC 0x00000004 +#define VXF_INFO_PRIVATE 0x00000008 + +#define VXF_INFO_INIT 0x00000010 +#define VXF_INFO_HIDE 0x00000020 +#define VXF_INFO_ULIMIT 0x00000040 +#define VXF_INFO_NSPACE 0x00000080 + +#define VXF_SCHED_HARD 0x00000100 +#define VXF_SCHED_PRIO 0x00000200 +#define VXF_SCHED_PAUSE 0x00000400 + +#define VXF_VIRT_MEM 0x00010000 +#define VXF_VIRT_UPTIME 0x00020000 +#define VXF_VIRT_CPU 0x00040000 + +#define VXF_HIDE_MOUNT 0x01000000 +#define VXF_HIDE_NETIF 0x02000000 + +#define VXF_STATE_SETUP (1ULL<<32) +#define VXF_STATE_INIT (1ULL<<33) + +#define VXF_FORK_RSS (1ULL<<48) +#define VXF_PROLIFIC (1ULL<<49) + +#define VXF_ONE_TIME (0x0003ULL<<32) + +#define VCMD_get_ccaps VC_CMD(FLAGS, 3, 0) +#define VCMD_set_ccaps VC_CMD(FLAGS, 4, 0) + +struct vcmd_ctx_caps_v0 { + uint64_t bcaps; + uint64_t ccaps; + uint64_t cmask; +}; + +#ifdef __KERNEL__ +extern int vc_get_ccaps(uint32_t, void __user *); +extern int vc_set_ccaps(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VXC_SET_UTSNAME 0x00000001 +#define VXC_SET_RLIMIT 0x00000002 + +#define VXC_RAW_ICMP 0x00000100 + +#define VXC_SECURE_MOUNT 0x00010000 + + +#endif /* _VX_CONTEXT_H */ diff --git a/include/linux/vserver/cvirt.h b/include/linux/vserver/cvirt.h new file mode 100644 index 000000000..ba3a25356 --- /dev/null +++ b/include/linux/vserver/cvirt.h @@ -0,0 +1,133 @@ +#if defined(__KERNEL__) && defined(_VX_INFO_DEF_) + +#include +#include +#include +#include +#include + +/* context sub struct */ + +struct _vx_cvirt { + int max_threads; + + unsigned int bias_cswtch; + struct timespec bias_idle; + struct timespec bias_tp; + uint64_t bias_jiffies; + + struct new_utsname utsname; +}; + +struct sock_acc { + atomic_t count; + atomic_t total; +}; + +struct _vx_cacct { + atomic_t nr_threads; + int nr_running; + + unsigned long total_forks; + + struct sock_acc sock[5][3]; +}; + + +static inline long vx_sock_count(struct _vx_cacct *cacct, int type, int pos) +{ + return atomic_read(&cacct->sock[type][pos].count); +} + + +static inline long vx_sock_total(struct _vx_cacct *cacct, int type, int pos) +{ + return atomic_read(&cacct->sock[type][pos].total); +} + + +extern uint64_t vx_idle_jiffies(void); + +static inline void vx_info_init_cvirt(struct _vx_cvirt *cvirt) +{ + uint64_t idle_jiffies = vx_idle_jiffies(); + + // new->virt.bias_cswtch = kstat.context_swtch; + cvirt->bias_jiffies = get_jiffies_64(); + + jiffies_to_timespec(idle_jiffies, &cvirt->bias_idle); + do_posix_clock_monotonic_gettime(&cvirt->bias_tp); + + down_read(&uts_sem); + cvirt->utsname = system_utsname; + up_read(&uts_sem); +} + +static inline void vx_info_exit_cvirt(struct _vx_cvirt *cvirt) +{ + return; +} + +static inline void vx_info_init_cacct(struct _vx_cacct *cacct) +{ + int i,j; + + atomic_set(&cacct->nr_threads, 1); + for (i=0; i<5; i++) { + for (j=0; j<3; j++) { + atomic_set(&cacct->sock[i][j].count, 0); + atomic_set(&cacct->sock[i][j].total, 0); + } + } +} + +static inline void vx_info_exit_cacct(struct _vx_cacct *cacct) +{ + return; +} + +static inline int vx_info_proc_cvirt(struct _vx_cvirt *cvirt, char *buffer) +{ + int length = 0; + return length; +} + +static inline int vx_info_proc_cacct(struct _vx_cacct *cacct, char *buffer) +{ + int i,j, length = 0; + static char *type[] = { "UNSPEC", "UNIX", "INET", "INET6", "OTHER" }; + + for (i=0; i<5; i++) { + length += sprintf(buffer + length, + "%s:", type[i]); + for (j=0; j<3; j++) { + length += sprintf(buffer + length, + "\t%12lu/%-12lu" + ,vx_sock_count(cacct, i, j) + ,vx_sock_total(cacct, i, j) + ); + } + buffer[length++] = '\n'; + } + return length; +} + +#else /* _VX_INFO_DEF_ */ +#ifndef _VX_CVIRT_H +#define _VX_CVIRT_H + +#include "switch.h" + +/* cvirt vserver commands */ + + +#ifdef __KERNEL__ + +struct timespec; + +void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle); + +#endif /* __KERNEL__ */ + +#endif /* _VX_CVIRT_H */ +#endif diff --git a/include/linux/vserver/dlimit.h b/include/linux/vserver/dlimit.h new file mode 100644 index 000000000..74872ed74 --- /dev/null +++ b/include/linux/vserver/dlimit.h @@ -0,0 +1,83 @@ +#ifndef _VX_DLIMIT_H +#define _VX_DLIMIT_H + +#include "switch.h" +#include + +/* inode vserver commands */ + +#define VCMD_add_dlimit VC_CMD(DLIMIT, 1, 0) +#define VCMD_rem_dlimit VC_CMD(DLIMIT, 2, 0) + +#define VCMD_set_dlimit VC_CMD(DLIMIT, 5, 0) +#define VCMD_get_dlimit VC_CMD(DLIMIT, 6, 0) + + +struct vcmd_ctx_dlimit_base_v0 { + const char __user *name; + uint32_t flags; +}; + +struct vcmd_ctx_dlimit_v0 { + const char __user *name; + uint32_t space_used; /* used space in kbytes */ + uint32_t space_total; /* maximum space in kbytes */ + uint32_t inodes_used; /* used inodes */ + uint32_t inodes_total; /* maximum inodes */ + uint32_t reserved; /* reserved for root in % */ + uint32_t flags; +}; + +#define CDLIM_UNSET (0ULL) +#define CDLIM_INFINITY (~0ULL) +#define CDLIM_KEEP (~1ULL) + + +#ifdef __KERNEL__ + +struct super_block; + +struct dl_info { + struct hlist_node dl_hlist; /* linked list of contexts */ + struct rcu_head dl_rcu; /* the rcu head */ + xid_t dl_xid; /* context id */ + atomic_t dl_usecnt; /* usage count */ + atomic_t dl_refcnt; /* reference count */ + + struct super_block *dl_sb; /* associated superblock */ + +// struct rw_semaphore dl_sem; /* protect the values */ + spinlock_t dl_lock; /* protect the values */ + + uint64_t dl_space_used; /* used space in bytes */ + uint64_t dl_space_total; /* maximum space in bytes */ + uint32_t dl_inodes_used; /* used inodes */ + uint32_t dl_inodes_total; /* maximum inodes */ + + unsigned int dl_nrlmult; /* non root limit mult */ +}; + +extern void rcu_free_dl_info(void *); +extern void unhash_dl_info(struct dl_info *); + +extern struct dl_info *locate_dl_info(struct super_block *, xid_t); + + +struct kstatfs; + +extern void vx_vsi_statfs(struct super_block *, struct kstatfs *); + + +extern int vc_add_dlimit(uint32_t, void __user *); +extern int vc_rem_dlimit(uint32_t, void __user *); + +extern int vc_set_dlimit(uint32_t, void __user *); +extern int vc_get_dlimit(uint32_t, void __user *); + + +typedef uint64_t dlsize_t; + + +#endif /* __KERNEL__ */ + +#endif /* _VX_DLIMIT_H */ diff --git a/include/linux/vserver/inode.h b/include/linux/vserver/inode.h new file mode 100644 index 000000000..aa8852f43 --- /dev/null +++ b/include/linux/vserver/inode.h @@ -0,0 +1,67 @@ +#ifndef _VX_INODE_H +#define _VX_INODE_H + +#include "switch.h" + +/* inode vserver commands */ + +#define VCMD_get_iattr_v0 VC_CMD(INODE, 1, 0) +#define VCMD_set_iattr_v0 VC_CMD(INODE, 2, 0) + +#define VCMD_get_iattr VC_CMD(INODE, 1, 1) +#define VCMD_set_iattr VC_CMD(INODE, 2, 1) + +struct vcmd_ctx_iattr_v0 { + /* device handle in id */ + uint64_t ino; + uint32_t xid; + uint32_t flags; + uint32_t mask; +}; + +struct vcmd_ctx_iattr_v1 { + const char __user *name; + uint32_t xid; + uint32_t flags; + uint32_t mask; +}; + + +#define IATTR_XID 0x01000000 + +#define IATTR_ADMIN 0x00000001 +#define IATTR_WATCH 0x00000002 +#define IATTR_HIDE 0x00000004 +#define IATTR_FLAGS 0x00000007 + +#define IATTR_BARRIER 0x00010000 +#define IATTR_IUNLINK 0x00020000 +#define IATTR_IMMUTABLE 0x00040000 + + +#ifdef CONFIG_PROC_SECURE +#define IATTR_PROC_DEFAULT ( IATTR_ADMIN | IATTR_HIDE ) +#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) +#else +#define IATTR_PROC_DEFAULT ( IATTR_ADMIN ) +#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) +#endif + +#ifdef __KERNEL__ + +#define vx_hide_check(c,m) (((m) & IATTR_HIDE) ? vx_check(c,m) : 1) + +extern int vc_get_iattr_v0(uint32_t, void __user *); +extern int vc_set_iattr_v0(uint32_t, void __user *); + +extern int vc_get_iattr(uint32_t, void __user *); +extern int vc_set_iattr(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +/* inode ioctls */ + +#define FIOC_GETXFLG _IOR('x', 5, long) +#define FIOC_SETXFLG _IOW('x', 6, long) + +#endif /* _VX_INODE_H */ diff --git a/include/linux/vserver/legacy.h b/include/linux/vserver/legacy.h new file mode 100644 index 000000000..1372c0fa6 --- /dev/null +++ b/include/linux/vserver/legacy.h @@ -0,0 +1,54 @@ +#ifndef _VX_LEGACY_H +#define _VX_LEGACY_H + +#include "switch.h" +#include "network.h" + +/* compatibiliy vserver commands */ + +#define VCMD_new_s_context VC_CMD(COMPAT, 1, 1) +#define VCMD_set_ipv4root VC_CMD(COMPAT, 2, 3) + +#define VCMD_create_context VC_CMD(VSETUP, 1, 0) + +/* compatibiliy vserver arguments */ + +struct vcmd_new_s_context_v1 { + uint32_t remove_cap; + uint32_t flags; +}; + +struct vcmd_set_ipv4root_v3 { + /* number of pairs in id */ + uint32_t broadcast; + struct { + uint32_t ip; + uint32_t mask; + } nx_mask_pair[NB_IPV4ROOT]; +}; + + +#define VX_INFO_LOCK 1 /* Can't request a new vx_id */ +#define VX_INFO_NPROC 4 /* Limit number of processes in a context */ +#define VX_INFO_PRIVATE 8 /* Noone can join this security context */ +#define VX_INFO_INIT 16 /* This process wants to become the */ + /* logical process 1 of the security */ + /* context */ +#define VX_INFO_HIDEINFO 32 /* Hide some information in /proc */ +#define VX_INFO_ULIMIT 64 /* Use ulimit of the current process */ + /* to become the global limits */ + /* of the context */ +#define VX_INFO_NAMESPACE 128 /* save private namespace */ + + +#define NB_S_CONTEXT 16 + +#define NB_IPV4ROOT 16 + + +#ifdef __KERNEL__ +extern int vc_new_s_context(uint32_t, void __user *); +extern int vc_set_ipv4root(uint32_t, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_LEGACY_H */ diff --git a/include/linux/vserver/limit.h b/include/linux/vserver/limit.h new file mode 100644 index 000000000..a7a50f972 --- /dev/null +++ b/include/linux/vserver/limit.h @@ -0,0 +1,140 @@ +#if defined(__KERNEL__) && defined(_VX_INFO_DEF_) + +#include +#include + +/* context sub struct */ + +#define RLIMIT_OPENFD 12 + +#define NUM_RLIMITS 16 + +#define VLIMIT_SOCK 16 + + +struct _vx_limit { + atomic_t ticks; + + unsigned long rlim[NUM_RLIMITS]; /* Context limit */ + unsigned long rmax[NUM_RLIMITS]; /* Context maximum */ + atomic_t rcur[NUM_RLIMITS]; /* Current value */ + atomic_t lhit[NUM_RLIMITS]; /* Limit hits */ +}; + +static inline void vx_info_init_limit(struct _vx_limit *limit) +{ + int lim; + + for (lim=0; limrlim[lim] = RLIM_INFINITY; + limit->rmax[lim] = 0; + atomic_set(&limit->rcur[lim], 0); + atomic_set(&limit->lhit[lim], 0); + } +} + +extern unsigned int vx_debug_limit; + +static inline void vx_info_exit_limit(struct _vx_limit *limit) +{ + unsigned long value; + unsigned int lim; + + if (!vx_debug_limit) + return; + for (lim=0; limrcur[lim]); + if (value) + printk("!!! limit: %p[%d] = %ld on exit.\n", + limit, lim, value); + } +} + +static inline void vx_limit_fixup(struct _vx_limit *limit) +{ + unsigned long value; + unsigned int lim; + + for (lim=0; limrcur[lim]); + if (value > limit->rmax[lim]) + limit->rmax[lim] = value; + if (limit->rmax[lim] > limit->rlim[lim]) + limit->rmax[lim] = limit->rlim[lim]; + } +} + +#define VX_LIMIT_FMT ":\t%10d\t%10ld\t%10ld\t%6d\n" + +#define VX_LIMIT_ARG(r) \ + ,atomic_read(&limit->rcur[r]) \ + ,limit->rmax[r] \ + ,limit->rlim[r] \ + ,atomic_read(&limit->lhit[r]) + +static inline int vx_info_proc_limit(struct _vx_limit *limit, char *buffer) +{ + vx_limit_fixup(limit); + return sprintf(buffer, + "PROC" VX_LIMIT_FMT + "VM" VX_LIMIT_FMT + "VML" VX_LIMIT_FMT + "RSS" VX_LIMIT_FMT + "FILES" VX_LIMIT_FMT + "OFD" VX_LIMIT_FMT + VX_LIMIT_ARG(RLIMIT_NPROC) + VX_LIMIT_ARG(RLIMIT_AS) + VX_LIMIT_ARG(RLIMIT_MEMLOCK) + VX_LIMIT_ARG(RLIMIT_RSS) + VX_LIMIT_ARG(RLIMIT_NOFILE) + VX_LIMIT_ARG(RLIMIT_OPENFD) + ); +} + +#else /* _VX_INFO_DEF_ */ +#ifndef _VX_LIMIT_H +#define _VX_LIMIT_H + +#include "switch.h" + +/* rlimit vserver commands */ + +#define VCMD_get_rlimit VC_CMD(RLIMIT, 1, 0) +#define VCMD_set_rlimit VC_CMD(RLIMIT, 2, 0) +#define VCMD_get_rlimit_mask VC_CMD(RLIMIT, 3, 0) + +struct vcmd_ctx_rlimit_v0 { + uint32_t id; + uint64_t minimum; + uint64_t softlimit; + uint64_t maximum; +}; + +struct vcmd_ctx_rlimit_mask_v0 { + uint32_t minimum; + uint32_t softlimit; + uint32_t maximum; +}; + +#define CRLIM_UNSET (0ULL) +#define CRLIM_INFINITY (~0ULL) +#define CRLIM_KEEP (~1ULL) + +#ifdef __KERNEL__ + +#include + +extern int vc_get_rlimit(uint32_t, void __user *); +extern int vc_set_rlimit(uint32_t, void __user *); +extern int vc_get_rlimit_mask(uint32_t, void __user *); + +struct sysinfo; + +void vx_vsi_meminfo(struct sysinfo *); +void vx_vsi_swapinfo(struct sysinfo *); + + +#endif /* __KERNEL__ */ + +#endif /* _VX_LIMIT_H */ +#endif diff --git a/include/linux/vserver/namespace.h b/include/linux/vserver/namespace.h new file mode 100644 index 000000000..140fc79f2 --- /dev/null +++ b/include/linux/vserver/namespace.h @@ -0,0 +1,55 @@ +#ifndef _VX_NAMESPACE_H +#define _VX_NAMESPACE_H + +#include + + +/* virtual host info names */ + +#define VCMD_vx_set_vhi_name VC_CMD(VHOST, 1, 0) +#define VCMD_vx_get_vhi_name VC_CMD(VHOST, 2, 0) + +struct vcmd_vx_vhi_name_v0 { + uint32_t field; + char name[65]; +}; + + +enum vx_vhi_name_field { + VHIN_CONTEXT=0, + VHIN_SYSNAME, + VHIN_NODENAME, + VHIN_RELEASE, + VHIN_VERSION, + VHIN_MACHINE, + VHIN_DOMAINNAME, +}; + + +#ifdef __KERNEL__ + +#include + +extern int vc_set_vhi_name(uint32_t, void __user *); +extern int vc_get_vhi_name(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_enter_namespace VC_CMD(PROCALT, 1, 0) +#define VCMD_cleanup_namespace VC_CMD(PROCALT, 2, 0) +#define VCMD_set_namespace VC_CMD(PROCALT, 3, 0) + +#ifdef __KERNEL__ + +struct vx_info; +struct namespace; +struct fs_struct; + +extern int vx_set_namespace(struct vx_info *, struct namespace *, struct fs_struct *); + +extern int vc_enter_namespace(uint32_t, void __user *); +extern int vc_cleanup_namespace(uint32_t, void __user *); +extern int vc_set_namespace(uint32_t, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_NAMESPACE_H */ diff --git a/include/linux/vserver/network.h b/include/linux/vserver/network.h new file mode 100644 index 000000000..086f566c4 --- /dev/null +++ b/include/linux/vserver/network.h @@ -0,0 +1,146 @@ +#ifndef _VX_NETWORK_H +#define _VX_NETWORK_H + +#define MAX_N_CONTEXT 65535 /* Arbitrary limit */ + +#define NX_DYNAMIC_ID ((uint32_t)-1) /* id for dynamic context */ + +#define NB_IPV4ROOT 16 + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + + +struct nx_info { + struct hlist_node nx_hlist; /* linked list of nxinfos */ + struct rcu_head nx_rcu; /* the rcu head */ + nid_t nx_id; /* vnet id */ + atomic_t nx_usecnt; /* usage count */ + atomic_t nx_refcnt; /* reference count */ + + uint64_t nx_flags; /* network flag word */ + uint64_t nx_ncaps; /* network capabilities */ + + int nbipv4; + __u32 ipv4[NB_IPV4ROOT]; /* Process can only bind to these IPs */ + /* The first one is used to connect */ + /* and for bind any service */ + /* The other must be used explicity */ + __u32 mask[NB_IPV4ROOT]; /* Netmask for each ipv4 */ + /* Used to select the proper source */ + /* address for sockets */ + __u32 v4_bcast; /* Broadcast address to receive UDP */ + + char nx_name[65]; /* network context name */ +}; + + +extern void rcu_free_nx_info(void *); +extern void unhash_nx_info(struct nx_info *); + +extern struct nx_info *locate_nx_info(int); +extern struct nx_info *locate_or_create_nx_info(int); + +extern int get_nid_list(int, unsigned int *, int); +extern int nx_info_is_hashed(nid_t); + +extern int nx_migrate_task(struct task_struct *, struct nx_info *); + +struct in_ifaddr; +struct net_device; + +int ifa_in_nx_info(struct in_ifaddr *, struct nx_info *); +int dev_in_nx_info(struct net_device *, struct nx_info *); + + +#endif /* __KERNEL__ */ + +#include "switch.h" + +/* vinfo commands */ + +#define VCMD_task_nid VC_CMD(VINFO, 2, 0) + +#ifdef __KERNEL__ +extern int vc_task_nid(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_nx_info VC_CMD(VINFO, 6, 0) + +struct vcmd_nx_info_v0 { + uint32_t nid; + /* more to come */ +}; + +#ifdef __KERNEL__ +extern int vc_nx_info(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_net_create VC_CMD(VNET, 1, 0) +#define VCMD_net_migrate VC_CMD(NETMIG, 1, 0) + +#define VCMD_net_add VC_CMD(NETALT, 1, 0) +#define VCMD_net_remove VC_CMD(NETALT, 2, 0) + +struct vcmd_net_nx_v0 { + uint16_t type; + uint16_t count; + uint32_t ip[4]; + uint32_t mask[4]; + /* more to come */ +}; + +// IPN_TYPE_IPV4 + + +#ifdef __KERNEL__ +extern int vc_net_create(uint32_t, void __user *); +extern int vc_net_migrate(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_get_nflags VC_CMD(FLAGS, 5, 0) +#define VCMD_set_nflags VC_CMD(FLAGS, 6, 0) + +struct vcmd_net_flags_v0 { + uint64_t flagword; + uint64_t mask; +}; + +#ifdef __KERNEL__ +extern int vc_get_nflags(uint32_t, void __user *); +extern int vc_set_nflags(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define IPF_STATE_SETUP (1ULL<<32) + + +#define IPF_ONE_TIME (0x0001ULL<<32) + +#define VCMD_get_ncaps VC_CMD(FLAGS, 7, 0) +#define VCMD_set_ncaps VC_CMD(FLAGS, 8, 0) + +struct vcmd_net_caps_v0 { + uint64_t ncaps; + uint64_t cmask; +}; + +#ifdef __KERNEL__ +extern int vc_get_ncaps(uint32_t, void __user *); +extern int vc_set_ncaps(uint32_t, void __user *); + +#endif /* __KERNEL__ */ + +#define IPC_WOSSNAME 0x00000001 + + +#endif /* _VX_NETWORK_H */ diff --git a/include/linux/vserver/sched.h b/include/linux/vserver/sched.h new file mode 100644 index 000000000..0f4469383 --- /dev/null +++ b/include/linux/vserver/sched.h @@ -0,0 +1,139 @@ +#if defined(__KERNEL__) && defined(_VX_INFO_DEF_) + +#include +#include +#include +#include +#include + +/* context sub struct */ + +struct _vx_sched { + spinlock_t tokens_lock; /* lock for this structure */ + + int fill_rate; /* Fill rate: add X tokens... */ + int interval; /* Divisor: per Y jiffies */ + atomic_t tokens; /* number of CPU tokens in this context */ + int tokens_min; /* Limit: minimum for unhold */ + int tokens_max; /* Limit: no more than N tokens */ + uint32_t jiffies; /* add an integral multiple of Y to this */ + + uint64_t ticks; /* token tick events */ + cpumask_t cpus_allowed; /* cpu mask for context */ +}; + +static inline void vx_info_init_sched(struct _vx_sched *sched) +{ + /* scheduling; hard code starting values as constants */ + sched->fill_rate = 1; + sched->interval = 4; + sched->tokens_min = HZ >> 4; + sched->tokens_max = HZ >> 1; + sched->jiffies = jiffies; + sched->tokens_lock = SPIN_LOCK_UNLOCKED; + + atomic_set(&sched->tokens, HZ >> 2); + sched->cpus_allowed = CPU_MASK_ALL; +} + +static inline void vx_info_exit_sched(struct _vx_sched *sched) +{ + return; +} + +static inline int vx_info_proc_sched(struct _vx_sched *sched, char *buffer) +{ + return sprintf(buffer, + "Ticks:\t%16lld\n" + "Token:\t\t%8d\n" + "FillRate:\t%8d\n" + "Interval:\t%8d\n" + "TokensMin:\t%8d\n" + "TokensMax:\t%8d\n" + ,(unsigned long long)sched->ticks + ,atomic_read(&sched->tokens) + ,sched->fill_rate + ,sched->interval + ,sched->tokens_min + ,sched->tokens_max + ); +} + + +#else /* _VX_INFO_DEF_ */ +#ifndef _VX_SCHED_H +#define _VX_SCHED_H + +#include "switch.h" + +/* sched vserver commands */ + +#define VCMD_set_sched VC_CMD(SCHED, 1, 2) + +struct vcmd_set_sched_v2 { + int32_t fill_rate; + int32_t interval; + int32_t tokens; + int32_t tokens_min; + int32_t tokens_max; + uint64_t cpu_mask; +}; + +#define SCHED_KEEP (-2) + +#ifdef __KERNEL__ + +extern int vc_set_sched_v1(uint32_t, void __user *); +extern int vc_set_sched(uint32_t, void __user *); + + +#define VAVAVOOM_RATIO 50 + +#include "context.h" + + +/* scheduling stuff */ + +int effective_vavavoom(struct task_struct *, int); + +int vx_tokens_recalc(struct vx_info *); + +/* new stuff ;) */ + +static inline int vx_tokens_avail(struct vx_info *vxi) +{ + return atomic_read(&vxi->sched.tokens); +} + +static inline void vx_consume_token(struct vx_info *vxi) +{ + atomic_dec(&vxi->sched.tokens); +} + +static inline int vx_need_resched(struct task_struct *p) +{ +#ifdef CONFIG_VSERVER_HARDCPU + struct vx_info *vxi = p->vx_info; + + if (vxi) { + int tokens; + + p->time_slice--; + if (atomic_read(&vxi->vx_usecnt) < 1) + printk("need_resched: p=%p, s=%ld, ref=%d, id=%d/%d\n", + p, p->state, atomic_read(&vxi->vx_usecnt), + vxi->vx_id, p->xid); + if ((tokens = vx_tokens_avail(vxi)) > 0) + vx_consume_token(vxi); + return ((p->time_slice == 0) || (tokens < 1)); + } +#endif + p->time_slice--; + return (p->time_slice == 0); +} + + +#endif /* __KERNEL__ */ + +#endif /* _VX_SCHED_H */ +#endif diff --git a/include/linux/vserver/signal.h b/include/linux/vserver/signal.h new file mode 100644 index 000000000..391112768 --- /dev/null +++ b/include/linux/vserver/signal.h @@ -0,0 +1,19 @@ +#ifndef _VX_SIGNAL_H +#define _VX_SIGNAL_H + +#include "switch.h" + +/* context signalling */ + +#define VCMD_ctx_kill VC_CMD(PROCTRL, 1, 0) + +struct vcmd_ctx_kill_v0 { + int32_t pid; + int32_t sig; +}; + +#ifdef __KERNEL__ +extern int vc_ctx_kill(uint32_t, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_SIGNAL_H */ diff --git a/include/linux/vserver/switch.h b/include/linux/vserver/switch.h new file mode 100644 index 000000000..0e4c62dae --- /dev/null +++ b/include/linux/vserver/switch.h @@ -0,0 +1,96 @@ +#ifndef _VX_SWITCH_H +#define _VX_SWITCH_H + +#include + +#define VC_CATEGORY(c) (((c) >> 24) & 0x3F) +#define VC_COMMAND(c) (((c) >> 16) & 0xFF) +#define VC_VERSION(c) ((c) & 0xFFF) + +#define VC_CMD(c,i,v) ((((VC_CAT_ ## c) & 0x3F) << 24) \ + | (((i) & 0xFF) << 16) | ((v) & 0xFFF)) + +/* + + Syscall Matrix V2.7 + + |VERSION|CREATE |MODIFY |MIGRATE|CONTROL|EXPERIM| |SPECIAL|SPECIAL| + |STATS |DESTROY|ALTER |CHANGE |LIMIT |TEST | | | | + |INFO |SETUP | |MOVE | | | | | | + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + SYSTEM |VERSION|VSETUP |VHOST | | | | |DEVICES| | + HOST | 00| 01| 02| 03| 04| 05| | 06| 07| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + CPU | |VPROC |PROCALT|PROCMIG|PROCTRL| | |SCHED. | | + PROCESS| 08| 09| 10| 11| 12| 13| | 14| 15| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + MEMORY | | | | | | | |SWAP | | + | 16| 17| 18| 19| 20| 21| | 22| 23| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + NETWORK| |VNET |NETALT |NETMIG |NETCTL | | |SERIAL | | + | 24| 25| 26| 27| 28| 29| | 30| 31| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + DISK | | | | |DLIMIT | | |INODE | | + VFS | 32| 33| 34| 35| 36| 37| | 38| 39| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + OTHER | | | | | | | |VINFO | | + | 40| 41| 42| 43| 44| 45| | 46| 47| + =======+=======+=======+=======+=======+=======+=======+ +=======+=======+ + SPECIAL| | | | |FLAGS | | | | | + | 48| 49| 50| 51| 52| 53| | 54| 55| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + SPECIAL| | | | |RLIMIT |SYSCALL| | |COMPAT | + | 56| 57| 58| 59| 60|TEST 61| | 62| 63| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + +*/ + +#define VC_CAT_VERSION 0 + +#define VC_CAT_VSETUP 1 +#define VC_CAT_VHOST 2 + +#define VC_CAT_VPROC 9 +#define VC_CAT_PROCALT 10 +#define VC_CAT_PROCMIG 11 +#define VC_CAT_PROCTRL 12 + +#define VC_CAT_SCHED 14 + +#define VC_CAT_VNET 25 +#define VC_CAT_NETALT 26 +#define VC_CAT_NETMIG 27 +#define VC_CAT_NETCTRL 28 + +#define VC_CAT_DLIMIT 36 +#define VC_CAT_INODE 38 + +#define VC_CAT_VINFO 46 + +#define VC_CAT_FLAGS 52 +#define VC_CAT_RLIMIT 60 + +#define VC_CAT_SYSTEST 61 +#define VC_CAT_COMPAT 63 + +/* interface version */ + +#define VCI_VERSION 0x00010016 + + +/* query version */ + +#define VCMD_get_version VC_CMD(VERSION, 0, 0) + + +#ifdef __KERNEL__ + +#include + +#define ENOTSUP -EOPNOTSUPP + +#else /* __KERNEL__ */ +#define __user +#endif /* __KERNEL__ */ + +#endif /* _VX_SWITCH_H */ diff --git a/include/linux/vserver/xid.h b/include/linux/vserver/xid.h new file mode 100644 index 000000000..ba52c2588 --- /dev/null +++ b/include/linux/vserver/xid.h @@ -0,0 +1,94 @@ +#ifndef _LINUX_XID_H_ +#define _LINUX_XID_H_ + +#ifdef CONFIG_INOXID_NONE + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0xFFFFFFFF + +#define INOXID_XID(uid, gid, xid) (0) + +#define XIDINO_UID(uid, xid) (uid) +#define XIDINO_GID(gid, xid) (gid) + +#endif + + +#ifdef CONFIG_INOXID_GID16 + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0x0000FFFF + +#define INOXID_XID(uid, gid, xid) (((gid) >> 16) & 0xFFFF) + +#define XIDINO_UID(uid, xid) (uid) +#define XIDINO_GID(gid, xid) (((gid) & 0xFFFF) | ((xid) << 16)) + + +#endif + + +#ifdef CONFIG_INOXID_GID24 + +#define MAX_UID 0x00FFFFFF +#define MAX_GID 0x00FFFFFF + +#define INOXID_XID(uid, gid, xid) ((((uid) >> 16) & 0xFF00) | (((gid) >> 24) & 0xFF)) + +#define XIDINO_UID(uid, xid) (((uid) & 0xFFFFFF) | (((xid) & 0xFF00) << 16)) +#define XIDINO_GID(gid, xid) (((gid) & 0xFFFFFF) | (((xid) & 0x00FF) << 24)) + +#endif + + +#ifdef CONFIG_INOXID_GID32 + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0xFFFFFFFF + +#define INOXID_XID(uid, gid, xid) (xid) + +#define XIDINO_UID(uid, xid) (uid) +#define XIDINO_GID(gid, xid) (gid) + +#endif + + +#ifdef CONFIG_INOXID_RUNTIME + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0xFFFFFFFF + +#define INOXID_XID(uid, gid, xid) (0) + +#define XIDINO_UID(uid, xid) (uid) +#define XIDINO_GID(gid, xid) (gid) + +#endif + + +#define INOXID_UID(uid, gid) ((uid) & MAX_UID) +#define INOXID_GID(uid, gid) ((gid) & MAX_GID) + +static inline uid_t vx_map_uid(uid_t uid) +{ + if ((uid > MAX_UID) && (uid != -1)) + uid = -2; + return (uid & MAX_UID); +} + +static inline gid_t vx_map_gid(gid_t gid) +{ + if ((gid > MAX_GID) && (gid != -1)) + gid = -2; + return (gid & MAX_GID); +} + + +#ifdef CONFIG_VSERVER_LEGACY +#define FIOC_GETXID _IOR('x', 1, long) +#define FIOC_SETXID _IOW('x', 2, long) +#define FIOC_SETXIDJ _IOW('x', 3, long) +#endif + +#endif /* _LINUX_XID_H_ */ diff --git a/include/linux/wait.h b/include/linux/wait.h index 52edb1786..7f2eaaee7 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -225,10 +225,10 @@ static inline void remove_wait_queue_locked(wait_queue_head_t *q, * They are racy. DO NOT use them, use the wait_event* interfaces above. * We plan to remove these interfaces during 2.7. */ -extern void FASTCALL(sleep_on(wait_queue_head_t *q)); +extern void __deprecated FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); -extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); +extern void __deprecated FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); diff --git a/include/net/af_unix.h b/include/net/af_unix.h index be877d75c..b47489bfc 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -11,9 +11,9 @@ extern rwlock_t unix_table_lock; extern atomic_t unix_tot_inflight; -static inline struct sock *first_unix_socket(int *i) +static inline struct sock *next_unix_socket_table(int *i) { - for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) { + for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { if (!hlist_empty(&unix_socket_table[*i])) return __sk_head(&unix_socket_table[*i]); } @@ -22,16 +22,19 @@ static inline struct sock *first_unix_socket(int *i) static inline struct sock *next_unix_socket(int *i, struct sock *s) { - struct sock *next = sk_next(s); - /* More in this chain? */ - if (next) - return next; - /* Look for next non-empty chain. */ - for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { - if (!hlist_empty(&unix_socket_table[*i])) - return __sk_head(&unix_socket_table[*i]); - } - return NULL; + do { + if (s) + s = sk_next(s); + if (!s) + s = next_unix_socket_table(i); + } while (s && !vx_check(s->sk_xid, VX_IDENT|VX_WATCH)); + return s; +} + +static inline struct sock *first_unix_socket(int *i) +{ + *i = 0; + return next_unix_socket(i, NULL); } #define forall_unix_sockets(i, s) \ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 830888147..3cb77ae85 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -358,12 +358,12 @@ int hci_dev_open(__u16 dev); int hci_dev_close(__u16 dev); int hci_dev_reset(__u16 dev); int hci_dev_reset_stat(__u16 dev); -int hci_dev_cmd(unsigned int cmd, void __user *arg); -int hci_get_dev_list(void __user *arg); -int hci_get_dev_info(void __user *arg); -int hci_get_conn_list(void __user *arg); -int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); -int hci_inquiry(void __user *arg); +int hci_dev_cmd(unsigned int cmd, unsigned long arg); +int hci_get_dev_list(unsigned long arg); +int hci_get_dev_info(unsigned long arg); +int hci_get_conn_list(unsigned long arg); +int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg); +int hci_inquiry(unsigned long arg); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 819b06dfb..ce249f1e5 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -348,7 +348,7 @@ struct rfcomm_dev_list_req { struct rfcomm_dev_info dev_info[0]; }; -int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); +int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg); int rfcomm_init_ttys(void); void rfcomm_cleanup_ttys(void); diff --git a/include/net/ip.h b/include/net/ip.h index 5a683ccd4..94ea1eda3 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -92,8 +92,8 @@ extern int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); extern int ip_local_deliver(struct sk_buff *skb); extern int ip_mr_input(struct sk_buff *skb); -extern int ip_output(struct sk_buff **pskb); -extern int ip_mc_output(struct sk_buff **pskb); +extern int ip_output(struct sk_buff *skb); +extern int ip_mc_output(struct sk_buff *skb); extern int ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 291149080..ea2781128 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -65,7 +65,7 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr, extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev, struct neighbour *neigh, struct in6_addr *addr, - int (*output)(struct sk_buff **)); + int (*output)(struct sk_buff *)); extern int ndisc_dst_gc(int *more); extern void fib6_force_start_gc(void); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8f647ae8e..06b350cef 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -355,7 +355,8 @@ extern int ip6_dst_lookup(struct sock *sk, * skb processing functions */ -extern int ip6_output(struct sk_buff **pskb); +extern int ip6_output(struct sk_buff *skb); +extern int ip6_output2(struct sk_buff *skb); extern int ip6_forward(struct sk_buff *skb); extern int ip6_input(struct sk_buff *skb); extern int ip6_mc_input(struct sk_buff *skb); diff --git a/include/net/route.h b/include/net/route.h index 0e7210e6d..c9914c6d8 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -33,6 +33,7 @@ #include #include #include +#include #ifndef __KERNEL__ #warning This file is not supposed to be used outside of kernel. @@ -148,6 +149,59 @@ static inline char rt_tos2priority(u8 tos) return ip_tos2prio[IPTOS_TOS(tos)>>1]; } +#define IPI_LOOPBACK 0x0100007f + +static inline int ip_find_src(struct nx_info *nxi, struct rtable **rp, struct flowi *fl) +{ + int err; + int i, n = nxi->nbipv4; + u32 ipv4root = nxi->ipv4[0]; + + if (ipv4root == 0) + return 0; + + if (fl->fl4_src == 0) { + if (n > 1) { + u32 foundsrc; + + err = __ip_route_output_key(rp, fl); + if (err) { + fl->fl4_src = ipv4root; + err = __ip_route_output_key(rp, fl); + } + if (err) + return err; + + foundsrc = (*rp)->rt_src; + ip_rt_put(*rp); + + for (i=0; imask[i]; + u32 ipv4 = nxi->ipv4[i]; + u32 net4 = ipv4 & mask; + + if (foundsrc == ipv4) { + fl->fl4_src = ipv4; + break; + } + if (!fl->fl4_src && (foundsrc & mask) == net4) + fl->fl4_src = ipv4; + } + } + if (fl->fl4_src == 0) + fl->fl4_src = (fl->fl4_dst == IPI_LOOPBACK) + ? IPI_LOOPBACK : ipv4root; + } else { + for (i=0; iipv4[i] == fl->fl4_src) + break; + } + if (i == n) + return -EPERM; + } + return 0; +} + static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif, u8 protocol, u16 sport, u16 dport, struct sock *sk) @@ -162,7 +216,22 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, .dport = dport } } }; int err; - if (!dst || !src) { + struct nx_info *nx_info = current->nx_info; + + if (sk) + nx_info = sk->sk_nx_info; + vxdprintk("ip_route_connect(%p) %p,%p;%lx\n", + sk, nx_info, sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + + if (nx_info) { + err = ip_find_src(nx_info, rp, &fl); + if (err) + return err; + if (fl.fl4_dst == IPI_LOOPBACK && !vx_check(0, VX_ADMIN)) + fl.fl4_dst = nx_info->ipv4[0]; + } + if (!fl.fl4_dst || !fl.fl4_src) { err = __ip_route_output_key(rp, &fl); if (err) return err; diff --git a/include/net/scm.h b/include/net/scm.h index b7ba74dbc..30e9fbb98 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -51,13 +51,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, { if (!msg->msg_control) { - if (sock->passcred || scm->fp) + if (test_bit(SOCK_PASS_CRED, &sock->flags) || scm->fp) msg->msg_flags |= MSG_CTRUNC; scm_destroy(scm); return; } - if (sock->passcred) + if (test_bit(SOCK_PASS_CRED, &sock->flags)) put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); if (!scm->fp) diff --git a/include/net/sock.h b/include/net/sock.h index eb7580c94..fcf6dfa05 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -50,6 +50,7 @@ #include #include +#include #include #include @@ -61,7 +62,7 @@ */ /* Define this to get the sk->sk_debug debugging facility. */ -#define SOCK_DEBUGGING +//#define SOCK_DEBUGGING #ifdef SOCK_DEBUGGING #define SOCK_DEBUG(sk, msg...) do { if ((sk) && ((sk)->sk_debug)) \ printk(KERN_DEBUG msg); } while (0) @@ -109,6 +110,10 @@ struct sock_common { struct hlist_node skc_node; struct hlist_node skc_bind_node; atomic_t skc_refcnt; + xid_t skc_xid; + struct vx_info *skc_vx_info; + nid_t skc_nid; + struct nx_info *skc_nx_info; }; /** @@ -164,12 +169,13 @@ struct sock_common { * @sk_timer - sock cleanup timer * @sk_stamp - time stamp of last packet received * @sk_socket - Identd and reporting IO signals - * @sk_user_data - RPC layer private data + * @sk_user_data - RPC and Tux layer private data * @sk_owner - module that owns this socket * @sk_state_change - callback to indicate change in the state of the sock * @sk_data_ready - callback to indicate there is data to be processed * @sk_write_space - callback to indicate there is bf sending space available * @sk_error_report - callback to indicate errors (e.g. %MSG_ERRQUEUE) + * @sk_create_child - callback to get new socket events * @sk_backlog_rcv - callback to process the backlog * @sk_destruct - called at sock freeing time, i.e. when all refcnt == 0 */ @@ -186,6 +192,10 @@ struct sock { #define sk_node __sk_common.skc_node #define sk_bind_node __sk_common.skc_bind_node #define sk_refcnt __sk_common.skc_refcnt +#define sk_xid __sk_common.skc_xid +#define sk_vx_info __sk_common.skc_vx_info +#define sk_nid __sk_common.skc_nid +#define sk_nx_info __sk_common.skc_nx_info volatile unsigned char sk_zapped; unsigned char sk_shutdown; unsigned char sk_use_write_queue; @@ -245,6 +255,7 @@ struct sock { struct timeval sk_stamp; struct socket *sk_socket; void *sk_user_data; + void *sk_ns; // For use by CKRM struct module *sk_owner; void *sk_security; void (*sk_state_change)(struct sock *sk); @@ -253,6 +264,7 @@ struct sock { void (*sk_error_report)(struct sock *sk); int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); + void (*sk_create_child)(struct sock *sk, struct sock *newsk); void (*sk_destruct)(struct sock *sk); }; @@ -398,21 +410,6 @@ static inline int sock_flag(struct sock *sk, enum sock_flags flag) return test_bit(flag, &sk->sk_flags); } -static inline void sk_acceptq_removed(struct sock *sk) -{ - sk->sk_ack_backlog--; -} - -static inline void sk_acceptq_added(struct sock *sk) -{ - sk->sk_ack_backlog++; -} - -static inline int sk_acceptq_is_full(struct sock *sk) -{ - return sk->sk_ack_backlog > sk->sk_max_ack_backlog; -} - /* The per-socket spinlock must be held here. */ #define sk_add_backlog(__sk, __skb) \ do { if (!(__sk)->sk_backlog.tail) { \ @@ -425,20 +422,6 @@ do { if (!(__sk)->sk_backlog.tail) { \ (__skb)->next = NULL; \ } while(0) -#define sk_wait_event(__sk, __timeo, __condition) \ -({ int rc; \ - release_sock(__sk); \ - rc = __condition; \ - if (!rc) { \ - *(__timeo) = schedule_timeout(*(__timeo)); \ - rc = __condition; \ - } \ - lock_sock(__sk); \ - rc; \ -}) - -extern int sk_wait_data(struct sock *sk, long *timeo); - /* IP protocol blocks we attach to sockets. * socket layer -> transport layer interface * transport -> network interface is defined by struct inet_proto @@ -927,11 +910,6 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) atomic_add(skb->truesize, &sk->sk_rmem_alloc); } -extern void sk_reset_timer(struct sock *sk, struct timer_list* timer, - unsigned long expires); - -extern void sk_stop_timer(struct sock *sk, struct timer_list* timer); - static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { int err = 0; @@ -1069,20 +1047,6 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) sk->sk_stamp = *stamp; } -/** - * sk_eat_skb - Release a skb if it is no longer needed - * @sk - socket to eat this skb from - * @skb - socket buffer to eat - * - * This routine must be called with interrupts disabled or with the socket - * locked so that the sk_buff queue operation is ok. -*/ -static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb) -{ - __skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); -} - extern atomic_t netstamp_needed; extern void sock_enable_timestamp(struct sock *sk); extern void sock_disable_timestamp(struct sock *sk); diff --git a/include/net/tcp.h b/include/net/tcp.h index 86e9f9add..45e5fdbac 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -195,6 +195,10 @@ struct tcp_tw_bucket { #define tw_node __tw_common.skc_node #define tw_bind_node __tw_common.skc_bind_node #define tw_refcnt __tw_common.skc_refcnt +#define tw_xid __tw_common.skc_xid +#define tw_vx_info __tw_common.skc_vx_info +#define tw_nid __tw_common.skc_nid +#define tw_nx_info __tw_common.skc_nx_info volatile unsigned char tw_substate; unsigned char tw_rcv_wscale; __u16 tw_sport; @@ -671,6 +675,10 @@ struct open_request { struct tcp_v6_open_req v6_req; #endif } af; +#ifdef CONFIG_ACCEPT_QUEUES + unsigned long acceptq_time_stamp; + int acceptq_class; +#endif }; /* SLAB cache for open requests. */ @@ -959,6 +967,7 @@ extern int tcp_transmit_skb(struct sock *, struct sk_buff *); extern void tcp_push_one(struct sock *, unsigned mss_now); extern void tcp_send_ack(struct sock *sk); extern void tcp_send_delayed_ack(struct sock *sk); +extern void cleanup_rbuf(struct sock *sk, int copied); /* tcp_timer.c */ extern void tcp_init_xmit_timers(struct sock *); @@ -970,9 +979,6 @@ extern int tcp_sync_mss(struct sock *sk, u32 pmtu); extern const char timer_bug_msg[]; -/* tcp_diag.c */ -extern void tcp_get_info(struct sock *, struct tcp_info *); - /* Read 'sendfile()'-style from a TCP socket */ typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t); @@ -989,7 +995,9 @@ static inline void tcp_clear_xmit_timer(struct sock *sk, int what) tp->pending = 0; #ifdef TCP_CLEAR_TIMERS - sk_stop_timer(sk, &tp->retransmit_timer); + if (timer_pending(&tp->retransmit_timer) && + del_timer(&tp->retransmit_timer)) + __sock_put(sk); #endif break; case TCP_TIME_DACK: @@ -997,7 +1005,9 @@ static inline void tcp_clear_xmit_timer(struct sock *sk, int what) tp->ack.pending = 0; #ifdef TCP_CLEAR_TIMERS - sk_stop_timer(sk, &tp->delack_timer); + if (timer_pending(&tp->delack_timer) && + del_timer(&tp->delack_timer)) + __sock_put(sk); #endif break; default: @@ -1026,13 +1036,15 @@ static inline void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long case TCP_TIME_PROBE0: tp->pending = what; tp->timeout = jiffies+when; - sk_reset_timer(sk, &tp->retransmit_timer, tp->timeout); + if (!mod_timer(&tp->retransmit_timer, tp->timeout)) + sock_hold(sk); break; case TCP_TIME_DACK: tp->ack.pending |= TCP_ACK_TIMER; tp->ack.timeout = jiffies+when; - sk_reset_timer(sk, &tp->delack_timer, tp->ack.timeout); + if (!mod_timer(&tp->delack_timer, tp->ack.timeout)) + sock_hold(sk); break; default: @@ -1399,8 +1411,9 @@ static __inline__ void tcp_minshall_update(struct tcp_opt *tp, int mss, struct s /* Return 0, if packet can be sent now without violation Nagle's rules: 1. It is full sized. 2. Or it contains FIN. - 3. Or TCP_NODELAY was set. - 4. Or TCP_CORK is not set, and all sent packets are ACKed. + 3. Or higher layers meant to force a packet boundary, hence the PSH bit. + 4. Or TCP_NODELAY was set. + 5. Or TCP_CORK is not set, and all sent packets are ACKed. With Minshall's modification: all sent small packets are ACKed. */ @@ -1794,13 +1807,91 @@ static inline int tcp_full_space( struct sock *sk) return tcp_win_from_space(sk->sk_rcvbuf); } +#ifdef CONFIG_ACCEPT_QUEUES +static inline void tcp_acceptq_removed(struct sock *sk, int class) +{ + tcp_sk(sk)->acceptq[class].aq_backlog--; +} + +static inline void tcp_acceptq_added(struct sock *sk, int class) +{ + tcp_sk(sk)->acceptq[class].aq_backlog++; +} + +static inline int tcp_acceptq_is_full(struct sock *sk, int class) +{ + return tcp_sk(sk)->acceptq[class].aq_backlog > + sk->sk_max_ack_backlog; +} + +static inline void tcp_set_acceptq(struct tcp_opt *tp, struct open_request *req) +{ + int class = req->acceptq_class; + int prev_class; + + if (!tp->acceptq[class].aq_ratio) { + req->acceptq_class = 0; + class = 0; + } + + tp->acceptq[class].aq_qcount++; + req->acceptq_time_stamp = jiffies; + + if (tp->acceptq[class].aq_tail) { + req->dl_next = tp->acceptq[class].aq_tail->dl_next; + tp->acceptq[class].aq_tail->dl_next = req; + tp->acceptq[class].aq_tail = req; + } else { /* if first request in the class */ + tp->acceptq[class].aq_head = req; + tp->acceptq[class].aq_tail = req; + + prev_class = class - 1; + while (prev_class >= 0) { + if (tp->acceptq[prev_class].aq_tail) + break; + prev_class--; + } + if (prev_class < 0) { + req->dl_next = tp->accept_queue; + tp->accept_queue = req; + } + else { + req->dl_next = tp->acceptq[prev_class].aq_tail->dl_next; + tp->acceptq[prev_class].aq_tail->dl_next = req; + } + } +} +static inline void tcp_acceptq_queue(struct sock *sk, struct open_request *req, + struct sock *child) +{ + tcp_set_acceptq(tcp_sk(sk),req); + req->sk = child; + tcp_acceptq_added(sk,req->acceptq_class); +} + +#else +static inline void tcp_acceptq_removed(struct sock *sk) +{ + sk->sk_ack_backlog--; +} + +static inline void tcp_acceptq_added(struct sock *sk) +{ + sk->sk_ack_backlog++; +} + +static inline int tcp_acceptq_is_full(struct sock *sk) +{ + return sk->sk_ack_backlog > sk->sk_max_ack_backlog; +} + static inline void tcp_acceptq_queue(struct sock *sk, struct open_request *req, struct sock *child) { struct tcp_opt *tp = tcp_sk(sk); req->sk = child; - sk_acceptq_added(sk); + tcp_acceptq_added(sk); if (!tp->accept_queue_tail) { tp->accept_queue = req; @@ -1811,16 +1902,55 @@ static inline void tcp_acceptq_queue(struct sock *sk, struct open_request *req, req->dl_next = NULL; } +#endif + struct tcp_listen_opt { u8 max_qlen_log; /* log_2 of maximal queued SYNs */ int qlen; +#ifdef CONFIG_ACCEPT_QUEUES + int qlen_young[NUM_ACCEPT_QUEUES]; +#else int qlen_young; +#endif int clock_hand; u32 hash_rnd; struct open_request *syn_table[TCP_SYNQ_HSIZE]; }; +#ifdef CONFIG_ACCEPT_QUEUES +static inline void +tcp_synq_removed(struct sock *sk, struct open_request *req) +{ + struct tcp_listen_opt *lopt = tcp_sk(sk)->listen_opt; + + if (--lopt->qlen == 0) + tcp_delete_keepalive_timer(sk); + if (req->retrans == 0) + lopt->qlen_young[req->acceptq_class]--; +} + +static inline void tcp_synq_added(struct sock *sk, struct open_request *req) +{ + struct tcp_listen_opt *lopt = tcp_sk(sk)->listen_opt; + + if (lopt->qlen++ == 0) + tcp_reset_keepalive_timer(sk, TCP_TIMEOUT_INIT); + lopt->qlen_young[req->acceptq_class]++; +} + +static inline int tcp_synq_len(struct sock *sk) +{ + return tcp_sk(sk)->listen_opt->qlen; +} + +static inline int tcp_synq_young(struct sock *sk, int class) +{ + return tcp_sk(sk)->listen_opt->qlen_young[class]; +} + +#else + static inline void tcp_synq_removed(struct sock *sk, struct open_request *req) { @@ -1850,6 +1980,7 @@ static inline int tcp_synq_young(struct sock *sk) { return tcp_sk(sk)->listen_opt->qlen_young; } +#endif static inline int tcp_synq_is_full(struct sock *sk) { diff --git a/include/net/tux.h b/include/net/tux.h new file mode 100644 index 000000000..44a38826a --- /dev/null +++ b/include/net/tux.h @@ -0,0 +1,800 @@ +#ifndef _NET_TUX_H +#define _NET_TUX_H + +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * tux.h: main structure definitions and function prototypes + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Maximum number of threads: */ +#define CONFIG_TUX_NUMTHREADS 8 + +/* Number of cachemiss/IO threads: */ +#define NR_IO_THREADS 32 + +/* Maximum number of listen sockets per thread: */ +#define CONFIG_TUX_NUMSOCKETS 16 + +extern spinlock_t tux_module_lock; +extern struct module *tux_module; +extern asmlinkage long (*sys_tux_ptr) (unsigned int action, user_req_t *u_info); + +#undef Dprintk + +extern int tux_TDprintk; +extern int tux_Dprintk; + +#define TUX_DEBUG CONFIG_TUX_DEBUG +#if CONFIG_TUX_DEBUG +# define TUX_BUG() BUG() + +# define TUX_DPRINTK 1 +# define TDprintk(x...) do { if (tux_TDprintk) { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } } while (0) +# define Dprintk(x...) do { if (tux_Dprintk == 1) TDprintk(x); } while (0) +#else +# define TUX_DPRINTK 0 +# define Dprintk(x...) do { } while (0) +# define TDprintk(x...) do { } while (0) +//# define TUX_BUG() BUG() +# define TUX_BUG() do { } while (0) +#endif + +#if 1 +# define INC_STAT(x) do { } while (0) +# define DEC_STAT(x) do { } while (0) +# define ADD_STAT(x,y) do { } while (0) +# define SUB_STAT(x,y) do { } while (0) +#else +# define INC_STAT(x) atomic_inc((atomic_t *)&kstat.x) +# define DEC_STAT(x) atomic_dec((atomic_t *)&kstat.x) +# define ADD_STAT(y,x) atomic_add(y,(atomic_t *)&kstat.x) +# define SUB_STAT(y,x) atomic_sub(y,(atomic_t *)&kstat.x) +#endif + +// lru needs this: + +# define DEBUG_DEL_LIST(x...) do { INIT_LIST_HEAD((x)); } while (0) + + +#define LOG_LEN (8*1024*1024UL) + +struct tux_req_struct; +typedef struct tux_req_struct tux_req_t; +typedef struct tux_threadinfo threadinfo_t; + +extern struct address_space_operations url_aops; + +typedef struct tcapi_template_s { + char *vfs_name; + struct list_head modules; + int (*query) (tux_req_t *req); + struct module *mod; + unsigned int userspace_id; +} tcapi_template_t; + +typedef struct mimetype_s { + struct list_head list; + + char *ext; + unsigned int ext_len; + char *type; + unsigned int type_len; + char *expire_str; + unsigned int expire_str_len; + + unsigned int special; +} mimetype_t; + +typedef struct tux_attribute_s { + mimetype_t *mime; + tcapi_template_t *tcapi; +} tux_attribute_t; + +#define MAX_TUX_ATOMS 8 + +typedef void (atom_func_t)(tux_req_t *req, int cachemiss); + +typedef struct tux_proto_s +{ + unsigned int defer_accept; + unsigned int can_redirect; + void (*got_request) (tux_req_t *req); + int (*parse_message) (tux_req_t *req, const int total_len); + atom_func_t *illegal_request; + atom_func_t *request_timeout; + void (*pre_log) (tux_req_t *req); + int (*check_req_err) (tux_req_t *req, int cachemiss); + char * (*print_dir_line) (tux_req_t *req, char *tmp, char *d_name, int d_len, int d_type, struct dentry *dentry, struct inode *inode); + const char *name; + struct nameidata main_docroot; +} tux_proto_t; + +typedef struct tux_socket_s { + tux_proto_t *proto; + unsigned int ip; + unsigned short port; + struct proc_dir_entry *entry; +} tux_socket_t; + +extern tux_socket_t tux_listen [CONFIG_TUX_NUMTHREADS][CONFIG_TUX_NUMSOCKETS]; + + +typedef struct abuf_s { + struct page *page; + char *buf; + unsigned int size; + unsigned int max_len; + unsigned int offset; + unsigned int left; + unsigned long flags; +} abuf_t; + +struct linux_dirent64 { + u64 d_ino; + s64 d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +}; + +struct getdents_callback64 { + struct linux_dirent64 * current_dir; + struct linux_dirent64 * previous; + int count; + int error; +}; + +#define TUX_MAGIC 0x12457801 + +#define MAX_TUX_ATOMS 8 + +struct tux_req_struct +{ + tux_proto_t *proto; + + int atom_idx; + atom_func_t *atoms [MAX_TUX_ATOMS]; + struct list_head work; + + struct list_head all; + struct list_head free; + struct list_head lru; + + unsigned long idle_input; + unsigned long wait_output_space; + + struct socket *sock; + struct dentry *dentry; + struct vfsmount *mnt; + struct dentry *docroot_dentry; + struct vfsmount *docroot_mnt; + struct dentry *cwd_dentry; + struct vfsmount *cwd_mnt; + + struct file in_file; + int fd; + read_descriptor_t desc; + u32 client_addr; + u32 client_port; + unsigned int virtual; + + loff_t total_file_len; + unsigned int lendigits; + loff_t offset_start; + loff_t offset_end; + loff_t output_len; + + loff_t ftp_offset_start; + + time_t mtime; + unsigned int etaglen; + char etag [40]; + + char usermode; + unsigned int usermodule_idx; + struct dentry *module_dentry; + struct vfsmount *module_mnt; + char *userbuf; + unsigned int userlen; + + tux_attribute_t *attr; + + threadinfo_t *ti; + wait_queue_t sleep; + wait_queue_t ftp_sleep; + + abuf_t abuf; + /* + * Parsed request fields. In-line strings are zero-delimited. + */ + const char *headers; + unsigned int headers_len; + + unsigned int parsed_len; + + // FTP part + ftp_command_t ftp_command; + u32 ftp_user_addr; + u16 ftp_user_port; + + struct socket *data_sock; + unsigned int prev_pos; + + // ls handing: + struct linux_dirent64 *dirp0; + unsigned int curroff, total; + +#define MAX_USERNAME_LEN 16 + char username[MAX_USERNAME_LEN]; + unsigned int username_len; + + // HTTP part + http_method_t method; + const char *method_str; + unsigned int method_len; + + http_version_t version; + const char *version_str; + unsigned int version_len; + + /* requested URI: */ + + const char *uri_str; + unsigned int uri_len; + + /* Objectname (filename/scriptname) this URI refers to: */ + +#define MAX_OBJECTNAME_LEN 256 + char objectname[MAX_OBJECTNAME_LEN + 4]; // space for .gz as well + unsigned int objectname_len; + + /* Query string within the URI: */ + + const char *query_str; + unsigned int query_len; + + /* Cookies: */ + + const char *cookies_str; + unsigned int cookies_len; + unsigned int parse_cookies; + + /* Content-TYpe */ + const char *content_type_str; + unsigned int content_type_len; + + /* Content-Length: */ + + const char *contentlen_str; + unsigned int contentlen_len; + unsigned int content_len; + + /* User-Agent: */ + + const char *user_agent_str; + unsigned int user_agent_len; + + /* Accept: */ + + const char *accept_str; + unsigned int accept_len; + + /* Accept-Charset: */ + + const char *accept_charset_str; + unsigned int accept_charset_len; + + /* Accept-Language: */ + + const char *accept_language_str; + unsigned int accept_language_len; + + /* Cache-Control: */ + + const char *cache_control_str; + unsigned int cache_control_len; + + /* If-Modified-Since: */ + + const char *if_modified_since_str; + unsigned int if_modified_since_len; + + /* If-None-Match: */ + const char *if_none_match_str; + unsigned int if_none_match_len; + + /* If-Range: */ + + const char *if_range_str; + unsigned int if_range_len; + + /* Negotiate: */ + + const char *negotiate_str; + unsigned int negotiate_len; + + /* Pragma: */ + + const char *pragma_str; + unsigned int pragma_len; + + /* Referer: */ + + const char *referer_str; + unsigned int referer_len; + + /* Accept-Encoding: */ + + const char *accept_encoding_str; + unsigned int accept_encoding_len; + unsigned int may_send_gzip; + unsigned int content_gzipped; + + /* Host */ + +#define MAX_HOST_LEN 128 + char host[MAX_HOST_LEN]; + unsigned int host_len; + + /* POSTed data: */ + + const char *post_data_str; + unsigned int post_data_len; + + unsigned int status; + + /* the file being sent */ + + unsigned int bytes_sent; +#if CONFIG_TUX_DEBUG + unsigned int bytes_expected; +#endif + unsigned long first_timestamp; + unsigned int body_len; + + unsigned int user_error; + + char error; + char postponed; + + char had_cachemiss; + char lookup_dir; + char lookup_404; + + char keep_alive; + struct timer_list keepalive_timer; + unsigned int total_bytes; + struct timer_list output_timer; + + unsigned int nr_keepalives; + + unsigned int event; + u64 private; + + unsigned int magic; + void (*real_data_ready)(struct sock *sk, int space); + void (*real_state_change)(struct sock *sk); + void (*real_write_space)(struct sock *sk); + void (*real_error_report)(struct sock *sk); + void (*real_destruct)(struct sock *sk); + + void (*ftp_real_data_ready)(struct sock *sk, int space); + void (*ftp_real_state_change)(struct sock *sk); + void (*ftp_real_write_space)(struct sock *sk); + void (*ftp_real_error_report)(struct sock *sk); + void (*ftp_real_create_child)(struct sock *sk, struct sock *newsk); + void (*ftp_real_destruct)(struct sock *sk); + +#if CONFIG_TUX_EXTENDED_LOG + unsigned long accept_timestamp; + unsigned long parse_timestamp; + unsigned long output_timestamp; + unsigned long flush_timestamp; +# define SET_TIMESTAMP(x) do { (x) = jiffies; } while (0) +#else +# define SET_TIMESTAMP(x) do { } while (0) +#endif + +}; + +extern void add_tux_atom (tux_req_t *req, atom_func_t *event_done); +extern void del_tux_atom (tux_req_t *req); +extern void tux_schedule_atom (tux_req_t *req, int cachemiss); +extern void add_req_to_workqueue (tux_req_t *req); + + +typedef struct iothread_s +{ + spinlock_t async_lock; + threadinfo_t *ti; + struct list_head async_queue; + wait_queue_head_t async_sleep; + unsigned int nr_async_pending; + unsigned int threads; + unsigned int shutdown; + wait_queue_head_t wait_shutdown; +} iothread_t; + +typedef struct tux_listen_s +{ + tux_proto_t *proto; + struct socket *sock; + unsigned int cloned; +} tux_listen_t; + +struct tux_threadinfo +{ + tux_req_t *userspace_req; + unsigned int started; + struct task_struct *thread; + iothread_t *iot; + wait_queue_t wait_event [CONFIG_TUX_NUMSOCKETS]; + wait_queue_t stop; + unsigned int pid; + + struct page *header_cache; + unsigned int header_offset; + + unsigned int nr_requests; + struct list_head all_requests; + + unsigned int nr_free_requests; + spinlock_t free_requests_lock; + struct list_head free_requests; + + spinlock_t work_lock; + struct list_head work_pending; + struct list_head lru; + unsigned int nr_lru; + + unsigned int listen_error; + tux_listen_t listen[CONFIG_TUX_NUMSOCKETS]; + + struct semaphore gzip_sem; + z_stream gzip_state; + + unsigned int cpu; + unsigned int __padding[16]; +}; + +typedef enum special_mimetypes { + NORMAL_MIME_TYPE, + MIME_TYPE_REDIRECT, + MIME_TYPE_CGI, + MIME_TYPE_MODULE, +} special_mimetypes_t; + +#if CONFIG_TUX_DEBUG +#if 0 +extern inline void url_hist_hit (int size) +{ + unsigned int idx = size/1024; + + if (idx >= URL_HIST_SIZE) + idx = URL_HIST_SIZE-1; + kstat.url_hist_hits[idx]++; +} +extern inline void url_hist_miss (int size) +{ + unsigned int idx = size/1024; + + if (idx >= URL_HIST_SIZE) + idx = URL_HIST_SIZE-1; + kstat.url_hist_misses[idx]++; +} +#endif +extern void __check_req_list (tux_req_t *req, struct list_head *list); +# define check_req_list __check_req_list +#else +# define check_req_list(req, list) do { } while (0) +#endif + +#define url_hist_hit(size) do { } while (0) +#define url_hist_miss(size) do { } while (0) + +extern char tux_common_docroot[200]; +extern char tux_http_subdocroot[200]; +extern char tux_ftp_subdocroot[200]; +extern char tux_logfile[200]; +extern char tux_cgiroot[200]; +extern char tux_404_page[200]; +extern char tux_default_vhost[200]; +extern char tux_extra_html_header[600]; +extern unsigned int tux_extra_html_header_size; +extern int tux_cgi_uid; +extern int tux_cgi_gid; +extern unsigned int tux_clientport; +extern unsigned int tux_logging; +extern unsigned int tux_threads; +extern unsigned int tux_keepalive_timeout; +extern unsigned int tux_max_output_bandwidth; +extern unsigned int tux_max_backlog; +extern unsigned int tux_max_connect; +extern unsigned int tux_mode_forbidden; +extern unsigned int tux_mode_allowed; +extern unsigned int tux_logentry_align_order; +extern unsigned int tux_nonagle; +extern unsigned int tux_ack_pingpong; +extern unsigned int tux_push_all; +extern unsigned int tux_zerocopy_parse; +extern unsigned int tux_generate_etags; +extern unsigned int tux_generate_last_mod; +extern unsigned int tux_generate_cache_control; +extern unsigned int tux_ip_logging; +extern unsigned int tux_ftp_wait_close; +extern unsigned int tux_ftp_log_retr_only; +extern unsigned int tux_hide_unreadable; + +typedef enum virtual_server { + TUX_VHOST_NONE, + TUX_VHOST_HOST, + TUX_VHOST_IP, + TUX_VHOST_IP_HOST, +} virtual_server_t; + +extern unsigned int tux_virtual_server; +extern unsigned int mass_hosting_hash; +extern unsigned int strip_host_tail; +extern unsigned int tux_ftp_virtual_server; + +extern unsigned int tux_max_object_size; +extern unsigned int tux_max_free_requests; +extern unsigned int tux_defer_accept; + +extern struct socket * start_listening(tux_socket_t *listen, int nr); +extern void stop_listening(struct socket **sock); +extern void start_sysctl(void); +extern void end_sysctl(void); +extern void flush_request (tux_req_t *req, int cachemiss); +extern void unlink_tux_socket (tux_req_t *req); +extern void unlink_tux_data_socket (tux_req_t *req); +extern void unlink_tux_listen_socket (tux_req_t *req); +extern void link_tux_ftp_accept_socket (tux_req_t *req, struct socket *sock); +extern void link_tux_data_socket (tux_req_t *req, struct socket *sock); +extern void tux_push_req (tux_req_t *req); +extern int send_sync_buf (tux_req_t *req, struct socket *sock, const char *buf, const size_t length, unsigned long flags); +extern void __send_async_message (tux_req_t *req, const char *message, int status, unsigned int size, int push); +#define send_async_message(req,str,status,push) \ + __send_async_message(req,str,status,strlen(str),push) + +extern void send_success (tux_req_t *req, struct socket *sock); +extern void send_async_err_not_found (tux_req_t *req); +extern void send_async_timed_out (tux_req_t *req); + +extern void kfree_req (tux_req_t *req); +extern int accept_requests (threadinfo_t *ti); +extern int process_requests (threadinfo_t *ti, tux_req_t **user_req); +extern int flush_freequeue (threadinfo_t * ti); +extern int tux_flush_workqueue (threadinfo_t *ti); +extern tux_req_t * pick_userspace_req (threadinfo_t *ti); +extern atom_func_t redirect_request; +extern atom_func_t parse_request; +extern void queue_cachemiss (tux_req_t *req); +extern int start_cachemiss_threads (threadinfo_t *ti); +extern void stop_cachemiss_threads (threadinfo_t *ti); +struct file * tux_open_file(char *filename, int mode); +extern void start_log_thread (void); +extern void stop_log_thread (void); +extern void add_mimetype (char *new_ext, char *new_type, char *new_expire); +extern void free_mimetypes (void); +extern int lookup_object (tux_req_t *req, const unsigned int flag); +extern int handle_gzip_req (tux_req_t *req, unsigned int flags); +extern struct dentry * tux_lookup (tux_req_t *req, const char *filename, const unsigned int flag, struct vfsmount **mnt); +extern tcapi_template_t * lookup_tuxmodule (const char *filename); +extern int register_tuxmodule (tcapi_template_t *tcapi); +extern tcapi_template_t * unregister_tuxmodule (char *vfs_name); +extern tcapi_template_t * get_first_usermodule (void); +extern int user_register_module (user_req_t *u_info); +extern int user_unregister_module (user_req_t *u_info); +extern void unregister_all_tuxmodules (void); + +typedef struct exec_param_s { + char *command; + char **argv; + char **envp; + unsigned int pipe_fds; +} exec_param_t; + +extern pid_t tux_exec_process (char *command, char **argv, char **envp, int pipe_fds, exec_param_t *param, int wait); + +extern void start_external_cgi (tux_req_t *req); +extern tcapi_template_t extcgi_tcapi; + +extern void queue_output_req (tux_req_t *req, threadinfo_t *ti); +extern void queue_userspace_req (tux_req_t *req, threadinfo_t *ti); + + +extern void __log_request (tux_req_t *req); +extern inline void log_request (tux_req_t *req) +{ + if (tux_logging) + __log_request(req); +} + +extern int __connection_too_fast (tux_req_t *req); + +#define connection_too_fast(req) \ + ({ \ + int __ret = 1; \ + if (unlikely(tux_max_output_bandwidth)) \ + __ret = __connection_too_fast(req); \ + __ret; \ + }) + +extern void trunc_headers (tux_req_t *req); +extern int generic_send_file (tux_req_t *req, struct socket *sock, int cachemiss); +extern int tux_fetch_file (tux_req_t *req, int nonblock); + +extern void postpone_request (tux_req_t *req); +extern int continue_request (int fd); +extern void tux_push_pending (struct sock *sk); +extern void zap_request (tux_req_t *req, int cachemiss); +extern int add_output_space_event (tux_req_t *req, struct socket *sock); + +extern void reap_kids (void); +extern void unuse_frag (struct sk_buff *skb, skb_frag_t *frag); +extern skb_frag_t * build_dynbuf_frag (tux_req_t *req, unsigned int size); +extern int tux_permission (struct inode *inode); +extern void flush_all_signals (void); + +#define D() Dprintk("{%s:%d}\n", __FILE__, __LINE__) + +extern int nr_async_io_pending (void); + +extern void __add_keepalive_timer (tux_req_t *req); +#define add_keepalive_timer(req) \ +do { \ + if (tux_keepalive_timeout) { \ + Dprintk("add_keepalive_timer(%p).\n", (req)); \ + __add_keepalive_timer(req); \ + } \ +} while (0) +extern void __del_keepalive_timer (tux_req_t *req); +#define del_keepalive_timer(req) \ +do { \ + if (tux_keepalive_timeout) { \ + Dprintk("del_keepalive_timer(%p).\n", (req)); \ + __del_keepalive_timer(req); \ + } \ +} while (0) + +extern void del_output_timer (tux_req_t *req); +extern void output_timeout (tux_req_t *req); + +extern void print_req (tux_req_t *req); + +extern char tux_date [DATE_LEN]; + + +extern int nr_async_io_pending (void); +extern void tux_exit (void); +extern char * get_abuf (tux_req_t *req, unsigned int max_size); +extern void send_abuf (tux_req_t *req, unsigned int size, unsigned long flags); + + +extern int idle_event (tux_req_t *req); +extern int output_space_event (tux_req_t *req); +extern unsigned int log_cpu_mask; +extern unsigned int tux_compression; +extern unsigned int tux_noid; +extern unsigned int tux_cgi_inherit_cpu; +extern unsigned int tux_zerocopy_header; +extern unsigned int tux_zerocopy_sendfile; +extern unsigned int tux_cgi_cpu_mask; +extern tux_proto_t tux_proto_http; +extern tux_proto_t tux_proto_ftp; +extern unsigned int tux_all_userspace; +extern unsigned int tux_ignore_query; +extern unsigned int tux_redirect_logging; +extern unsigned int tux_referer_logging; +extern unsigned int tux_log_incomplete; +extern unsigned int tux_max_header_len; +extern unsigned int tux_cpu_offset; +extern unsigned int tux_ftp_login_message; + +extern void drop_permissions (void); +extern int query_extcgi (tux_req_t *req); +extern int tux_chroot (char *dir); + +extern void install_req_dentry (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt); +extern void release_req_dentry (tux_req_t *req); +extern void unidle_req (tux_req_t *req); +extern int nr_requests_used (void); + +#define req_err(req) do { (req)->error = 1; Dprintk("request %p error at %s:%d.\n", req, __FILE__, __LINE__); } while (0) + +#define enough_wspace(sk) (tcp_wspace(sk) >= tcp_min_write_space(sk)) +#define clear_keepalive(req) do { (req)->keep_alive = 0; Dprintk("keepalive cleared for req %p.\n", req); } while (0) + +extern int print_all_requests (threadinfo_t *ti); +extern unsigned int tux_max_keepalives; +extern int time_unix2ls (time_t zulu, char *buf); +extern void last_mod_time(char * curr, const time_t t); +extern int mdtm_time(char * curr, const time_t t); +extern time_t parse_time(const char *str, const int str_len); + +extern unsigned int nr_tux_threads; +extern threadinfo_t threadinfo[CONFIG_TUX_NUMTHREADS]; + +#define switch_docroot(req) do { if (((req)->docroot_dentry != current->fs->root) || ((req)->docroot_mnt != current->fs->rootmnt)) __switch_docroot(req); } while (0) +extern void __switch_docroot(tux_req_t *req); +extern void list_directory (tux_req_t *req, int cachemiss); +extern char * tux_print_path (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt, char *buf, unsigned int max_len); + +extern unsigned int tux_http_dir_indexing; + +int tux_gzip_compress (tux_req_t *req, unsigned char *data_in, unsigned char *data_out, __u32 *in_len, __u32 *out_len); + +struct dentry * __tux_lookup (tux_req_t *req, const char *filename, + struct nameidata *base, struct vfsmount **mnt); + +/* error codes for req->error */ +#define TUX_ERROR_REDIRECT 1 +#define TUX_ERROR_UNUSED 2 +#define TUX_ERROR_CONN_CLOSE 3 +#define TUX_ERROR_CONN_TIMEOUT 4 + +extern void __put_data_sock (tux_req_t *req); + +static inline void put_data_sock (tux_req_t *req) +{ + if (req->data_sock) + __put_data_sock(req); +} + +#define socket_input(sock) \ + (!skb_queue_empty(&(sock)->sk->sk_receive_queue) || \ + !skb_queue_empty(&(sock)->sk->sk_error_queue)) + +#define tux_kmalloc(size) \ +({ \ + void *__ptr; \ + \ + while (!(__ptr = kmalloc(size, GFP_KERNEL))) { \ + if (net_ratelimit()) \ + printk(KERN_WARNING "tux: OOM at %s:%d (%d bytes).\n", \ + __FILE__, __LINE__, size); \ + current->state = TASK_UNINTERRUPTIBLE; \ + schedule_timeout(1); \ + } \ + __ptr; \ +}) + +extern long tux_close(unsigned int fd); + +#endif diff --git a/include/net/tux_u.h b/include/net/tux_u.h new file mode 100644 index 000000000..24ba401b5 --- /dev/null +++ b/include/net/tux_u.h @@ -0,0 +1,163 @@ +#ifndef _NET_TUX_U_H +#define _NET_TUX_U_H + +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * tux_u.h: HTTP module API - HTTP interface to user-space + */ + +/* + * Different major versions are not compatible. + * Different minor versions are only downward compatible. + * Different patchlevel versions are downward and upward compatible. + */ +#define TUX_MAJOR_VERSION 3 +#define TUX_MINOR_VERSION 0 +#define TUX_PATCHLEVEL_VERSION 0 + +#define __KERNEL_SYSCALLS__ + +typedef enum http_versions { + HTTP_1_0, + HTTP_1_1 +} http_version_t; + +/* + * Request methods known to HTTP: + */ +typedef enum http_methods { + METHOD_NONE, + METHOD_GET, + METHOD_HEAD, + METHOD_POST, + METHOD_PUT, + NR_METHODS +} http_method_t; + +enum user_req { + TUX_ACTION_STARTUP = 1, + TUX_ACTION_SHUTDOWN = 2, + TUX_ACTION_STARTTHREAD = 3, + TUX_ACTION_STOPTHREAD = 4, + TUX_ACTION_EVENTLOOP = 5, + TUX_ACTION_GET_OBJECT = 6, + TUX_ACTION_SEND_OBJECT = 7, + TUX_ACTION_READ_OBJECT = 8, + TUX_ACTION_FINISH_REQ = 9, + TUX_ACTION_FINISH_CLOSE_REQ = 10, + TUX_ACTION_REGISTER_MODULE = 11, + TUX_ACTION_UNREGISTER_MODULE = 12, + TUX_ACTION_CURRENT_DATE = 13, + TUX_ACTION_REGISTER_MIMETYPE = 14, + TUX_ACTION_READ_HEADERS = 15, + TUX_ACTION_POSTPONE_REQ = 16, + TUX_ACTION_CONTINUE_REQ = 17, + TUX_ACTION_REDIRECT_REQ = 18, + TUX_ACTION_READ_POST_DATA = 19, + TUX_ACTION_SEND_BUFFER = 20, + TUX_ACTION_WATCH_PROXY_SOCKET = 21, + TUX_ACTION_WAIT_PROXY_SOCKET = 22, + TUX_ACTION_QUERY_VERSION = 23, + MAX_TUX_ACTION +}; + +enum tux_ret { + TUX_ERROR = -1, + TUX_RETURN_USERSPACE_REQUEST = 0, + TUX_RETURN_EXIT = 1, + TUX_RETURN_SIGNAL = 2, + TUX_CONTINUE_EVENTLOOP = 3, +}; + +#define MAX_URI_LEN 256 +#define MAX_COOKIE_LEN 128 +#define MAX_FIELD_LEN 64 +#define DATE_LEN 30 + +typedef struct user_req_s { + u32 version_major; + u32 version_minor; + u32 version_patch; + u32 http_version; + u32 http_method; + u32 http_status; + + u32 sock; + u32 event; + u32 error; + u32 thread_nr; + u32 bytes_sent; + u32 client_host; + u32 objectlen; + u32 module_index; + u32 keep_alive; + u32 cookies_len; + + u64 id; + u64 priv; + u64 object_addr; + + u8 query[MAX_URI_LEN]; + u8 objectname[MAX_URI_LEN]; + u8 cookies[MAX_COOKIE_LEN]; + u8 content_type[MAX_FIELD_LEN]; + u8 user_agent[MAX_FIELD_LEN]; + u8 accept[MAX_FIELD_LEN]; + u8 accept_charset[MAX_FIELD_LEN]; + u8 accept_encoding[MAX_FIELD_LEN]; + u8 accept_language[MAX_FIELD_LEN]; + u8 cache_control[MAX_FIELD_LEN]; + u8 if_modified_since[MAX_FIELD_LEN]; + u8 negotiate[MAX_FIELD_LEN]; + u8 pragma[MAX_FIELD_LEN]; + u8 referer[MAX_FIELD_LEN]; + u8 new_date[DATE_LEN]; + u8 pad[2]; + +} user_req_t; + +typedef enum ftp_commands { + FTP_COMM_NONE, + FTP_COMM_USER, + FTP_COMM_PASS, + FTP_COMM_ACCT, + FTP_COMM_CWD, + FTP_COMM_CDUP, + FTP_COMM_SMNT, + FTP_COMM_QUIT, + FTP_COMM_REIN, + FTP_COMM_PORT, + FTP_COMM_PASV, + FTP_COMM_TYPE, + FTP_COMM_STRU, + FTP_COMM_MODE, + FTP_COMM_RETR, + FTP_COMM_SIZE, + FTP_COMM_MDTM, + FTP_COMM_STOR, + FTP_COMM_STOU, + FTP_COMM_APPE, + FTP_COMM_ALLO, + FTP_COMM_REST, + FTP_COMM_RNFR, + FTP_COMM_RNTO, + FTP_COMM_ABOR, + FTP_COMM_DELE, + FTP_COMM_RMD, + FTP_COMM_MKD, + FTP_COMM_PWD, + FTP_COMM_LIST, + FTP_COMM_NLST, + FTP_COMM_SITE, + FTP_COMM_SYST, + FTP_COMM_STAT, + FTP_COMM_HELP, + FTP_COMM_NOOP, + FTP_COMM_FEAT, + FTP_COMM_CLNT, +} ftp_command_t; + +#endif diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 647049685..e6d768a96 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -216,7 +216,7 @@ struct xfrm_type void (*destructor)(struct xfrm_state *); int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); int (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); - int (*output)(struct sk_buff **pskb); + int (*output)(struct sk_buff *skb); /* Estimate maximal size of result of transformation of a dgram */ u32 (*get_max_size)(struct xfrm_state *, int size); }; diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h new file mode 100644 index 000000000..38fbb68c9 --- /dev/null +++ b/include/scsi/scsi_dbg.h @@ -0,0 +1,18 @@ +#ifndef _SCSI_SCSI_DBG_H +#define _SCSI_SCSI_DBG_H + +struct scsi_cmnd; +struct scsi_request; + +extern void scsi_print_command(struct scsi_cmnd *); +extern void __scsi_print_command(unsigned char *); +extern void scsi_print_sense(const char *, struct scsi_cmnd *); +extern void scsi_print_req_sense(const char *, struct scsi_request *); +extern void scsi_print_driverbyte(int); +extern void scsi_print_hostbyte(int); +extern void scsi_print_status(unsigned char); +extern int scsi_print_msg(const unsigned char *); +extern const char *scsi_sense_key_string(unsigned char); +extern const char *scsi_extd_sense_format(unsigned char, unsigned char); + +#endif /* _SCSI_SCSI_DBG_H */ diff --git a/include/sound/asound.h b/include/sound/asound.h index 69dc1829e..62841fe15 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -135,7 +135,7 @@ struct sndrv_hwdep_dsp_status { struct sndrv_hwdep_dsp_image { unsigned int index; /* W: DSP index */ unsigned char name[64]; /* W: ID (e.g. file name) */ - unsigned char __user *image; /* W: binary image */ + unsigned char *image; /* W: binary image */ size_t length; /* W: size of image in bytes */ unsigned long driver_data; /* W: driver-specific data */ }; @@ -446,13 +446,13 @@ struct sndrv_pcm_sync_ptr { struct sndrv_xferi { sndrv_pcm_sframes_t result; - void __user *buf; + void *buf; sndrv_pcm_uframes_t frames; }; struct sndrv_xfern { sndrv_pcm_sframes_t result; - void __user * __user *bufs; + void **bufs; sndrv_pcm_uframes_t frames; }; @@ -776,7 +776,7 @@ struct sndrv_ctl_elem_list { unsigned int space; /* W: count of element IDs to get */ unsigned int used; /* R: count of element IDs set */ unsigned int count; /* R: count of all elements */ - struct sndrv_ctl_elem_id __user *pids; /* R: IDs */ + struct sndrv_ctl_elem_id *pids; /* R: IDs */ unsigned char reserved[50]; }; diff --git a/include/sound/core.h b/include/sound/core.h index caf1b3c85..5d609309a 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -302,8 +302,8 @@ void snd_hidden_vfree(void *obj); #endif void *snd_kcalloc(size_t size, int flags); char *snd_kmalloc_strdup(const char *string, int flags); -int copy_to_user_fromio(void __user *dst, unsigned long src, size_t count); -int copy_from_user_toio(unsigned long dst, const void __user *src, size_t count); +int copy_to_user_fromio(void *dst, unsigned long src, size_t count); +int copy_from_user_toio(unsigned long dst, const void *src, size_t count); /* init.c */ diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 6182b7764..7ce25ed04 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1317,14 +1317,14 @@ typedef struct { unsigned int gpr_map[0x100]; /* initializers */ unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ - emu10k1_fx8010_control_gpr_t __user *gpr_add_controls; /* GPR controls to add/replace */ + emu10k1_fx8010_control_gpr_t *gpr_add_controls; /* GPR controls to add/replace */ unsigned int gpr_del_control_count; /* count of GPR controls to remove */ - snd_ctl_elem_id_t __user *gpr_del_controls; /* IDs of GPR controls to remove */ + snd_ctl_elem_id_t *gpr_del_controls; /* IDs of GPR controls to remove */ unsigned int gpr_list_control_count; /* count of GPR controls to list */ unsigned int gpr_list_control_total; /* total count of GPR controls */ - emu10k1_fx8010_control_gpr_t __user *gpr_list_controls; /* listed GPR controls */ + emu10k1_fx8010_control_gpr_t *gpr_list_controls; /* listed GPR controls */ unsigned long tram_valid[0xa0/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ unsigned int tram_data_map[0xa0]; /* data initializers */ diff --git a/include/sound/trident.h b/include/sound/trident.h index 255a5cbe6..5ded7d036 100644 --- a/include/sound/trident.h +++ b/include/sound/trident.h @@ -479,6 +479,6 @@ int snd_trident_free_pages(trident_t *trident, snd_util_memblk_t *blk); snd_util_memblk_t *snd_trident_synth_alloc(trident_t *trident, unsigned int size); int snd_trident_synth_free(trident_t *trident, snd_util_memblk_t *blk); int snd_trident_synth_bzero(trident_t *trident, snd_util_memblk_t *blk, int offset, int size); -int snd_trident_synth_copy_from_user(trident_t *trident, snd_util_memblk_t *blk, int offset, const char __user *data, int size); +int snd_trident_synth_copy_from_user(trident_t *trident, snd_util_memblk_t *blk, int offset, const char *data, int size); #endif /* __SOUND_TRIDENT_H */ diff --git a/init/Kconfig b/init/Kconfig index 210ca2cb7..aba5efde8 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -121,6 +121,75 @@ config BSD_PROCESS_ACCT up to the user level program to do useful things with this information. This is generally a good idea, so say Y. +menu "Class Based Kernel Resource Management" + +config CKRM + bool "Class Based Kernel Resource Management Core" + depends on EXPERIMENTAL + help + Class-based Kernel Resource Management is a framework for controlling + and monitoring resource allocation of user-defined groups of tasks or + incoming socket connections. For more information, please visit + http://ckrm.sf.net. + + If you say Y here, enable the Resource Class File System and atleast + one of the resource controllers below. Say N if you are unsure. + +config RCFS_FS + tristate "Resource Class File System (User API)" + depends on CKRM + help + RCFS is the filesystem API for CKRM. This separate configuration + option is provided only for debugging and will eventually disappear + since rcfs will be automounted whenever CKRM is configured. + + Say N if unsure, Y if you've enabled CKRM, M to debug rcfs + initialization. + +config CKRM_TYPE_TASKCLASS + bool "Class Manager for Task Groups" + depends on CKRM + help + TASKCLASS provides the extensions for CKRM to track task classes + This is the base to enable task class based resource control for + cpu, memory and disk I/O. + + Say N if unsure + +config CKRM_RES_NUMTASKS + tristate "Number of Tasks Resource Manager" + depends on CKRM_TYPE_TASKCLASS + default m + help + Provides a Resource Controller for CKRM that allows limiting no of + tasks a task class can have. + + Say N if unsure, Y to use the feature. + +config CKRM_TYPE_SOCKETCLASS + bool "Class Manager for socket groups" + depends on CKRM + help + SOCKET provides the extensions for CKRM to track per socket + classes. This is the base to enable socket based resource + control for inbound connection control, bandwidth control etc. + + Say N if unsure. + +config CKRM_RES_LISTENAQ + tristate "Multiple Accept Queues Resource Manager" + depends on CKRM_TYPE_SOCKETCLASS && ACCEPT_QUEUES + default m + help + Provides a resource controller for CKRM to prioritize inbound + connection requests. See inbound control description for + "IP: TCP Multiple accept queues support". If you choose that + option choose this option to control the queue weights. + + If unsure, say N. + +endmenu + config SYSCTL bool "Sysctl support" ---help--- @@ -227,6 +296,15 @@ menuconfig EMBEDDED environments which can tolerate a "non-standard" kernel. Only use this if you really know what you are doing. +config DELAY_ACCT + bool "Enable delay accounting (EXPERIMENTAL)" + help + In addition to counting frequency the total delay in ns is also + recorded. CPU delays are specified as cpu-wait and cpu-run. Memory + delay is recorded for minor and major faults. Information is + accessible through /proc//delay. + + config KALLSYMS bool "Load all symbols for debugging/kksymoops" if EMBEDDED default y @@ -264,7 +342,7 @@ config EPOLL source "drivers/block/Kconfig.iosched" config CC_OPTIMIZE_FOR_SIZE - bool "Optimize for size" if EMBEDDED + bool "Optimize for size" default y if ARM || H8300 default n help diff --git a/init/main.c b/init/main.c index 613aaaba8..f77694320 100644 --- a/init/main.c +++ b/init/main.c @@ -47,6 +47,8 @@ #include #include +#include + /* * This is one of the first .c files built. Error out early * if we have compiler trouble.. @@ -186,7 +188,7 @@ void __devinit calibrate_delay(void) loops_per_jiffy = (1<<12); printk("Calibrating delay loop... "); - while ((loops_per_jiffy <<= 1) != 0) { + while (loops_per_jiffy <<= 1) { /* wait for "start of" clock tick */ ticks = jiffies; while (ticks == jiffies) @@ -432,6 +434,11 @@ asmlinkage void __init start_kernel(void) rcu_init(); init_IRQ(); pidhash_init(); + /* MEF: In 2.6.5. ckrm_init was right after pidhash_init() but + before sched_init(). Will leave it after pidhash_init() + and cross finger. + */ + ckrm_init(); init_timers(); softirq_init(); time_init(); @@ -480,6 +487,7 @@ asmlinkage void __init start_kernel(void) #ifdef CONFIG_PROC_FS proc_root_init(); #endif + check_bugs(); /* @@ -632,7 +640,7 @@ static int init(void * unused) * check if there is an early userspace init. If yes, let it do all * the work */ - if (sys_access((const char __user *) "/init", 0) == 0) + if (sys_access("/init", 0) == 0) execute_command = "/init"; else prepare_namespace(); @@ -646,7 +654,7 @@ static int init(void * unused) unlock_kernel(); system_state = SYSTEM_RUNNING; - if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) + if (sys_open("/dev/console", O_RDWR, 0) < 0) printk("Warning: unable to open an initial console.\n"); (void) sys_dup(0); diff --git a/ipc/msg.c b/ipc/msg.c index 5f256af8b..210641516 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -96,6 +96,7 @@ static int newque (key_t key, int msgflg) msq->q_perm.mode = (msgflg & S_IRWXUGO); msq->q_perm.key = key; + msq->q_perm.xid = current->xid; msq->q_perm.security = NULL; retval = security_msg_queue_alloc(msq); @@ -788,7 +789,11 @@ static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int l for(i = 0; i <= msg_ids.max_id; i++) { struct msg_queue * msq; msq = msg_lock(i); - if(msq != NULL) { + if (msq) { + if (!vx_check(msq->q_perm.xid, VX_IDENT)) { + msg_unlock(msq); + continue; + } len += sprintf(buffer + len, "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", msq->q_perm.key, msg_buildid(i,msq->q_perm.seq), diff --git a/ipc/sem.c b/ipc/sem.c index 6316aca9c..d226d3dd1 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -175,6 +175,7 @@ static int newary (key_t key, int nsems, int semflg) sma->sem_perm.mode = (semflg & S_IRWXUGO); sma->sem_perm.key = key; + sma->sem_perm.xid = current->xid; sma->sem_perm.security = NULL; retval = security_sem_alloc(sma); @@ -1296,7 +1297,11 @@ static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int l for(i = 0; i <= sem_ids.max_id; i++) { struct sem_array *sma; sma = sem_lock(i); - if(sma) { + if (sma) { + if (!vx_check(sma->sem_perm.xid, VX_IDENT)) { + sem_unlock(sma); + continue; + } len += sprintf(buffer + len, "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", sma->sem_perm.key, sem_buildid(i,sma->sem_perm.seq), diff --git a/ipc/shm.c b/ipc/shm.c index 9761e3bcb..9400dcd1b 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -189,6 +189,7 @@ static int newseg (key_t key, int shmflg, size_t size) return -ENOMEM; shp->shm_perm.key = key; + shp->shm_perm.xid = current->xid; shp->shm_flags = (shmflg & S_IRWXUGO); shp->shm_perm.security = NULL; @@ -504,14 +505,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) case SHM_LOCK: case SHM_UNLOCK: { -/* Allow superuser to lock segment in memory */ -/* Should the pages be faulted in here or leave it to user? */ -/* need to determine interaction with current->swappable */ - if (!capable(CAP_IPC_LOCK)) { + /* Allow superuser to lock segment in memory */ + if (!can_do_mlock()) { err = -EPERM; goto out; } - shp = shm_lock(shmid); if(shp==NULL) { err = -EINVAL; @@ -526,9 +524,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) goto out_unlock; if(cmd==SHM_LOCK) { - if (!is_file_hugepages(shp->shm_file)) - shmem_lock(shp->shm_file, 1); - shp->shm_flags |= SHM_LOCKED; + if (!is_file_hugepages(shp->shm_file)) { + err = shmem_lock(shp->shm_file, 1); + if (!err) + shp->shm_flags |= SHM_LOCKED; + } } else { if (!is_file_hugepages(shp->shm_file)) shmem_lock(shp->shm_file, 0); @@ -847,11 +847,15 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l struct shmid_kernel* shp; shp = shm_lock(i); - if(shp!=NULL) { + if (shp) { #define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" #define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" char *format; + if (!vx_check(shp->shm_perm.xid, VX_IDENT)) { + shm_unlock(shp); + continue; + } if (sizeof(size_t) <= sizeof(int)) format = SMALL_STRING; else diff --git a/ipc/util.c b/ipc/util.c index 81a145ede..0064a7980 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -105,8 +105,10 @@ int ipc_findkey(struct ipc_ids* ids, key_t key) */ for (id = 0; id <= max_id; id++) { p = ids->entries[id].p; - if(p==NULL) + if (p==NULL) continue; + if (!vx_check(p->xid, VX_IDENT)) + continue; if (key == p->key) return id; } @@ -369,6 +371,8 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag) { /* flag will most probably be 0 or S_...UGO from */ int requested_mode, granted_mode; + if (!vx_check(ipcp->xid, VX_ADMIN|VX_IDENT)) /* maybe just VX_IDENT? */ + return -1; requested_mode = (flag >> 6) | (flag >> 3) | flag; granted_mode = ipcp->mode; if (current->euid == ipcp->cuid || current->euid == ipcp->uid) @@ -377,8 +381,11 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag) granted_mode >>= 3; /* is there some bit set in requested_mode but not in granted_mode? */ if ((requested_mode & ~granted_mode & 0007) && - !capable(CAP_IPC_OWNER)) - return -1; + !capable(CAP_IPC_OWNER)) { + if (!can_do_mlock()) { + return -1; + } + } return security_ipc_permission(ipcp, flag); } diff --git a/kernel/Makefile b/kernel/Makefile index 238c65f60..e1b650130 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -7,7 +7,12 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o + kthread.o ckrm/ + +# mod-subdirs := vserver + +subdir-y += vserver +obj-y += vserver/vserver.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o diff --git a/kernel/ckrm/Makefile b/kernel/ckrm/Makefile new file mode 100644 index 000000000..58b9aad74 --- /dev/null +++ b/kernel/ckrm/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for CKRM +# + +ifeq ($(CONFIG_CKRM),y) + obj-y = ckrm.o ckrmutils.o +endif + +obj-$(CONFIG_CKRM_TYPE_TASKCLASS) += ckrm_tc.o +obj-$(CONFIG_CKRM_RES_NUMTASKS) += ckrm_tasks.o + +obj-$(CONFIG_CKRM_TYPE_SOCKETCLASS) += ckrm_sockc.o +obj-$(CONFIG_CKRM_RES_LISTENAQ) += ckrm_listenaq.o + diff --git a/kernel/ckrm/ckrm.c b/kernel/ckrm/ckrm.c new file mode 100644 index 000000000..43d14a8a9 --- /dev/null +++ b/kernel/ckrm/ckrm.c @@ -0,0 +1,1009 @@ +/* ckrm.c - Class-based Kernel Resource Management (CKRM) + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003, 2004 + * (C) Shailabh Nagar, IBM Corp. 2003, 2004 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Vivek Kashyap, IBM Corp. 2004 + * + * + * Provides kernel API of CKRM for in-kernel,per-resource controllers + * (one each for cpu, memory, io, network) and callbacks for + * classification modules. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 28 Aug 2003 + * Created. + * 06 Nov 2003 + * Made modifications to suit the new RBCE module. + * 10 Nov 2003 + * Fixed a bug in fork and exit callbacks. Added callbacks_active and + * surrounding logic. Added task paramter for all CE callbacks. + * 23 Mar 2004 + * moved to referenced counted class objects and correct locking + * 19 Apr 2004 + * Integrated ckrm hooks, classtypes, ... + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +rwlock_t ckrm_class_lock = RW_LOCK_UNLOCKED; // protect classlists + +struct rcfs_functions rcfs_fn ; +EXPORT_SYMBOL(rcfs_fn); + + +/************************************************************************** + * Helper Functions * + **************************************************************************/ + +/* + * Return TRUE if the given core class pointer is valid. + */ + +/* + * Return TRUE if the given resource is registered. + */ +inline unsigned int +is_res_regd(struct ckrm_classtype *clstype, int resid) +{ + return ( (resid>=0) && (resid < clstype->max_resid) && + test_bit(resid, &clstype->bit_res_ctlrs) + ); +} + +struct ckrm_res_ctlr* +ckrm_resctlr_lookup(struct ckrm_classtype *clstype, const char *resname) +{ + int resid = -1; + + for (resid=0; resid < clstype->max_resid; resid++) { + if (test_bit(resid, &clstype->bit_res_ctlrs)) { + struct ckrm_res_ctlr *rctrl = clstype->res_ctlrs[resid]; + if (!strncmp(resname, rctrl->res_name,CKRM_MAX_RES_NAME)) + return rctrl; + } + } + return NULL; +} +EXPORT_SYMBOL(ckrm_resctlr_lookup); + +/* given a classname return the class handle and its classtype*/ +void * +ckrm_classobj(char *classname, int *classTypeID) +{ + int i; + + *classTypeID = -1; + if (!classname || !*classname) { + return NULL; + } + + read_lock(&ckrm_class_lock); + for ( i=0 ; iclasses, clslist) { + if (core->name && !strcmp(core->name, classname)) { + // FIXME: should grep reference.. + read_unlock(&ckrm_class_lock); + *classTypeID = ctype->typeID; + return core; + } + } + } + read_unlock(&ckrm_class_lock); + return NULL; +} + +EXPORT_SYMBOL(is_res_regd); +EXPORT_SYMBOL(ckrm_classobj); + +/************************************************************************** + * Internal Functions/macros * + **************************************************************************/ + +static inline void +set_callbacks_active(struct ckrm_classtype *ctype) +{ + ctype->ce_cb_active = ((atomic_read(&ctype->ce_nr_users) > 0) && + (ctype->ce_callbacks.always_callback || (ctype->num_classes > 1))); +} + +int +ckrm_validate_and_grab_core(struct ckrm_core_class *core) +{ + int rc = 0; + read_lock(&ckrm_class_lock); + if (likely(ckrm_is_core_valid(core))) { + ckrm_core_grab(core); + rc = 1; + } + read_unlock(&ckrm_class_lock); + return rc; +} + +/**************************************************************************** + * Interfaces for classification engine * + ****************************************************************************/ + +/* + * Registering a callback structure by the classification engine. + * + * Returns typeId of class on success -errno for failure. + */ +int +ckrm_register_engine(const char *typename, ckrm_eng_callback_t *ecbs) +{ + struct ckrm_classtype *ctype; + + ctype = ckrm_find_classtype_by_name(typename); + if (ctype == NULL) + return (-ENOENT); + + ce_protect(ctype); + if (atomic_read(&ctype->ce_nr_users) != 1) { + // Some engine is acive, deregister it first. + ce_release(ctype); + return (-EBUSY); + } + + /* we require that either classify and class_delete are set (due to object reference) + * or that notify is set (in case no real classification is supported only notification + * also require that the function pointer be set the momement the mask is non-null + */ + if ( ! (((ecbs->classify) && (ecbs->class_delete)) || (ecbs->notify)) || + (ecbs->c_interest && ecbs->classify == NULL) || + (ecbs->n_interest && ecbs->notify == NULL) ) + { + ce_release(ctype); + return (-EINVAL); + } + + + /* Is any other engine registered for this classtype ? */ + if (ctype->ce_regd) { + ce_release(ctype); + return (-EINVAL); + } + + ctype->ce_regd = 1; + ctype->ce_callbacks = *ecbs; + set_callbacks_active(ctype); + if (ctype->ce_callbacks.class_add) + (*ctype->ce_callbacks.class_add)(ctype->default_class->name,ctype->default_class); + return ctype->typeID; +} + +/* + * Unregistering a callback structure by the classification engine. + * + * Returns 0 on success -errno for failure. + */ +int +ckrm_unregister_engine(const char *typename) +{ + struct ckrm_classtype *ctype; + + ctype = ckrm_find_classtype_by_name(typename); + if (ctype == NULL) + return (-ENOENT); + + ctype->ce_cb_active = 0; + + if (atomic_dec_and_test(&ctype->ce_nr_users) != 1) { + // Somebody is currently using the engine, cannot deregister. + atomic_inc(&ctype->ce_nr_users); + return (-EBUSY); + } + + ctype->ce_regd = 0; + memset(&ctype->ce_callbacks, 0, sizeof(ckrm_eng_callback_t)); + return 0; +} + +/**************************************************************************** + * Interfaces to manipulate class (core or resource) hierarchies + ****************************************************************************/ + +/* + */ +static void +ckrm_add_child(struct ckrm_core_class *parent, struct ckrm_core_class *child) +{ + struct ckrm_hnode *cnode = &child->hnode; + + if (!ckrm_is_core_valid(child)) { + printk(KERN_ERR "Invalid child %p given in ckrm_add_child\n", child); + return; + } + + class_lock(child); + INIT_LIST_HEAD(&cnode->children); + INIT_LIST_HEAD(&cnode->siblings); + + if (parent) { + struct ckrm_hnode *pnode; + + if (!ckrm_is_core_valid(parent)) { + printk(KERN_ERR "Invalid parent %p given in ckrm_add_child\n", + parent); + parent = NULL; + } else { + pnode = &parent->hnode; + write_lock(&parent->hnode_rwlock); + list_add(&cnode->siblings, &pnode->children); + write_unlock(&parent->hnode_rwlock); + } + } + cnode->parent = parent; + class_unlock(child); + return; +} + +/* + */ +static int +ckrm_remove_child(struct ckrm_core_class *child) +{ + struct ckrm_hnode *cnode, *pnode; + struct ckrm_core_class *parent; + + if (!ckrm_is_core_valid(child)) { + printk(KERN_ERR "Invalid child %p given in ckrm_remove_child\n", child); + return 0; + } + + cnode = &child->hnode; + parent = cnode->parent; + if (!ckrm_is_core_valid(parent)) { + printk(KERN_ERR "Invalid parent %p in ckrm_remove_child\n", parent); + return 0; + } + + pnode = &parent->hnode; + + class_lock(child); + /* ensure that the node does not have children */ + if (!list_empty(&cnode->children)) { + class_unlock(child); + return 0; + } + write_lock(&parent->hnode_rwlock); + list_del(&cnode->siblings); + write_unlock(&parent->hnode_rwlock); + cnode->parent = NULL; + class_unlock(child); + return 1; +} + +void +ckrm_lock_hier(struct ckrm_core_class *parent) +{ + if (ckrm_is_core_valid(parent)) { + read_lock(&parent->hnode_rwlock); + } +} + +void +ckrm_unlock_hier(struct ckrm_core_class *parent) +{ + if (ckrm_is_core_valid(parent)) { + read_unlock(&parent->hnode_rwlock); + } +} + +/* + * hnode_rwlock of the parent core class must held in read mode. + * external callers should 've called ckrm_lock_hier before calling this + * function. + */ +#define hnode_2_core(ptr) ((ptr) ? container_of(ptr, struct ckrm_core_class, hnode) : NULL) + +struct ckrm_core_class * +ckrm_get_next_child(struct ckrm_core_class *parent, + struct ckrm_core_class *child) +{ + struct list_head *cnode; + struct ckrm_hnode *next_cnode; + struct ckrm_core_class *next_childcore; + + if (!ckrm_is_core_valid(parent)) { + printk(KERN_ERR "Invalid parent %p in ckrm_get_next_child\n", parent); + return NULL; + } + if (list_empty(&parent->hnode.children)) { + return NULL; + } + + if (child) { + if (!ckrm_is_core_valid(child)) { + printk(KERN_ERR "Invalid child %p in ckrm_get_next_child\n", child); + return NULL; + } + cnode = child->hnode.siblings.next; + } else { + cnode = parent->hnode.children.next; + } + + if (cnode == &parent->hnode.children) { // back at the anchor + return NULL; + } + + next_cnode = container_of(cnode, struct ckrm_hnode, siblings); + next_childcore = hnode_2_core(next_cnode); + + if (!ckrm_is_core_valid(next_childcore)) { + printk(KERN_ERR "Invalid next child %p in ckrm_get_next_child\n", + next_childcore); + return NULL; + } + return next_childcore; +} + +EXPORT_SYMBOL(ckrm_lock_hier); +EXPORT_SYMBOL(ckrm_unlock_hier); +EXPORT_SYMBOL(ckrm_get_next_child); + +static void +ckrm_alloc_res_class(struct ckrm_core_class *core, + struct ckrm_core_class *parent, + int resid) +{ + + struct ckrm_classtype *clstype; + + /* + * Allocate a resource class only if the resource controller has + * registered with core and the engine requests for the class. + */ + + if (!ckrm_is_core_valid(core)) + return ; + + clstype = core->classtype; + core->res_class[resid] = NULL; + + if (test_bit(resid, &clstype->bit_res_ctlrs)) { + ckrm_res_ctlr_t *rcbs; + + atomic_inc(&clstype->nr_resusers[resid]); + rcbs = clstype->res_ctlrs[resid]; + + if (rcbs && rcbs->res_alloc) { + core->res_class[resid] =(*rcbs->res_alloc)(core,parent); + if (core->res_class[resid]) + return; + printk(KERN_ERR "Error creating res class\n"); + } + atomic_dec(&clstype->nr_resusers[resid]); + } +} + +/* + * Initialize a core class + * + */ + +#define CLS_DEBUG(fmt, args...) do { /* printk("%s: " fmt, __FUNCTION__ , ## args); */ } while (0) + + +int +ckrm_init_core_class(struct ckrm_classtype *clstype, + struct ckrm_core_class *dcore, + struct ckrm_core_class *parent, + const char *name) +{ + // Hubertus ... should replace name with dentry or add dentry ? + int i; + + // Hubertus .. how is this used in initialization + + CLS_DEBUG("name %s => %p\n", name?name:"default",dcore); + + if ((dcore != clstype->default_class) && ( !ckrm_is_core_valid(parent))) { + printk("error not a valid parent %p\n", parent); + return -EINVAL; + } +#if 0 // Hubertus .. dynamic allocation still breaks when RCs registers. See def in ckrm_rc.h + dcore->res_class = NULL; + if (clstype->max_resid > 0) { + dcore->res_class = (void**)kmalloc(clstype->max_resid * sizeof(void*) , GFP_KERNEL); + if (dcore->res_class == NULL) { + printk("error no mem\n"); + return -ENOMEM; + } + } +#endif + + dcore->classtype = clstype; + dcore->magic = CKRM_CORE_MAGIC; + dcore->name = name; + dcore->class_lock = SPIN_LOCK_UNLOCKED; + dcore->hnode_rwlock = RW_LOCK_UNLOCKED; + dcore->delayed = 0; + + atomic_set(&dcore->refcnt, 0); + write_lock(&ckrm_class_lock); + + INIT_LIST_HEAD(&dcore->objlist); + list_add(&dcore->clslist,&clstype->classes); + + clstype->num_classes++; + set_callbacks_active(clstype); + + write_unlock(&ckrm_class_lock); + ckrm_add_child(parent, dcore); + + for (i = 0; i < clstype->max_resid; i++) + ckrm_alloc_res_class(dcore,parent,i); + + // fix for race condition seen in stress with numtasks + if (parent) + ckrm_core_grab(parent); + + ckrm_core_grab( dcore ); + return 0; +} + + +static void +ckrm_free_res_class(struct ckrm_core_class *core, int resid) +{ + /* + * Free a resource class only if the resource controller has + * registered with core + */ + + if (core->res_class[resid]) { + ckrm_res_ctlr_t *rcbs; + struct ckrm_classtype *clstype = core->classtype; + + atomic_inc(&clstype->nr_resusers[resid]); + rcbs = clstype->res_ctlrs[resid]; + + if (rcbs->res_free) { + (*rcbs->res_free)(core->res_class[resid]); + atomic_dec(&clstype->nr_resusers[resid]); // for inc in alloc + core->res_class[resid] = NULL; + } + atomic_dec(&clstype->nr_resusers[resid]); + } +} + + +/* + * Free a core class + * requires that all tasks were previously reassigned to another class + * + * Returns 0 on success -errno on failure. + */ + +void +ckrm_free_core_class(struct ckrm_core_class *core) +{ + int i; + struct ckrm_classtype *clstype = core->classtype; + struct ckrm_core_class *parent = core->hnode.parent; + + CLS_DEBUG("core=%p:%s parent=%p:%s\n",core,core->name,parent,parent->name); + if (core->delayed) { + /* this core was marked as late */ + printk("class <%s> finally deleted %lu\n",core->name,jiffies); + } + if (ckrm_remove_child(core) == 0) { + printk("Core class removal failed. Chilren present\n"); + } + + for (i = 0; i < clstype->max_resid; i++) { + ckrm_free_res_class(core,i); + } + + write_lock(&ckrm_class_lock); + + // Clear the magic, so we would know if this core is reused. + core->magic = 0; +#if 0 // Dynamic not yet enabled + core->res_class = NULL; +#endif + // Remove this core class from its linked list. + list_del(&core->clslist); + clstype->num_classes--; + set_callbacks_active(clstype); + write_unlock(&ckrm_class_lock); + + // fix for race condition seen in stress with numtasks + if (parent) + ckrm_core_drop(parent); + + kfree(core); +} + +int +ckrm_release_core_class(struct ckrm_core_class *core) +{ + if (!ckrm_is_core_valid(core)) { + // Invalid core + return (-EINVAL); + } + + if (core == core->classtype->default_class) + return 0; + + /* need to make sure that the classgot really dropped */ + if (atomic_read(&core->refcnt) != 1) { + CLS_DEBUG("class <%s> deletion delayed refcnt=%d jif=%ld\n", + core->name,atomic_read(&core->refcnt),jiffies); + core->delayed = 1; /* just so we have a ref point */ + } + ckrm_core_drop(core); + return 0; +} + +/**************************************************************************** + * Interfaces for the resource controller * + ****************************************************************************/ +/* + * Registering a callback structure by the resource controller. + * + * Returns the resource id(0 or +ve) on success, -errno for failure. + */ +static int +ckrm_register_res_ctlr_intern(struct ckrm_classtype *clstype, ckrm_res_ctlr_t *rcbs) +{ + int resid, ret,i; + + if (!rcbs) + return -EINVAL; + + resid = rcbs->resid; + + spin_lock(&clstype->res_ctlrs_lock); + + printk(KERN_WARNING "resid is %d name is %s %s\n", + resid, rcbs->res_name,clstype->res_ctlrs[resid]->res_name); + + if (resid >= 0) { + if ((resid < CKRM_MAX_RES_CTLRS) && (clstype->res_ctlrs[resid] == NULL)) { + clstype->res_ctlrs[resid] = rcbs; + atomic_set(&clstype->nr_resusers[resid], 0); + set_bit(resid, &clstype->bit_res_ctlrs); + ret = resid; + if (resid >= clstype->max_resid) { + clstype->max_resid = resid + 1; + } + } else { + ret = -EBUSY; + } + spin_unlock(&clstype->res_ctlrs_lock); + return ret; + } + + for (i = clstype->resid_reserved; i < clstype->max_res_ctlrs; i++) { + if (clstype->res_ctlrs[i] == NULL) { + clstype->res_ctlrs[i] = rcbs; + rcbs->resid = i; + atomic_set(&clstype->nr_resusers[i], 0); + set_bit(i, &clstype->bit_res_ctlrs); + if (i >= clstype->max_resid) { + clstype->max_resid = i + 1; + } + spin_unlock(&clstype->res_ctlrs_lock); + return i; + } + } + + spin_unlock(&clstype->res_ctlrs_lock); + return (-ENOMEM); +} + +int +ckrm_register_res_ctlr(struct ckrm_classtype *clstype, ckrm_res_ctlr_t *rcbs) +{ + struct ckrm_core_class *core; + int resid; + + resid = ckrm_register_res_ctlr_intern(clstype,rcbs); + + if (resid >= 0) { + /* run through all classes and create the resource class object and + * if necessary "initialize" class in context of this resource + */ + read_lock(&ckrm_class_lock); + list_for_each_entry(core, &clstype->classes, clslist) { + printk("CKRM .. create res clsobj for resouce <%s> class <%s> par=%p\n", + rcbs->res_name, core->name, core->hnode.parent); + ckrm_alloc_res_class(core, core->hnode.parent, resid); + if (clstype->add_resctrl) // FIXME: this should be mandatory + (*clstype->add_resctrl)(core,resid); + } + read_unlock(&ckrm_class_lock); + } + return resid; +} + +/* + * Unregistering a callback structure by the resource controller. + * + * Returns 0 on success -errno for failure. + */ +int +ckrm_unregister_res_ctlr(struct ckrm_res_ctlr *rcbs) +{ + struct ckrm_classtype *clstype = rcbs->classtype; + int resid = rcbs->resid; + + if ((clstype == NULL) || (resid < 0)) + return -EINVAL; + + if (atomic_read(&clstype->nr_resusers[resid])) + return -EBUSY; + + // FIXME: probably need to also call deregistration function + + spin_lock(&clstype->res_ctlrs_lock); + clstype->res_ctlrs[resid] = NULL; + clear_bit(resid, &clstype->bit_res_ctlrs); + clstype->max_resid = fls(clstype->bit_res_ctlrs); + rcbs->resid = -1; + spin_unlock(&clstype->res_ctlrs_lock); + + return 0; +} + +/******************************************************************* + * Class Type Registration + *******************************************************************/ + +/* Hubertus ... we got to do some locking here */ + +struct ckrm_classtype* ckrm_classtypes[CKRM_MAX_CLASSTYPES]; +EXPORT_SYMBOL(ckrm_classtypes); // really should build a better interface for this + +int +ckrm_register_classtype(struct ckrm_classtype *clstype) +{ + int tid = clstype->typeID; + + if (tid != -1) { + if ((tid < 0) || (tid > CKRM_MAX_CLASSTYPES) || (ckrm_classtypes[tid])) + return -EINVAL; + } else { + int i; + for ( i=CKRM_RESV_CLASSTYPES ; itypeID = tid; + ckrm_classtypes[tid] = clstype; + + /* Hubertus .. we need to call the callbacks of the RCFS client */ + if (rcfs_fn.register_classtype) { + (* rcfs_fn.register_classtype)(clstype); + // No error return for now ; + } + + return tid; +} + +int +ckrm_unregister_classtype(struct ckrm_classtype *clstype) +{ + int tid = clstype->typeID; + + if ((tid < 0) || (tid > CKRM_MAX_CLASSTYPES) || (ckrm_classtypes[tid] != clstype)) + return -EINVAL; + + if (rcfs_fn.deregister_classtype) { + (* rcfs_fn.deregister_classtype)(clstype); + // No error return for now + } + + ckrm_classtypes[tid] = NULL; + clstype->typeID = -1; + return 0; +} + +struct ckrm_classtype* +ckrm_find_classtype_by_name(const char *name) +{ + int i; + for ( i=0 ; iname,name,CKRM_MAX_TYPENAME_LEN)) + return ctype; + } + return NULL; +} + + +/******************************************************************* + * Event callback invocation + *******************************************************************/ + +struct ckrm_hook_cb* ckrm_event_callbacks[CKRM_NONLATCHABLE_EVENTS]; + +/* Registration / Deregistration / Invocation functions */ + +int +ckrm_register_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb) +{ + struct ckrm_hook_cb **cbptr; + + if ((ev < CKRM_LATCHABLE_EVENTS) || (ev >= CKRM_NONLATCHABLE_EVENTS)) + return 1; + cbptr = &ckrm_event_callbacks[ev]; + while (*cbptr != NULL) + cbptr = &((*cbptr)->next); + *cbptr = cb; + return 0; +} + +int +ckrm_unregister_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb) +{ + struct ckrm_hook_cb **cbptr; + + if ((ev < CKRM_LATCHABLE_EVENTS) || (ev >= CKRM_NONLATCHABLE_EVENTS)) + return -1; + cbptr = &ckrm_event_callbacks[ev]; + while ((*cbptr != NULL) && (*cbptr != cb)) + cbptr = &((*cbptr)->next); + if (*cbptr) + (*cbptr)->next = cb->next; + return (*cbptr == NULL); +} + +int +ckrm_register_event_set(struct ckrm_event_spec especs[]) +{ + struct ckrm_event_spec *espec = especs; + + for ( espec = especs ; espec->ev != -1 ; espec++ ) + ckrm_register_event_cb(espec->ev,&espec->cb); + return 0; +} + +int +ckrm_unregister_event_set(struct ckrm_event_spec especs[]) +{ + struct ckrm_event_spec *espec = especs; + + for ( espec = especs ; espec->ev != -1 ; espec++ ) + ckrm_unregister_event_cb(espec->ev,&espec->cb); + return 0; +} + +#define ECC_PRINTK(fmt, args...) // printk("%s: " fmt, __FUNCTION__ , ## args) + +void +ckrm_invoke_event_cb_chain(enum ckrm_event ev, void *arg) +{ + struct ckrm_hook_cb *cb, *anchor; + + ECC_PRINTK("%d %x\n",current,ev,arg); + if ((anchor = ckrm_event_callbacks[ev]) != NULL) { + for ( cb = anchor ; cb ; cb = cb->next ) + (*cb->fct)(arg); + } +} + +/******************************************************************* + * Generic Functions that can be used as default functions + * in almost all classtypes + * (a) function iterator over all resource classes of a class + * (b) function invoker on a named resource + *******************************************************************/ + +int +ckrm_class_show_shares(struct ckrm_core_class *core, struct seq_file *seq) +{ + int i; + struct ckrm_res_ctlr *rcbs; + struct ckrm_classtype *clstype = core->classtype; + struct ckrm_shares shares; + + for (i = 0; i < clstype->max_resid; i++) { + atomic_inc(&clstype->nr_resusers[i]); + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->get_share_values) { + (*rcbs->get_share_values)(core->res_class[i], &shares); + seq_printf(seq,"res=%s,guarantee=%d,limit=%d,total_guarantee=%d,max_limit=%d\n", + rcbs->res_name, + shares.my_guarantee, + shares.my_limit, + shares.total_guarantee, + shares.max_limit); + } + atomic_dec(&clstype->nr_resusers[i]); + } + return 0; +} + +int +ckrm_class_show_stats(struct ckrm_core_class *core, struct seq_file *seq) +{ + int i; + struct ckrm_res_ctlr *rcbs; + struct ckrm_classtype *clstype = core->classtype; + + for (i = 0; i < clstype->max_resid; i++) { + atomic_inc(&clstype->nr_resusers[i]); + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->get_stats) + (*rcbs->get_stats)(core->res_class[i], seq); + atomic_dec(&clstype->nr_resusers[i]); + } + return 0; +} + +int +ckrm_class_show_config(struct ckrm_core_class *core, struct seq_file *seq) +{ + int i; + struct ckrm_res_ctlr *rcbs; + struct ckrm_classtype *clstype = core->classtype; + + for (i = 0; i < clstype->max_resid; i++) { + atomic_inc(&clstype->nr_resusers[i]); + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->show_config) + (*rcbs->show_config)(core->res_class[i], seq); + atomic_dec(&clstype->nr_resusers[i]); + } + return 0; +} + +int +ckrm_class_set_config(struct ckrm_core_class *core, const char *resname, const char *cfgstr) +{ + struct ckrm_classtype *clstype = core->classtype; + struct ckrm_res_ctlr *rcbs = ckrm_resctlr_lookup(clstype,resname); + int rc; + + if (rcbs == NULL || rcbs->set_config == NULL) + return -EINVAL; + rc = (*rcbs->set_config)(core->res_class[rcbs->resid],cfgstr); + return rc; +} + +int +ckrm_class_set_shares(struct ckrm_core_class *core, const char *resname, + struct ckrm_shares *shares) +{ + struct ckrm_classtype *clstype = core->classtype; + struct ckrm_res_ctlr *rcbs; + int rc; + + printk("ckrm_class_set_shares(%s,%s)\n",core->name,resname); + rcbs = ckrm_resctlr_lookup(clstype,resname); + if (rcbs == NULL || rcbs->set_share_values == NULL) + return -EINVAL; + rc = (*rcbs->set_share_values)(core->res_class[rcbs->resid],shares); + return rc; +} + +int +ckrm_class_reset_stats(struct ckrm_core_class *core, const char *resname, const char *unused) +{ + struct ckrm_classtype *clstype = core->classtype; + struct ckrm_res_ctlr *rcbs = ckrm_resctlr_lookup(clstype,resname); + int rc; + + if (rcbs == NULL || rcbs->reset_stats == NULL) + return -EINVAL; + rc = (*rcbs->reset_stats)(core->res_class[rcbs->resid]); + return rc; +} + +/******************************************************************* + * Initialization + *******************************************************************/ + +void +ckrm_cb_newtask(struct task_struct *tsk) +{ + tsk->ce_data = NULL; + spin_lock_init(&tsk->ckrm_tsklock); + ckrm_invoke_event_cb_chain(CKRM_EVENT_NEWTASK,tsk); +} + +void +ckrm_cb_exit(struct task_struct *tsk) +{ + ckrm_invoke_event_cb_chain(CKRM_EVENT_EXIT,tsk); + tsk->ce_data = NULL; +} + +void __init +ckrm_init(void) +{ + printk("CKRM Initialization\n"); + + // register/initialize the Metatypes + +#ifdef CONFIG_CKRM_TYPE_TASKCLASS + { + extern void ckrm_meta_init_taskclass(void); + ckrm_meta_init_taskclass(); + } +#endif +#ifdef CONFIG_CKRM_TYPE_SOCKETCLASS + { + extern void ckrm_meta_init_sockclass(void); + ckrm_meta_init_sockclass(); + } +#endif + // prepare init_task and then rely on inheritance of properties + ckrm_cb_newtask(&init_task); + printk("CKRM Initialization done\n"); +} + +EXPORT_SYMBOL(ckrm_register_engine); +EXPORT_SYMBOL(ckrm_unregister_engine); + +EXPORT_SYMBOL(ckrm_register_res_ctlr); +EXPORT_SYMBOL(ckrm_unregister_res_ctlr); + +EXPORT_SYMBOL(ckrm_init_core_class); +EXPORT_SYMBOL(ckrm_free_core_class); +EXPORT_SYMBOL(ckrm_release_core_class); + +EXPORT_SYMBOL(ckrm_register_classtype); +EXPORT_SYMBOL(ckrm_unregister_classtype); +EXPORT_SYMBOL(ckrm_find_classtype_by_name); + +EXPORT_SYMBOL(ckrm_core_grab); +EXPORT_SYMBOL(ckrm_core_drop); +EXPORT_SYMBOL(ckrm_is_core_valid); +EXPORT_SYMBOL(ckrm_validate_and_grab_core); + +EXPORT_SYMBOL(ckrm_register_event_set); +EXPORT_SYMBOL(ckrm_unregister_event_set); +EXPORT_SYMBOL(ckrm_register_event_cb); +EXPORT_SYMBOL(ckrm_unregister_event_cb); + +EXPORT_SYMBOL(ckrm_class_show_stats); +EXPORT_SYMBOL(ckrm_class_show_config); +EXPORT_SYMBOL(ckrm_class_show_shares); + +EXPORT_SYMBOL(ckrm_class_set_config); +EXPORT_SYMBOL(ckrm_class_set_shares); + +EXPORT_SYMBOL(ckrm_class_reset_stats); + + diff --git a/kernel/ckrm/ckrm_listenaq.c b/kernel/ckrm/ckrm_listenaq.c new file mode 100644 index 000000000..235ac0699 --- /dev/null +++ b/kernel/ckrm/ckrm_listenaq.c @@ -0,0 +1,503 @@ +/* ckrm_socketaq.c - accept queue resource controller + * + * Copyright (C) Vivek Kashyap, IBM Corp. 2004 + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * Initial version + */ + +/* Code Description: TBD + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define hnode_2_core(ptr) \ + ((ptr) ? container_of(ptr, struct ckrm_core_class, hnode) : NULL) + + +#define CKRM_SAQ_MAX_DEPTH 3 // 0 => /rcfs + // 1 => socket_aq + // 2 => socket_aq/listen_class + // 3 => socket_aq/listen_class/accept_queues + // 4 => Not allowed + +typedef struct ckrm_laq_res { + spinlock_t reslock; + atomic_t refcnt; + struct ckrm_shares shares; + struct ckrm_core_class *core; + struct ckrm_core_class *pcore; + int my_depth; + int my_id; +} ckrm_laq_res_t; + +static int my_resid = -1; + +extern struct ckrm_core_class *rcfs_create_under_netroot(char *, int, int); +extern struct ckrm_core_class *rcfs_make_core(struct dentry *, + struct ckrm_core_class * ) ; + +void +laq_res_hold(struct ckrm_laq_res *res) +{ + atomic_inc(&res->refcnt); + return; +} + +void +laq_res_put(struct ckrm_laq_res *res) +{ + if (atomic_dec_and_test(&res->refcnt)) + kfree(res); + return; +} + +/* Initialize rescls values + */ +static void +laq_res_initcls(void *my_res) +{ + ckrm_laq_res_t *res = my_res; + + res->shares.my_guarantee = CKRM_SHARE_DONTCARE; + res->shares.my_limit = CKRM_SHARE_DONTCARE; + res->shares.total_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE; + res->shares.max_limit = CKRM_SHARE_DFLT_MAX_LIMIT; + res->shares.unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE; + res->shares.cur_max_limit = 0; +} + +static int +atoi(char *s) +{ + int k = 0; + while(*s) + k = *s++ - '0' + (k * 10); + return k; +} + +static char * +laq_get_name(struct ckrm_core_class *c) +{ + char *p = (char *)c->name; + + while(*p) + p++; + while( *p != '/' && p != c->name) + p--; + + return ++p; +} + +static void * +laq_res_alloc(struct ckrm_core_class *core, struct ckrm_core_class *parent) +{ + ckrm_laq_res_t *res, *pres; + int pdepth; + + if (parent) + pres = ckrm_get_res_class(parent, my_resid, ckrm_laq_res_t); + else + pres = NULL; + + if (core == core->classtype->default_class) + pdepth = 1; + else { + if (!parent) + return NULL; + pdepth = 1 + pres->my_depth; + } + + res = kmalloc(sizeof(ckrm_laq_res_t), GFP_ATOMIC); + if (res) { + memset(res, 0, sizeof(res)); + spin_lock_init(&res->reslock); + laq_res_hold(res); + res->my_depth = pdepth; + if (pdepth == 2) // listen class + res->my_id = 0; + else if (pdepth == 3) + res->my_id = atoi(laq_get_name(core)); + res->core = core; + res->pcore = parent; + + // rescls in place, now initialize contents other than + // hierarchy pointers + laq_res_initcls(res); // acts as initialising value + } + + return res; +} + +static void +laq_res_free(void *my_res) +{ + ckrm_laq_res_t *res = (ckrm_laq_res_t *)my_res; + ckrm_laq_res_t *parent; + + if (!res) + return; + + if (res->my_depth != 3) { + kfree(res); + return; + } + + parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t); + if (!parent) // Should never happen + return; + + spin_lock(&parent->reslock); + spin_lock(&res->reslock); + + // return child's guarantee to parent node + // Limits have no meaning for accept queue control + child_guarantee_changed(&parent->shares, res->shares.my_guarantee, 0); + + spin_unlock(&res->reslock); + laq_res_put(res); + spin_unlock(&parent->reslock); + return; +} + +/************************************************************************** + * SHARES *** + **************************************************************************/ + +void +laq_set_aq_values(ckrm_laq_res_t *my_res, ckrm_laq_res_t *parent, int updatep) +{ + + struct ckrm_net_struct *ns; + struct ckrm_core_class *core = parent->core; + struct tcp_opt *tp; + + if (my_res->my_depth < 2) + return; + + // XXX Instead of holding a class_lock introduce a rw + // lock to be write locked by listen callbacks and read locked here. + // - VK + class_lock(core); + list_for_each_entry(ns, &core->objlist,ckrm_link) { + tp = tcp_sk(ns->ns_sk); + if (updatep) + tp->acceptq[0].aq_ratio = + parent->shares.total_guarantee/ + parent->shares.unused_guarantee; + + tp->acceptq[my_res->my_id].aq_ratio = + my_res->shares.total_guarantee/ + parent->shares.my_guarantee; + } + class_unlock(core); + return; +} + +static int +laq_set_share_values(void *my_res, struct ckrm_shares *shares) +{ + ckrm_laq_res_t *res = my_res; + ckrm_laq_res_t *parent, *child; + struct ckrm_hnode *chnode; + int rc = 0; + + if (!res) + return -EINVAL; + + if (!res->pcore) { + // something is badly wrong + printk(KERN_ERR "socketaq internal inconsistency\n"); + return -EBADF; + } + + parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t); + if (!parent) // socket_class does not have a share interface + return -EINVAL; + + // Ensure that we ignore limit values + shares->my_limit = shares->max_limit = CKRM_SHARE_UNCHANGED; + + switch (res->my_depth) { + + case 0: printk(KERN_ERR "socketaq bad entry\n"); + rc = -EBADF; + break; + + case 1: // can't be written to. this is internal default. + // return -EINVAL + rc = -EINVAL; + break; + + case 2: // nothing to inherit + if (!shares->total_guarantee) { + rc = -EINVAL; + break; + } + + ckrm_lock_hier(res->pcore); + spin_lock(&res->reslock); + rc = set_shares(shares, &res->shares, NULL); + if (!rc) { + list_for_each_entry(chnode, + &res->core->hnode.children,siblings){ + child=hnode_2_core(chnode)->res_class[my_resid]; + laq_set_aq_values(child,res,(child->my_id==1)); + } + } + spin_unlock(&res->reslock); + ckrm_unlock_hier(res->pcore); + break; + + case 3: // accept queue itself. Check against parent. + ckrm_lock_hier(parent->pcore); + spin_lock(&parent->reslock); + rc = set_shares(shares, &res->shares, &parent->shares); + if (!rc) { + laq_set_aq_values(res,parent,1); + } + spin_unlock(&parent->reslock); + ckrm_unlock_hier(parent->pcore); + break; + } + + return rc; +} + +static int +laq_get_share_values(void *my_res, struct ckrm_shares *shares) +{ + ckrm_laq_res_t *res = my_res; + + if (!res) + return -EINVAL; + *shares = res->shares; + return 0; +} + +/************************************************************************** + * STATS *** + **************************************************************************/ + +void +laq_print_aq_stats(struct seq_file *sfile, struct tcp_acceptq_info *taq, int i) +{ + seq_printf(sfile, "Class %d connections:\n\taccepted: %u\n\t" + "queued: %u\n\twait_time: %lu\n\t", + i, taq->acceptq_count, taq->acceptq_qcount, + taq->acceptq_wait_time); + + if (i) + return; + + for (i = 1; i < NUM_ACCEPT_QUEUES; i++) { + taq[0].acceptq_wait_time += taq[i].acceptq_wait_time; + taq[0].acceptq_qcount += taq[i].acceptq_qcount; + taq[0].acceptq_count += taq[i].acceptq_count; + } + + seq_printf(sfile, "Totals :\n\taccepted: %u\n\t" + "queued: %u\n\twait_time: %lu\n", + taq->acceptq_count, taq->acceptq_qcount, + taq->acceptq_wait_time); + + return; +} + +void +laq_get_aq_stats(ckrm_laq_res_t *pres, ckrm_laq_res_t *mres, + struct tcp_acceptq_info *taq) +{ + struct ckrm_net_struct *ns; + struct ckrm_core_class *core = pres->core; + struct tcp_opt *tp; + int a = mres->my_id; + int z; + + if (a == 0) + z = NUM_ACCEPT_QUEUES; + else + z = a+1; + + // XXX Instead of holding a class_lock introduce a rw + // lock to be write locked by listen callbacks and read locked here. + // - VK + class_lock(pres->core); + list_for_each_entry(ns, &core->objlist,ckrm_link) { + tp = tcp_sk(ns->ns_sk); + for (; a< z; a++) { + taq->acceptq_wait_time += tp->acceptq[a].aq_wait_time; + taq->acceptq_qcount += tp->acceptq[a].aq_qcount; + taq->acceptq_count += tp->acceptq[a].aq_count; + taq++; + } + } + class_unlock(pres->core); +} + + +static int +laq_get_stats(void *my_res, struct seq_file *sfile) +{ + ckrm_laq_res_t *res = my_res; + ckrm_laq_res_t *parent; + struct tcp_acceptq_info taq[NUM_ACCEPT_QUEUES]; + int rc = 0; + + if (!res) + return -EINVAL; + + if (!res->pcore) { + // something is badly wrong + printk(KERN_ERR "socketaq internal inconsistency\n"); + return -EBADF; + } + + parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t); + if (!parent) { // socket_class does not have a stat interface + printk(KERN_ERR "socketaq internal fs inconsistency\n"); + return -EINVAL; + } + + memset(taq, 0, sizeof(struct tcp_acceptq_info) * NUM_ACCEPT_QUEUES); + + switch (res->my_depth) { + + default: + case 0: printk(KERN_ERR "socket class bad entry\n"); + rc = -EBADF; + break; + + case 1: // can't be read from. this is internal default. + // return -EINVAL + rc = -EINVAL; + break; + + case 2: // return the default and total + ckrm_lock_hier(res->core); // block any deletes + laq_get_aq_stats(res, res, &taq[0]); + laq_print_aq_stats(sfile, &taq[0], 0); + ckrm_unlock_hier(res->core); // block any deletes + break; + + case 3: + ckrm_lock_hier(parent->core); // block any deletes + laq_get_aq_stats(parent, res, &taq[res->my_id]); + laq_print_aq_stats(sfile, &taq[res->my_id], res->my_id); + ckrm_unlock_hier(parent->core); // block any deletes + break; + } + + return rc; +} + +/* + * The network connection is reclassified to this class. Update its shares. + * The socket lock is held. + */ +static void +laq_change_resclass(void *n, void *old, void *r) +{ + struct ckrm_net_struct *ns = (struct ckrm_net_struct *)n; + struct ckrm_laq_res *res = (struct ckrm_laq_res *)r; + struct ckrm_hnode *chnode = NULL; + + + if (res->my_depth != 2) + return; + + // a change to my_depth == 3 ie. the accept classes cannot happen. + // there is no target file + if (res->my_depth == 2) { // it is one of the socket classes + struct ckrm_laq_res *reschild; + struct sock *sk = ns->ns_sk; + struct tcp_opt *tp = tcp_sk(sk); + + // share rule: hold parent resource lock. then self. + // However, since my_depth == 1 is a generic class it is not + // needed here. Self lock is enough. + spin_lock(&res->reslock); + tp->acceptq[0].aq_ratio = res->shares.total_guarantee/ + res->shares.unused_guarantee; + list_for_each_entry(chnode,&res->core->hnode.children,siblings){ + reschild = hnode_2_core(chnode)->res_class[my_resid]; + + spin_lock(&reschild->reslock); + tp->acceptq[reschild->my_id].aq_ratio= + reschild->shares.total_guarantee/ + res->shares.my_guarantee; + spin_unlock(&reschild->reslock); + } + spin_unlock(&res->reslock); + } + + return; +} + +struct ckrm_res_ctlr laq_rcbs = { + .res_name = "laq", + .resid = -1 , // dynamically assigned + .res_alloc = laq_res_alloc, + .res_free = laq_res_free, + .set_share_values = laq_set_share_values, + .get_share_values = laq_get_share_values, + .get_stats = laq_get_stats, + .change_resclass = laq_change_resclass, + // .res_initcls = laq_res_initcls, // LAQ_HUBERTUS: no need for this !! +}; + +int __init +init_ckrm_laq_res(void) +{ + struct ckrm_classtype *clstype; + int resid; + + clstype = ckrm_find_classtype_by_name("socket_class"); + if (clstype == NULL) { + printk(KERN_INFO " Unknown ckrm classtype"); + return -ENOENT; + } + + if (my_resid == -1) { + resid = ckrm_register_res_ctlr(clstype,&laq_rcbs); + if (resid >= 0) + my_resid = resid; + printk("........init_ckrm_listen_aq_res -> %d\n",my_resid); + } + return 0; + +} + +void __exit +exit_ckrm_laq_res(void) +{ + ckrm_unregister_res_ctlr(&laq_rcbs); + my_resid = -1; +} + + +module_init(init_ckrm_laq_res) +module_exit(exit_ckrm_laq_res) + +MODULE_LICENSE("GPL"); + diff --git a/kernel/ckrm/ckrm_sockc.c b/kernel/ckrm/ckrm_sockc.c new file mode 100644 index 000000000..26731bb20 --- /dev/null +++ b/kernel/ckrm/ckrm_sockc.c @@ -0,0 +1,554 @@ +/* ckrm_sock.c - Class-based Kernel Resource Management (CKRM) + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003,2004 + * (C) Shailabh Nagar, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Vivek Kashyap, IBM Corp. 2004 + * + * + * Provides kernel API of CKRM for in-kernel,per-resource controllers + * (one each for cpu, memory, io, network) and callbacks for + * classification modules. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 28 Aug 2003 + * Created. + * 06 Nov 2003 + * Made modifications to suit the new RBCE module. + * 10 Nov 2003 + * Fixed a bug in fork and exit callbacks. Added callbacks_active and + * surrounding logic. Added task paramter for all CE callbacks. + * 23 Mar 2004 + * moved to referenced counted class objects and correct locking + * 12 Apr 2004 + * introduced adopted to emerging classtype interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct ckrm_sock_class { + struct ckrm_core_class core; +}; + +static struct ckrm_sock_class sockclass_dflt_class = { +}; + +#define SOCKET_CLASS_TYPE_NAME "socket_class" + +const char *dflt_sockclass_name = SOCKET_CLASS_TYPE_NAME; + +static struct ckrm_core_class *sock_alloc_class(struct ckrm_core_class *parent, const char *name); +static int sock_free_class(struct ckrm_core_class *core); + +static int sock_forced_reclassify(ckrm_core_class_t *target, const char *resname); +static int sock_show_members(struct ckrm_core_class *core, struct seq_file *seq); +static void sock_add_resctrl(struct ckrm_core_class *core, int resid); +static void sock_reclassify_class(struct ckrm_sock_class *cls); + +struct ckrm_classtype CT_sockclass = { + .mfidx = 1, + .name = SOCKET_CLASS_TYPE_NAME, + .typeID = CKRM_CLASSTYPE_SOCKET_CLASS, + .maxdepth = 3, + .resid_reserved = 0, + .max_res_ctlrs = CKRM_MAX_RES_CTLRS, + .max_resid = 0, + .bit_res_ctlrs = 0L, + .res_ctlrs_lock = SPIN_LOCK_UNLOCKED, + .classes = LIST_HEAD_INIT(CT_sockclass.classes), + + .default_class = &sockclass_dflt_class.core, + + // private version of functions + .alloc = &sock_alloc_class, + .free = &sock_free_class, + .show_members = &sock_show_members, + .forced_reclassify = &sock_forced_reclassify, + + // use of default functions + .show_shares = &ckrm_class_show_shares, + .show_stats = &ckrm_class_show_stats, + .show_config = &ckrm_class_show_config, + .set_config = &ckrm_class_set_config, + .set_shares = &ckrm_class_set_shares, + .reset_stats = &ckrm_class_reset_stats, + + // mandatory private version .. no dflt available + .add_resctrl = &sock_add_resctrl, +}; + +/* helper functions */ + +void +ckrm_ns_hold(struct ckrm_net_struct *ns) +{ + atomic_inc(&ns->ns_refcnt); + return; +} + +void +ckrm_ns_put(struct ckrm_net_struct *ns) +{ + if (atomic_dec_and_test(&ns->ns_refcnt)) + kfree(ns); + + return; +} +/* + * Change the class of a netstruct + * + * Change the task's task class to "newcls" if the task's current + * class (task->taskclass) is same as given "oldcls", if it is non-NULL. + * + */ + +static void +sock_set_class(struct ckrm_net_struct *ns, struct ckrm_sock_class *newcls, + struct ckrm_sock_class *oldcls, enum ckrm_event event) +{ + int i; + struct ckrm_res_ctlr *rcbs; + struct ckrm_classtype *clstype; + void *old_res_class, *new_res_class; + + if ((newcls == oldcls) || (newcls == NULL)) { + ns->core = (void *)oldcls; + return; + } + + class_lock(class_core(newcls)); + ns->core = newcls; + list_add(&ns->ckrm_link, &class_core(newcls)->objlist); + class_unlock(class_core(newcls)); + + clstype = class_isa(newcls); + for (i = 0; i < clstype->max_resid; i++) { + atomic_inc(&clstype->nr_resusers[i]); + old_res_class = oldcls ? class_core(oldcls)->res_class[i] : NULL; + new_res_class = newcls ? class_core(newcls)->res_class[i] : NULL; + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->change_resclass && (old_res_class != new_res_class)) + (*rcbs->change_resclass)(ns, old_res_class, new_res_class); + atomic_dec(&clstype->nr_resusers[i]); + } + return; +} + +static void +sock_add_resctrl(struct ckrm_core_class *core, int resid) +{ + struct ckrm_net_struct *ns; + struct ckrm_res_ctlr *rcbs; + + if ((resid < 0) || (resid >= CKRM_MAX_RES_CTLRS) || ((rcbs = core->classtype->res_ctlrs[resid]) == NULL)) + return; + + class_lock(core); + list_for_each_entry(ns, &core->objlist, ckrm_link) { + if (rcbs->change_resclass) + (*rcbs->change_resclass)(ns, NULL, core->res_class[resid]); + } + class_unlock(core); +} + + +/************************************************************************** + * Functions called from classification points * + **************************************************************************/ + +static void +cb_sockclass_listen_start(struct sock *sk) +{ + struct ckrm_net_struct *ns = NULL; + struct ckrm_sock_class *newcls = NULL; + struct ckrm_res_ctlr *rcbs; + struct ckrm_classtype *clstype; + int i = 0; + + // XXX - TBD ipv6 + if (sk->sk_family == IPPROTO_IPV6) + return; + + // to store the socket address + ns = (struct ckrm_net_struct *) + kmalloc(sizeof(struct ckrm_net_struct), GFP_ATOMIC); + if (!ns) + return; + + memset(ns,0, sizeof(ns)); + INIT_LIST_HEAD(&ns->ckrm_link); + + ns->ns_family = sk->sk_family; + if (ns->ns_family == IPPROTO_IPV6) // IPv6 not supported yet. + return; + + ns->ns_daddrv4 = inet_sk(sk)->rcv_saddr; + ns->ns_dport = inet_sk(sk)->num; + + ns->ns_pid = current->pid; + ns->ns_tgid = current->tgid; + + ce_protect(&CT_sockclass); + CE_CLASSIFY_RET(newcls,&CT_sockclass,CKRM_EVENT_LISTEN_START,ns,current); + ce_release(&CT_sockclass); + + if (newcls == NULL) { + newcls = &sockclass_dflt_class; + ckrm_core_grab(class_core(newcls)); + } + + class_lock(class_core(newcls)); + list_add(&ns->ckrm_link, &class_core(newcls)->objlist); + ckrm_ns_put(ns); + ns->core = newcls; + class_unlock(class_core(newcls)); + + + // the socket is already locked + // take a reference on socket on our behalf + sock_hold(sk); + sk->sk_ns = (void *)ns; + ns->ns_sk = sk; + + // modify its shares + clstype = class_isa(newcls); + for (i = 0; i < clstype->max_resid; i++) { + atomic_inc(&clstype->nr_resusers[i]); + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->change_resclass) { + (*rcbs->change_resclass)((void *)ns, + NULL,class_core(newcls)->res_class[i]); + } + atomic_dec(&clstype->nr_resusers[i]); + } + return; +} + +static void +cb_sockclass_listen_stop(struct sock *sk) +{ + struct ckrm_net_struct *ns = NULL; + struct ckrm_sock_class *newcls = NULL; + + // XXX - TBD ipv6 + if (sk->sk_family == IPPROTO_IPV6) + return; + + ns = (struct ckrm_net_struct *)sk->sk_ns; + if (!ns) // listen_start called before socket_aq was loaded + return; + + newcls = ns->core; + if (newcls) { + class_lock(class_core(newcls)); + list_del(&ns->ckrm_link); + INIT_LIST_HEAD(&ns->ckrm_link); + class_unlock(class_core(newcls)); + ckrm_core_drop(class_core(newcls)); + } + + // the socket is already locked + sk->sk_ns = NULL; + sock_put(sk); + + // Should be the last count and free it + ckrm_ns_put(ns); + return; +} + +static struct ckrm_event_spec sock_events_callbacks[] = { + CKRM_EVENT_SPEC( LISTEN_START, cb_sockclass_listen_start ), + CKRM_EVENT_SPEC( LISTEN_STOP, cb_sockclass_listen_stop ), + { -1 } +}; + +/************************************************************************** + * Class Object Creation / Destruction + **************************************************************************/ + +static struct ckrm_core_class * +sock_alloc_class(struct ckrm_core_class *parent, const char *name) +{ + struct ckrm_sock_class *sockcls; + sockcls = kmalloc(sizeof(struct ckrm_sock_class), GFP_KERNEL); + if (sockcls == NULL) + return NULL; + + ckrm_init_core_class(&CT_sockclass,class_core(sockcls),parent,name); + + ce_protect(&CT_sockclass); + if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_add) + (*CT_sockclass.ce_callbacks.class_add)(name,sockcls); + ce_release(&CT_sockclass); + + return class_core(sockcls); +} + +static int +sock_free_class(struct ckrm_core_class *core) +{ + struct ckrm_sock_class *sockcls; + + if (!ckrm_is_core_valid(core)) { + // Invalid core + return (-EINVAL); + } + if (core == core->classtype->default_class) { + // reset the name tag + core->name = dflt_sockclass_name; + return 0; + } + + sockcls = class_type(struct ckrm_sock_class, core); + + ce_protect(&CT_sockclass); + + if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_delete) + (*CT_sockclass.ce_callbacks.class_delete)(core->name,sockcls); + + sock_reclassify_class ( sockcls ); + + ce_release(&CT_sockclass); + + ckrm_release_core_class(core); // Hubertus .... could just drop the class .. error message + return 0; +} + + +static int +sock_show_members(struct ckrm_core_class *core, struct seq_file *seq) +{ + struct list_head *lh; + struct ckrm_net_struct *ns = NULL; + + class_lock(core); + list_for_each(lh, &core->objlist) { + ns = container_of(lh, struct ckrm_net_struct,ckrm_link); + seq_printf(seq, "%d.%d.%d.%d\\%d\n", + NIPQUAD(ns->ns_daddrv4),ns->ns_dport); + } + class_unlock(core); + + return 0; +} + +static int +sock_forced_reclassify_ns(struct ckrm_net_struct *tns, struct ckrm_core_class *core) +{ + struct ckrm_net_struct *ns = NULL; + struct sock *sk = NULL; + struct ckrm_sock_class *oldcls, *newcls; + int rc = -EINVAL; + + if (!ckrm_is_core_valid(core)) { + return rc; + } + + newcls = class_type(struct ckrm_sock_class, core); + // lookup the listening sockets + // returns with a reference count set on socket + sk = tcp_v4_lookup_listener(tns->ns_daddrv4,tns->ns_dport,0); + if (!sk) { + printk(KERN_INFO "No such listener 0x%x:%d\n", + tns->ns_daddrv4, tns->ns_dport); + return rc; + } + lock_sock(sk); + if (!sk->sk_ns) { + goto out; + } + ns = sk->sk_ns; + ckrm_ns_hold(ns); + oldcls = ns->core; + if ((oldcls == NULL) || (oldcls == newcls)) { + ckrm_ns_put(ns); + goto out; + } + + // remove the net_struct from the current class + class_lock(class_core(oldcls)); + list_del(&ns->ckrm_link); + INIT_LIST_HEAD(&ns->ckrm_link); + ns->core = NULL; + class_unlock(class_core(oldcls)); + + sock_set_class(ns, newcls, oldcls, CKRM_EVENT_MANUAL); + ckrm_ns_put(ns); + rc = 0; +out: + release_sock(sk); + sock_put(sk); + + return rc; + +} + +enum sock_target_token_t { + IPV4, IPV6, SOCKC_TARGET_ERR +}; + +static match_table_t sock_target_tokens = { + {IPV4, "ipv4=%s"}, + {IPV6, "ipv6=%s"}, + {SOCKC_TARGET_ERR, NULL}, +}; + +char * +v4toi(char *s, char c, __u32 *v) +{ + unsigned int k = 0, n = 0; + + while(*s && (*s != c)) { + if (*s == '.') { + n <<= 8; + n |= k; + k = 0; + } + else + k = k *10 + *s - '0'; + s++; + } + + n <<= 8; + *v = n | k; + + return s; +} + +static int +sock_forced_reclassify(struct ckrm_core_class *target,const char *options) +{ + char *p,*p2; + struct ckrm_net_struct ns; + __u32 v4addr, tmp; + + if (!options) + return 1; + + while ((p = strsep((char**)&options, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + + if (!*p) + continue; + token = match_token(p, sock_target_tokens, args); + switch (token) { + + case IPV4: + + p2 = p; + while(*p2 && (*p2 != '=')) + ++p2; + p2++; + p2 = v4toi(p2, '\\',&(v4addr)); + ns.ns_daddrv4 = htonl(v4addr); + ns.ns_family = 4; //IPPROTO_IPV4 + p2 = v4toi(++p2, ':',&tmp); ns.ns_dport = (__u16)tmp; + p2 = v4toi(++p2,'\0',&ns.ns_pid); + + sock_forced_reclassify_ns(&ns,target); + break; + + case IPV6: + printk(KERN_INFO "rcfs: IPV6 not supported yet\n"); + return 0; + default: + return 0; + } + } + return 1; +} + +/* + * Listen_aq reclassification. + */ +static void +sock_reclassify_class(struct ckrm_sock_class *cls) +{ + struct ckrm_net_struct *ns, *tns; + struct ckrm_core_class *core = class_core(cls); + LIST_HEAD(local_list); + + if (!cls) + return; + + if (!ckrm_validate_and_grab_core(core)) + return; + + class_lock(core); + // we have the core refcnt + if (list_empty(&core->objlist)) { + class_unlock(core); + ckrm_core_drop(core); + return; + } + + INIT_LIST_HEAD(&local_list); + list_splice_init(&core->objlist, &local_list); + class_unlock(core); + ckrm_core_drop(core); + + list_for_each_entry_safe(ns, tns, &local_list, ckrm_link) { + ckrm_ns_hold(ns); + list_del(&ns->ckrm_link); + if (ns->ns_sk) { + lock_sock(ns->ns_sk); + sock_set_class(ns, &sockclass_dflt_class, NULL, CKRM_EVENT_MANUAL); + release_sock(ns->ns_sk); + } + ckrm_ns_put(ns); + } + return ; +} + +void __init +ckrm_meta_init_sockclass(void) +{ + printk("...... Initializing ClassType<%s> ........\n",CT_sockclass.name); + // intialize the default class + ckrm_init_core_class(&CT_sockclass, class_core(&sockclass_dflt_class), + NULL,dflt_sockclass_name); + + // register classtype and initialize default task class + ckrm_register_classtype(&CT_sockclass); + ckrm_register_event_set(sock_events_callbacks); + + // note registeration of all resource controllers will be done later dynamically + // as these are specified as modules +} + + + +#if 1 + +/*************************************************************************************** + * Debugging Network Classes: Utility functions + **************************************************************************************/ + +#endif diff --git a/kernel/ckrm/ckrm_tasks.c b/kernel/ckrm/ckrm_tasks.c new file mode 100644 index 000000000..dcc7ee341 --- /dev/null +++ b/kernel/ckrm/ckrm_tasks.c @@ -0,0 +1,509 @@ +/* ckrm_numtasks.c - "Number of tasks" resource controller for CKRM + * + * Copyright (C) Chandra Seetharaman, IBM Corp. 2003 + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 31 Mar 2004: Created + * + */ + +/* + * Code Description: TBD + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TOTAL_NUM_TASKS (131072) // 128 K +#define NUMTASKS_DEBUG +#define NUMTASKS_NAME "numtasks" + +typedef struct ckrm_numtasks { + struct ckrm_core_class *core; // the core i am part of... + struct ckrm_core_class *parent; // parent of the core above. + struct ckrm_shares shares; + spinlock_t cnt_lock; // always grab parent's lock first and then child's + int cnt_guarantee; // num_tasks guarantee in local units + int cnt_unused; // has to borrow if more than this is needed + int cnt_limit; // no tasks over this limit. + atomic_t cnt_cur_alloc; // current alloc from self + atomic_t cnt_borrowed; // borrowed from the parent + + int over_guarantee; //turn on/off when cur_alloc goes over/under guarantee + + // internally maintained statictics to compare with max numbers + int limit_failures; // no. of failures 'cause the request was over the limit + int borrow_sucesses; // no. of successful borrows + int borrow_failures; // no. of borrow faileures + + // Maximum the specific statictics has reached. + int max_limit_failures; + int max_borrow_sucesses; + int max_borrow_failures; + + // Total number of specific statistics + int tot_limit_failures; + int tot_borrow_sucesses; + int tot_borrow_failures; +} ckrm_numtasks_t; + +struct ckrm_res_ctlr numtasks_rcbs; + +/* Initialize rescls values + * May be called on each rcfs unmount or as part of error recovery + * to make share values sane. + * Does not traverse hierarchy reinitializing children. + */ +static void +numtasks_res_initcls_one(ckrm_numtasks_t *res) +{ + res->shares.my_guarantee = CKRM_SHARE_DONTCARE; + res->shares.my_limit = CKRM_SHARE_DONTCARE; + res->shares.total_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE; + res->shares.max_limit = CKRM_SHARE_DFLT_MAX_LIMIT; + res->shares.unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE; + res->shares.cur_max_limit = 0; + + res->cnt_guarantee = CKRM_SHARE_DONTCARE; + res->cnt_unused = CKRM_SHARE_DONTCARE; + res->cnt_limit = CKRM_SHARE_DONTCARE; + + res->over_guarantee = 0; + + res->limit_failures = 0; + res->borrow_sucesses = 0; + res->borrow_failures = 0; + + res->max_limit_failures = 0; + res->max_borrow_sucesses = 0; + res->max_borrow_failures = 0; + + res->tot_limit_failures = 0; + res->tot_borrow_sucesses = 0; + res->tot_borrow_failures = 0; + + atomic_set(&res->cnt_cur_alloc, 0); + atomic_set(&res->cnt_borrowed, 0); + return; +} + +#if 0 +static void +numtasks_res_initcls(void *my_res) +{ + ckrm_numtasks_t *res = my_res; + + /* Write a version which propagates values all the way down + and replace rcbs callback with that version */ + +} +#endif + +int +numtasks_get_ref(void *arg, int force) +{ + int rc, resid = numtasks_rcbs.resid; + ckrm_numtasks_t *res; + ckrm_core_class_t *core = arg; + + if ((resid < 0) || (core == NULL)) + return 1; + + res = ckrm_get_res_class(core, resid, ckrm_numtasks_t); + if (res == NULL) + return 1; + + atomic_inc(&res->cnt_cur_alloc); + + rc = 1; + if (((res->parent) && (res->cnt_unused == CKRM_SHARE_DONTCARE)) || + (atomic_read(&res->cnt_cur_alloc) > res->cnt_unused)) { + + rc = 0; + if (!force && (res->cnt_limit != CKRM_SHARE_DONTCARE) && + (atomic_read(&res->cnt_cur_alloc) > res->cnt_limit)) { + res->limit_failures++; + res->tot_limit_failures++; + } else if (res->parent != NULL) { + if ((rc = numtasks_get_ref(res->parent, force)) == 1) { + atomic_inc(&res->cnt_borrowed); + res->borrow_sucesses++; + res->tot_borrow_sucesses++; + res->over_guarantee = 1; + } else { + res->borrow_failures++; + res->tot_borrow_failures++; + } + } else { + rc = force; + } + } else if (res->over_guarantee) { + res->over_guarantee = 0; + + if (res->max_limit_failures < res->limit_failures) { + res->max_limit_failures = res->limit_failures; + } + if (res->max_borrow_sucesses < res->borrow_sucesses) { + res->max_borrow_sucesses = res->borrow_sucesses; + } + if (res->max_borrow_failures < res->borrow_failures) { + res->max_borrow_failures = res->borrow_failures; + } + res->limit_failures = 0; + res->borrow_sucesses = 0; + res->borrow_failures = 0; + } + + if (!rc) { + atomic_dec(&res->cnt_cur_alloc); + } + return rc; +} + +void +numtasks_put_ref(void *arg) +{ + int resid = numtasks_rcbs.resid; + ckrm_numtasks_t *res; + ckrm_core_class_t *core = arg; + + if ((resid == -1) || (core == NULL)) { + return; + } + + res = ckrm_get_res_class(core, resid, ckrm_numtasks_t); + if (res == NULL) + return; + atomic_dec(&res->cnt_cur_alloc); + if (atomic_read(&res->cnt_borrowed) > 0) { + atomic_dec(&res->cnt_borrowed); + numtasks_put_ref(res->parent); + } + return; +} + +static void * +numtasks_res_alloc(struct ckrm_core_class *core, struct ckrm_core_class *parent) +{ + ckrm_numtasks_t *res; + + res = kmalloc(sizeof(ckrm_numtasks_t), GFP_ATOMIC); + + if (res) { + res->core = core; + res->parent = parent; + numtasks_res_initcls_one(res); + res->cnt_lock = SPIN_LOCK_UNLOCKED; + if (parent == NULL) { + // I am part of root class. so set the max tasks to available + // default + res->cnt_guarantee = TOTAL_NUM_TASKS; + res->cnt_unused = TOTAL_NUM_TASKS; + res->cnt_limit = TOTAL_NUM_TASKS; + } + } else { + printk(KERN_ERR "numtasks_res_alloc: failed GFP_ATOMIC alloc\n"); + } + return res; +} + +/* + * No locking of this resource class object necessary as we are not + * supposed to be assigned (or used) when/after this function is called. + */ +static void +numtasks_res_free(void *my_res) +{ + ckrm_numtasks_t *res = my_res, *parres, *childres; + ckrm_core_class_t *child = NULL; + int i, borrowed, maxlimit, resid = numtasks_rcbs.resid; + + if (!res) + return; + + // Assuming there will be no children when this function is called + + parres = ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t); + + if (unlikely(atomic_read(&res->cnt_cur_alloc) != 0 || + atomic_read(&res->cnt_borrowed))) { + printk(KERN_ERR "numtasks_res_free: resource still alloc'd %p\n", res); + if ((borrowed = atomic_read(&res->cnt_borrowed)) > 0) { + for (i = 0; i < borrowed; i++) { + numtasks_put_ref(parres->core); + } + } + } + + // return child's limit/guarantee to parent node + spin_lock(&parres->cnt_lock); + child_guarantee_changed(&parres->shares, res->shares.my_guarantee, 0); + + // run thru parent's children and get the new max_limit of the parent + ckrm_lock_hier(parres->core); + maxlimit = 0; + while ((child = ckrm_get_next_child(parres->core, child)) != NULL) { + childres = ckrm_get_res_class(child, resid, ckrm_numtasks_t); + if (maxlimit < childres->shares.my_limit) { + maxlimit = childres->shares.my_limit; + } + } + ckrm_unlock_hier(parres->core); + if (parres->shares.cur_max_limit < maxlimit) { + parres->shares.cur_max_limit = maxlimit; + } + + spin_unlock(&parres->cnt_lock); + kfree(res); + return; +} +/* + * Recalculate the guarantee and limit in real units... and propagate the + * same to children. + * Caller is responsible for protecting res and for the integrity of parres + */ +static void +recalc_and_propagate(ckrm_numtasks_t *res, ckrm_numtasks_t *parres) +{ + ckrm_core_class_t *child = NULL; + ckrm_numtasks_t *childres; + int resid = numtasks_rcbs.resid; + + if (parres) { + struct ckrm_shares *par = &parres->shares; + struct ckrm_shares *self = &res->shares; + + // calculate cnt_guarantee and cnt_limit + // + if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE) { + res->cnt_guarantee = CKRM_SHARE_DONTCARE; + } else { + res->cnt_guarantee = (self->my_guarantee * parres->cnt_guarantee) + / par->total_guarantee; + } + if (parres->cnt_limit == CKRM_SHARE_DONTCARE) { + res->cnt_limit = CKRM_SHARE_DONTCARE; + } else { + res->cnt_limit = (self->my_limit * parres->cnt_limit) + / par->max_limit; + } + + // Calculate unused units + if (res->cnt_guarantee == CKRM_SHARE_DONTCARE) { + res->cnt_unused = CKRM_SHARE_DONTCARE; + } else { + res->cnt_unused = (self->unused_guarantee * + res->cnt_guarantee) / self->total_guarantee; + } + } + + // propagate to children + ckrm_lock_hier(res->core); + while ((child = ckrm_get_next_child(res->core, child)) != NULL) { + childres = ckrm_get_res_class(child, resid, ckrm_numtasks_t); + + spin_lock(&childres->cnt_lock); + recalc_and_propagate(childres, res); + spin_unlock(&childres->cnt_lock); + } + ckrm_unlock_hier(res->core); + return; +} + +static int +numtasks_set_share_values(void *my_res, struct ckrm_shares *new) +{ + ckrm_numtasks_t *parres, *res = my_res; + struct ckrm_shares *cur = &res->shares, *par; + int rc = -EINVAL, resid = numtasks_rcbs.resid; + + if (!res) + return rc; + + if (res->parent) { + parres = ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t); + spin_lock(&parres->cnt_lock); + spin_lock(&res->cnt_lock); + par = &parres->shares; + } else { + spin_lock(&res->cnt_lock); + par = NULL; + parres = NULL; + } + + rc = set_shares(new, cur, par); + + if ((rc == 0) && parres) { + // Calculate parent's unused units + if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE) { + parres->cnt_unused = CKRM_SHARE_DONTCARE; + } else { + parres->cnt_unused = (par->unused_guarantee * + parres->cnt_guarantee) / par->total_guarantee; + } + + recalc_and_propagate(res, parres); + } + spin_unlock(&res->cnt_lock); + if (res->parent) { + spin_unlock(&parres->cnt_lock); + } + return rc; +} + + +static int +numtasks_get_share_values(void *my_res, struct ckrm_shares *shares) +{ + ckrm_numtasks_t *res = my_res; + + if (!res) + return -EINVAL; + *shares = res->shares; + return 0; +} + +static int +numtasks_get_stats(void *my_res, struct seq_file *sfile) +{ + ckrm_numtasks_t *res = my_res; + + if (!res) + return -EINVAL; + + seq_printf(sfile, "Number of tasks resource:\n"); + seq_printf(sfile, "Total Over limit failures: %d\n", + res->tot_limit_failures); + seq_printf(sfile, "Total Over guarantee sucesses: %d\n", + res->tot_borrow_sucesses); + seq_printf(sfile, "Total Over guarantee failures: %d\n", + res->tot_borrow_failures); + + seq_printf(sfile, "Maximum Over limit failures: %d\n", + res->max_limit_failures); + seq_printf(sfile, "Maximum Over guarantee sucesses: %d\n", + res->max_borrow_sucesses); + seq_printf(sfile, "Maximum Over guarantee failures: %d\n", + res->max_borrow_failures); +#ifdef NUMTASKS_DEBUG + seq_printf(sfile, "cur_alloc %d; borrowed %d; cnt_guar %d; cnt_limit %d " + "unused_guarantee %d, cur_max_limit %d\n", + atomic_read(&res->cnt_cur_alloc), + atomic_read(&res->cnt_borrowed), + res->cnt_guarantee, + res->cnt_limit, + res->shares.unused_guarantee, + res->shares.cur_max_limit); +#endif + + return 0; +} + +static int +numtasks_show_config(void *my_res, struct seq_file *sfile) +{ + ckrm_numtasks_t *res = my_res; + + if (!res) + return -EINVAL; + + seq_printf(sfile, "res=%s,parameter=somevalue\n",NUMTASKS_NAME); + return 0; +} + +static int +numtasks_set_config(void *my_res, const char *cfgstr) +{ + ckrm_numtasks_t *res = my_res; + + if (!res) + return -EINVAL; + printk("numtasks config='%s'\n",cfgstr); + return 0; +} + +static void +numtasks_change_resclass(void *task, void *old, void *new) +{ + ckrm_numtasks_t *oldres = old; + ckrm_numtasks_t *newres = new; + + if (oldres != (void *) -1) { + struct task_struct *tsk = task; + if (!oldres) { + struct ckrm_core_class *old_core = &(tsk->parent->taskclass->core); + oldres = ckrm_get_res_class(old_core, numtasks_rcbs.resid, + ckrm_numtasks_t); + } + numtasks_put_ref(oldres->core); + } + if (newres) { + (void) numtasks_get_ref(newres->core, 1); + } +} + +struct ckrm_res_ctlr numtasks_rcbs = { + .res_name = NUMTASKS_NAME, + .res_hdepth = 1, + .resid = -1, + .res_alloc = numtasks_res_alloc, + .res_free = numtasks_res_free, + .set_share_values = numtasks_set_share_values, + .get_share_values = numtasks_get_share_values, + .get_stats = numtasks_get_stats, + .show_config = numtasks_show_config, + .set_config = numtasks_set_config, + .change_resclass = numtasks_change_resclass, +}; + +int __init +init_ckrm_numtasks_res(void) +{ + struct ckrm_classtype *clstype; + int resid = numtasks_rcbs.resid; + + clstype = ckrm_find_classtype_by_name("taskclass"); + if (clstype == NULL) { + printk(KERN_INFO " Unknown ckrm classtype"); + return -ENOENT; + } + + if (resid == -1) { + resid = ckrm_register_res_ctlr(clstype,&numtasks_rcbs); + printk("........init_ckrm_numtasks_res -> %d\n",resid); + } + return 0; +} + +void __exit +exit_ckrm_numtasks_res(void) +{ + ckrm_unregister_res_ctlr(&numtasks_rcbs); + numtasks_rcbs.resid = -1; +} + +module_init(init_ckrm_numtasks_res) +module_exit(exit_ckrm_numtasks_res) + +EXPORT_SYMBOL(numtasks_get_ref); +EXPORT_SYMBOL(numtasks_put_ref); + +MODULE_LICENSE("GPL"); + diff --git a/kernel/ckrm/ckrm_tc.c b/kernel/ckrm/ckrm_tc.c new file mode 100644 index 000000000..cc0377887 --- /dev/null +++ b/kernel/ckrm/ckrm_tc.c @@ -0,0 +1,785 @@ +/* ckrm_tc.c - Class-based Kernel Resource Management (CKRM) + * + * Copyright (C) Hubertus Franke, IBM Corp. 2003,2004 + * (C) Shailabh Nagar, IBM Corp. 2003 + * (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Vivek Kashyap, IBM Corp. 2004 + * + * + * Provides kernel API of CKRM for in-kernel,per-resource controllers + * (one each for cpu, memory, io, network) and callbacks for + * classification modules. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 28 Aug 2003 + * Created. + * 06 Nov 2003 + * Made modifications to suit the new RBCE module. + * 10 Nov 2003 + * Fixed a bug in fork and exit callbacks. Added callbacks_active and + * surrounding logic. Added task paramter for all CE callbacks. + * 23 Mar 2004 + * moved to referenced counted class objects and correct locking + * 12 Apr 2004 + * introduced adopted to emerging classtype interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +#define TC_DEBUG(fmt, args...) do { /* printk("%s: " fmt, __FUNCTION__ , ## args); */ } while (0) + + +static struct ckrm_task_class taskclass_dflt_class = { +}; + +const char *dflt_taskclass_name = TASK_CLASS_TYPE_NAME; + +static struct ckrm_core_class *ckrm_alloc_task_class(struct ckrm_core_class *parent, const char *name); +static int ckrm_free_task_class(struct ckrm_core_class *core); + +static int tc_forced_reclassify(ckrm_core_class_t *target, const char *resname); +static int tc_show_members(struct ckrm_core_class *core, struct seq_file *seq); +static void tc_add_resctrl(struct ckrm_core_class *core, int resid); + +struct ckrm_classtype CT_taskclass = { + .mfidx = TC_MF_IDX, + .name = TASK_CLASS_TYPE_NAME, + .typeID = CKRM_CLASSTYPE_TASK_CLASS, + .maxdepth = 3, // Hubertus .. just to start + .resid_reserved = 4, // Hubertus .. reservation + .max_res_ctlrs = CKRM_MAX_RES_CTLRS, + .max_resid = 0, + .bit_res_ctlrs = 0L, + .res_ctlrs_lock = SPIN_LOCK_UNLOCKED, + .classes = LIST_HEAD_INIT(CT_taskclass.classes), + + .default_class = &taskclass_dflt_class.core, + + // private version of functions + .alloc = &ckrm_alloc_task_class, + .free = &ckrm_free_task_class, + .show_members = &tc_show_members, + .forced_reclassify = &tc_forced_reclassify, + + // use of default functions + .show_shares = &ckrm_class_show_shares, + .show_stats = &ckrm_class_show_stats, + .show_config = &ckrm_class_show_config, + .set_config = &ckrm_class_set_config, + .set_shares = &ckrm_class_set_shares, + .reset_stats = &ckrm_class_reset_stats, + + // mandatory private version .. no dflt available + .add_resctrl = &tc_add_resctrl, +}; + +/************************************************************************** + * Helper Functions * + **************************************************************************/ + +static inline void +ckrm_init_task_lock(struct task_struct *tsk) +{ + tsk->ckrm_tsklock = SPIN_LOCK_UNLOCKED; +} + +// Hubertus .. following functions should move to ckrm_rc.h + +static inline void +ckrm_task_lock(struct task_struct *tsk) +{ + spin_lock(&tsk->ckrm_tsklock); +} + +static inline void +ckrm_task_unlock(struct task_struct *tsk) +{ + spin_unlock(&tsk->ckrm_tsklock); +} + +/* + * Change the task class of the given task. + * + * Change the task's task class to "newcls" if the task's current + * class (task->taskclass) is same as given "oldcls", if it is non-NULL. + * + * Caller is responsible to make sure the task structure stays put through + * this function. + * + * This function should be called with the following locks NOT held + * - tsk->ckrm_task_lock + * - core->ckrm_lock, if core is NULL then ckrm_dflt_class.ckrm_lock + * - tsk->taskclass->ckrm_lock + * + * Function is also called with a ckrm_core_grab on the new core, hence + * it needs to be dropped if no assignment takes place. + */ + +static void +ckrm_set_taskclass(struct task_struct *tsk, ckrm_task_class_t *newcls, + ckrm_task_class_t *oldcls, enum ckrm_event event) +{ + int i; + ckrm_classtype_t *clstype; + ckrm_res_ctlr_t *rcbs; + ckrm_task_class_t *curcls; + void *old_res_class, *new_res_class; + int drop_old_cls; + + ckrm_task_lock(tsk); + curcls = tsk->taskclass; + + // check whether compare_and_exchange should + if (oldcls && (oldcls != curcls)) { + ckrm_task_unlock(tsk); + if (newcls) { + /* compensate for previous grab */ + TC_DEBUG("(%s:%d): Race-condition caught <%s> %d\n", + tsk->comm,tsk->pid,class_core(newcls)->name,event); + ckrm_core_drop(class_core(newcls)); + } + return; + } + + // make sure we have a real destination core + if (!newcls) { + newcls = &taskclass_dflt_class; + ckrm_core_grab(class_core(newcls)); + } + + // take out of old class + // remember that we need to drop the oldcore + if ((drop_old_cls = (curcls != NULL))) { + class_lock(class_core(curcls)); + if (newcls == curcls) { + // we are already in the destination class. + // we still need to drop oldcore + class_unlock(class_core(curcls)); + ckrm_task_unlock(tsk); + goto out; + } + list_del(&tsk->taskclass_link); + INIT_LIST_HEAD(&tsk->taskclass_link); + tsk->taskclass = NULL; + class_unlock(class_core(curcls)); + } + + // put into new class + class_lock(class_core(newcls)); + tsk->taskclass = newcls; + list_add(&tsk->taskclass_link, &class_core(newcls)->objlist); + class_unlock(class_core(newcls)); + + if (newcls == curcls) { + ckrm_task_unlock(tsk); + goto out; + } + + CE_NOTIFY(&CT_taskclass,event,newcls,tsk); + + ckrm_task_unlock(tsk); + + clstype = class_isa(newcls); // Hubertus .. can hardcode ckrm_CT_taskclass + if (clstype->bit_res_ctlrs) { // avoid running through the entire list if non is registered + for (i = 0; i < clstype->max_resid; i++) { + if (clstype->res_ctlrs[i] == NULL) + continue; + atomic_inc(&clstype->nr_resusers[i]); + old_res_class = curcls ? class_core(curcls)->res_class[i] : NULL; + new_res_class = newcls ? class_core(newcls)->res_class[i] : NULL; + rcbs = clstype->res_ctlrs[i]; + if (rcbs && rcbs->change_resclass && (old_res_class != new_res_class)) + (*rcbs->change_resclass)(tsk, old_res_class, new_res_class); + atomic_dec(&clstype->nr_resusers[i]); + } + } + + out: + if (drop_old_cls) + ckrm_core_drop(class_core(curcls)); + return; +} + +// HF SUGGEST: we could macro-tize this for other types DEF_FUNC_ADD_RESCTRL(funcname,link) +// would DEF_FUNC_ADD_RESCTRL(tc_add_resctrl,taskclass_link) + +static void +tc_add_resctrl(struct ckrm_core_class *core, int resid) +{ + struct task_struct *tsk; + struct ckrm_res_ctlr *rcbs; + + if ((resid < 0) || (resid >= CKRM_MAX_RES_CTLRS) || ((rcbs = core->classtype->res_ctlrs[resid]) == NULL)) + return; + + class_lock(core); + list_for_each_entry(tsk, &core->objlist, taskclass_link) { + if (rcbs->change_resclass) + (*rcbs->change_resclass)(tsk, (void *) -1, core->res_class[resid]); + } + class_unlock(core); +} + + +/************************************************************************** + * Functions called from classification points * + **************************************************************************/ + +#define ECB_PRINTK(fmt, args...) // do { if (CT_taskclass.ce_regd) printk("%s: " fmt, __FUNCTION__ , ## args); } while (0) + +#define CE_CLASSIFY_TASK(event, tsk) \ +do { \ + struct ckrm_task_class *newcls = NULL, *oldcls = tsk->taskclass; \ + \ + CE_CLASSIFY_RET(newcls,&CT_taskclass,event,tsk); \ + if (newcls) { \ + /* called synchrously. no need to get task struct */ \ + ckrm_set_taskclass(tsk, newcls, oldcls, event); \ + } \ +} while (0) + +#define CE_CLASSIFY_TASK_PROTECT(event, tsk) \ +do { \ + ce_protect(&CT_taskclass); \ + CE_CLASSIFY_TASK(event,tsk); \ + ce_release(&CT_taskclass); \ +} while (0) + + + + +static void +cb_taskclass_newtask(struct task_struct *tsk) +{ + tsk->taskclass = NULL; + INIT_LIST_HEAD(&tsk->taskclass_link); +} + + +static void +cb_taskclass_fork(struct task_struct *tsk) +{ + struct ckrm_task_class *cls = NULL; + + ECB_PRINTK("%p:%d:%s\n",tsk,tsk->pid,tsk->comm); + + ce_protect(&CT_taskclass); + CE_CLASSIFY_RET(cls,&CT_taskclass,CKRM_EVENT_FORK,tsk); + if (cls == NULL) { + ckrm_task_lock(tsk->parent); + cls = tsk->parent->taskclass; + ckrm_core_grab(class_core(cls)); + ckrm_task_unlock(tsk->parent); + } + if (!list_empty(&tsk->taskclass_link)) + printk("BUG in cb_fork.. tsk (%s:%d> already linked\n", + tsk->comm,tsk->pid); + + ckrm_set_taskclass(tsk, cls, NULL, CKRM_EVENT_FORK); + ce_release(&CT_taskclass); +} + +static void +cb_taskclass_exit(struct task_struct *tsk) +{ + ckrm_task_class_t *cls; + + // Remove the task from the current core class + + ECB_PRINTK("%p:%d:%s\n",tsk,tsk->pid,tsk->comm); + ckrm_task_lock(tsk); + + CE_CLASSIFY_NORET( &CT_taskclass, CKRM_EVENT_EXIT, tsk); + + if ((cls = tsk->taskclass) != NULL) { + class_lock(class_core(cls)); + tsk->taskclass = NULL; + list_del(&tsk->taskclass_link); + class_unlock(class_core(cls)); + ckrm_core_drop(class_core(cls)); + } else { + INIT_LIST_HEAD(&tsk->taskclass_link); + } + ckrm_task_unlock(tsk); +} + +static void +cb_taskclass_exec(const char *filename) +{ + ECB_PRINTK("%p:%d:%s <%s>\n",current,current->pid,current->comm,filename); + CE_CLASSIFY_TASK_PROTECT(CKRM_EVENT_EXEC, current); +} + +static void +cb_taskclass_uid(void) +{ + ECB_PRINTK("%p:%d:%s\n",current,current->pid,current->comm); + CE_CLASSIFY_TASK_PROTECT(CKRM_EVENT_UID, current); +} + +static void +cb_taskclass_gid(void) +{ + ECB_PRINTK("%p:%d:%s\n",current,current->pid,current->comm); + CE_CLASSIFY_TASK_PROTECT(CKRM_EVENT_GID, current); +} + +static struct ckrm_event_spec taskclass_events_callbacks[] = { + CKRM_EVENT_SPEC( NEWTASK, cb_taskclass_newtask ), + CKRM_EVENT_SPEC( EXEC , cb_taskclass_exec ), + CKRM_EVENT_SPEC( FORK , cb_taskclass_fork ), + CKRM_EVENT_SPEC( EXIT , cb_taskclass_exit ), + CKRM_EVENT_SPEC( UID , cb_taskclass_uid ), + CKRM_EVENT_SPEC( GID , cb_taskclass_gid ), + { -1 } +}; + +/*********************************************************************** + * + * Asynchronous callback functions (driven by RCFS) + * + * Async functions force a setting of the task structure + * synchronous callbacks are protected against race conditions + * by using a cmpxchg on the core before setting it. + * Async calls need to be serialized to ensure they can't + * race against each other + * + ***********************************************************************/ + +DECLARE_MUTEX(async_serializer); // serialize all async functions + + +/* + * Go through the task list and reclassify all tasks according to the current + * classification rules. + * + * We have the problem that we can not hold any lock (including the + * tasklist_lock) while classifying. Two methods possible + * + * (a) go through entire pidrange (0..pidmax) and if a task exists at + * that pid then reclassify it + * (b) go several time through task list and build a bitmap for a particular + * subrange of pid otherwise the memory requirements ight be too much. + * + * We use a hybrid by comparing ratio nr_threads/pidmax + */ + +static void +ckrm_reclassify_all_tasks(void) +{ + extern int pid_max; + + struct task_struct *proc, *thread; + int i; + int curpidmax = pid_max; + int ratio; + int use_bitmap; + + + ratio = curpidmax / nr_threads; + if (curpidmax <= PID_MAX_DEFAULT) { + use_bitmap = 1; + } else { + use_bitmap = (ratio >= 2); + } + + ce_protect(&CT_taskclass); + + retry: + if (use_bitmap == 0) { + // go through it in one walk + read_lock(&tasklist_lock); + for ( i=0 ; ipid; + if ((pid < pid_start) || (pid >= pid_end)) { + if (pid >= pid_end) { + do_next = 1; + } + continue; + } + pid -= pid_start; + set_bit(pid, bitmap); + num_found++; + } while_each_thread(proc, thread); + read_unlock(&tasklist_lock); + + if (num_found == 0) + continue; + + pos = 0; + for ( ; num_found-- ; ) { + pos = find_next_bit(bitmap, bitmapsize, pos); + pid = pos + pid_start; + + read_lock(&tasklist_lock); + if ((thread = find_task_by_pid(pid)) != NULL) { + get_task_struct(thread); + read_unlock(&tasklist_lock); + CE_CLASSIFY_TASK(CKRM_EVENT_RECLASSIFY, thread); + put_task_struct(thread); + } else { + read_unlock(&tasklist_lock); + } + } + } + + } + ce_release(&CT_taskclass); +} + +int +ckrm_reclassify(int pid) +{ + struct task_struct *tsk; + int rc = 0; + + down(&async_serializer); // protect again race condition + if (pid < 0) { + // do we want to treat this as process group .. should YES ToDo + rc = -EINVAL; + } else if (pid == 0) { + // reclassify all tasks in the system + ckrm_reclassify_all_tasks(); + } else { + // reclassify particular pid + read_lock(&tasklist_lock); + if ((tsk = find_task_by_pid(pid)) != NULL) { + get_task_struct(tsk); + read_unlock(&tasklist_lock); + CE_CLASSIFY_TASK_PROTECT(CKRM_EVENT_RECLASSIFY, tsk); + put_task_struct(tsk); + } else { + read_unlock(&tasklist_lock); + rc = -EINVAL; + } + } + up(&async_serializer); + return rc; +} + +/* + * Reclassify all tasks in the given core class. + */ + +static void +ckrm_reclassify_class_tasks(struct ckrm_task_class *cls) +{ + int ce_regd; + struct ckrm_hnode *cnode; + struct ckrm_task_class *parcls; + int num = 0; + + if (!ckrm_validate_and_grab_core(&cls->core)) + return; + + down(&async_serializer); // protect again race condition + + + TC_DEBUG("start %p:%s:%d:%d\n",cls,cls->core.name, + atomic_read(&cls->core.refcnt),atomic_read(&cls->core.hnode.parent->refcnt)); + // If no CE registered for this classtype, following will be needed repeatedly; + ce_regd = class_core(cls)->classtype->ce_regd; + cnode = &(class_core(cls)->hnode); + parcls = class_type(ckrm_task_class_t, cnode->parent); + +next_task: + class_lock(class_core(cls)); + if (!list_empty(&class_core(cls)->objlist)) { + struct ckrm_task_class *newcls = NULL; + struct task_struct *tsk = + list_entry(class_core(cls)->objlist.next, + struct task_struct, taskclass_link); + + get_task_struct(tsk); + class_unlock(class_core(cls)); + + if (ce_regd) { + CE_CLASSIFY_RET(newcls,&CT_taskclass,CKRM_EVENT_RECLASSIFY,tsk); + if (cls == newcls) { + // don't allow reclassifying to the same class + // as we are in the process of cleaning up this class + ckrm_core_drop(class_core(newcls)); // to compensate CE's grab + newcls = NULL; + } + } + if (newcls == NULL) { + newcls = parcls; + ckrm_core_grab(class_core(newcls)); + } + ckrm_set_taskclass(tsk, newcls, cls, CKRM_EVENT_RECLASSIFY); + put_task_struct(tsk); + num++; + goto next_task; + } + TC_DEBUG("stop %p:%s:%d:%d %d\n",cls,cls->core.name, + atomic_read(&cls->core.refcnt),atomic_read(&cls->core.hnode.parent->refcnt),num); + class_unlock(class_core(cls)); + ckrm_core_drop(class_core(cls)); + + up(&async_serializer); + + return ; +} + +/* + * Change the core class of the given task. + */ + +int +ckrm_forced_reclassify_pid(pid_t pid, struct ckrm_task_class *cls) +{ + struct task_struct *tsk; + + if (!ckrm_validate_and_grab_core(class_core(cls))) + return - EINVAL; + + read_lock(&tasklist_lock); + if ((tsk = find_task_by_pid(pid)) == NULL) { + read_unlock(&tasklist_lock); + ckrm_core_drop(class_core(cls)); + return -EINVAL; + } + get_task_struct(tsk); + read_unlock(&tasklist_lock); + + down(&async_serializer); // protect again race condition + + ce_protect(&CT_taskclass); + ckrm_set_taskclass(tsk, cls, NULL, CKRM_EVENT_MANUAL); + ce_release(&CT_taskclass); + put_task_struct(tsk); + + up(&async_serializer); + return 0; +} + +static struct ckrm_core_class * +ckrm_alloc_task_class(struct ckrm_core_class *parent, const char *name) +{ + struct ckrm_task_class *taskcls; + taskcls = kmalloc(sizeof(struct ckrm_task_class), GFP_KERNEL); + if (taskcls == NULL) + return NULL; + + ckrm_init_core_class(&CT_taskclass, + class_core(taskcls),parent,name); + + ce_protect(&CT_taskclass); + if (CT_taskclass.ce_cb_active && CT_taskclass.ce_callbacks.class_add) + (*CT_taskclass.ce_callbacks.class_add)(name,taskcls); + ce_release(&CT_taskclass); + + return class_core(taskcls); +} + +static int +ckrm_free_task_class(struct ckrm_core_class *core) +{ + struct ckrm_task_class *taskcls; + + if (!ckrm_is_core_valid(core)) { + // Invalid core + return (-EINVAL); + } + if (core == core->classtype->default_class) { + // reset the name tag + core->name = dflt_taskclass_name; + return 0; + } + + TC_DEBUG("%p:%s:%d\n",core,core->name,atomic_read(&core->refcnt)); + + taskcls = class_type(struct ckrm_task_class, core); + + ce_protect(&CT_taskclass); + + if (CT_taskclass.ce_cb_active && CT_taskclass.ce_callbacks.class_delete) + (*CT_taskclass.ce_callbacks.class_delete)(core->name,taskcls); + ckrm_reclassify_class_tasks( taskcls ); + + ce_release(&CT_taskclass); + + ckrm_release_core_class(core); // Hubertus .... could just drop the class .. error message + return 0; +} + + +void __init +ckrm_meta_init_taskclass(void) +{ + printk("...... Initializing ClassType<%s> ........\n",CT_taskclass.name); + // intialize the default class + ckrm_init_core_class(&CT_taskclass, class_core(&taskclass_dflt_class), + NULL,dflt_taskclass_name); + + // register classtype and initialize default task class + ckrm_register_classtype(&CT_taskclass); + ckrm_register_event_set(taskclass_events_callbacks); + + // note registeration of all resource controllers will be done later dynamically + // as these are specified as modules +} + + + +static int +tc_show_members(struct ckrm_core_class *core, struct seq_file *seq) +{ + struct list_head *lh; + struct task_struct *tsk; + + class_lock(core); + list_for_each(lh, &core->objlist) { + tsk = container_of(lh, struct task_struct, taskclass_link); + seq_printf(seq,"%ld\n", (long)tsk->pid); + } + class_unlock(core); + + return 0; +} + +static int +tc_forced_reclassify(struct ckrm_core_class *target,const char *obj) +{ + pid_t pid; + int rc = -EINVAL; + + pid = (pid_t) simple_strtoul(obj,NULL,10); + if (pid > 0) { + rc = ckrm_forced_reclassify_pid(pid, + class_type(ckrm_task_class_t,target)); + } + return rc; +} + +#if 1 + +/*************************************************************************************** + * Debugging Task Classes: Utility functions + **************************************************************************************/ + +void +check_tasklist_sanity(struct ckrm_task_class *cls) +{ + struct ckrm_core_class *core = class_core(cls); + struct list_head *lh1, *lh2; + int count = 0; + + if (core) { + class_lock(core); + if (list_empty(&core->objlist)) { + class_lock(core); + printk("check_tasklist_sanity: class %s empty list\n", + core->name); + return; + } + list_for_each_safe(lh1, lh2, &core->objlist) { + struct task_struct *tsk = container_of(lh1, struct task_struct, taskclass_link); + if (count++ > 20000) { + printk("list is CORRUPTED\n"); + break; + } + if (tsk->taskclass != cls) { + const char *tclsname; + tclsname = (tsk->taskclass) ? class_core(tsk->taskclass)->name + : "NULL"; + printk("sanity: task %s:%d has ckrm_core |%s| but in list |%s|\n", + tsk->comm,tsk->pid,tclsname,core->name); + } + } + class_unlock(core); + } +} + +void +ckrm_debug_free_task_class(struct ckrm_task_class *tskcls) +{ + struct task_struct *proc, *thread; + int count = 0; + + printk("Analyze Error <%s> %d\n", + class_core(tskcls)->name,atomic_read(&(class_core(tskcls)->refcnt))); + + read_lock(&tasklist_lock); + class_lock(class_core(tskcls)); + do_each_thread(proc, thread) { + count += (tskcls == thread->taskclass); + if ((thread->taskclass == tskcls) || (tskcls == NULL)) { + const char *tclsname; + tclsname = (thread->taskclass) ? class_core(thread->taskclass)->name : "NULL"; + printk("%d thread=<%s:%d> -> <%s> <%lx>\n", + count,thread->comm,thread->pid,tclsname, thread->flags & PF_EXITING); + } + } while_each_thread(proc, thread); + class_unlock(class_core(tskcls)); + read_unlock(&tasklist_lock); + + printk("End Analyze Error <%s> %d\n", + class_core(tskcls)->name,atomic_read(&(class_core(tskcls)->refcnt))); +} + +#endif diff --git a/kernel/ckrm/ckrmutils.c b/kernel/ckrm/ckrmutils.c new file mode 100644 index 000000000..c0d873cb4 --- /dev/null +++ b/kernel/ckrm/ckrmutils.c @@ -0,0 +1,207 @@ +/* ckrmutils.c - Utility functions for CKRM + * + * Copyright (C) Chandra Seetharaman, IBM Corp. 2003 + * (C) Hubertus Franke , IBM Corp. 2004 + * + * Provides simple utility functions for the core module, CE and resource + * controllers. + * + * Latest version, more details at http://ckrm.sf.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Changes + * + * 13 Nov 2003 + * Created + */ + +#include +#include +#include +#include +#include + +int +get_exe_path_name(struct task_struct *tsk, char *buf, int buflen) +{ + struct vm_area_struct * vma; + struct vfsmount *mnt; + struct mm_struct * mm = get_task_mm(tsk); + struct dentry *dentry; + char *lname; + int rc = 0; + + *buf = '\0'; + if (!mm) { + return -EINVAL; + } + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + if ((vma->vm_flags & VM_EXECUTABLE) && + vma->vm_file) { + dentry = dget(vma->vm_file->f_dentry); + mnt = mntget(vma->vm_file->f_vfsmnt); + lname = d_path(dentry, mnt, buf, buflen); + if (! IS_ERR(lname)) { + strncpy(buf, lname, strlen(lname) + 1); + } else { + rc = (int) PTR_ERR(lname); + } + mntput(mnt); + dput(dentry); + break; + } + vma = vma->vm_next; + } + up_read(&mm->mmap_sem); + mmput(mm); + return rc; +} + + +/* + * must be called with cnt_lock of parres held + * Caller is responsible for making sure that the new guarantee doesn't + * overflow parent's total guarantee. + */ +void +child_guarantee_changed(struct ckrm_shares *parent, int cur, int new) +{ + if (new == cur || !parent) { + return; + } + if (new != CKRM_SHARE_DONTCARE) { + parent->unused_guarantee -= new; + } + if (cur != CKRM_SHARE_DONTCARE) { + parent->unused_guarantee += cur; + } + return; +} + +/* + * must be called with cnt_lock of parres held + * Caller is responsible for making sure that the new limit is not more + * than parent's max_limit + */ +void +child_maxlimit_changed(struct ckrm_shares *parent, int new_limit) +{ + if (parent && parent->cur_max_limit < new_limit) { + parent->cur_max_limit = new_limit; + } + return; +} + +/* + * Caller is responsible for holding any lock to protect the data + * structures passed to this function + */ +int +set_shares(struct ckrm_shares *new, struct ckrm_shares *cur, + struct ckrm_shares *par) +{ + int rc = -EINVAL; + int cur_usage_guar = cur->total_guarantee - cur->unused_guarantee; + int increase_by = new->my_guarantee - cur->my_guarantee; + + // Check total_guarantee for correctness + if (new->total_guarantee <= CKRM_SHARE_DONTCARE) { + goto set_share_err; + } else if (new->total_guarantee == CKRM_SHARE_UNCHANGED) { + ;// do nothing + } else if (cur_usage_guar > new->total_guarantee) { + goto set_share_err; + } + + // Check max_limit for correctness + if (new->max_limit <= CKRM_SHARE_DONTCARE) { + goto set_share_err; + } else if (new->max_limit == CKRM_SHARE_UNCHANGED) { + ; // do nothing + } else if (cur->cur_max_limit > new->max_limit) { + goto set_share_err; + } + + // Check my_guarantee for correctness + if (new->my_guarantee == CKRM_SHARE_UNCHANGED) { + ; // do nothing + } else if (new->my_guarantee == CKRM_SHARE_DONTCARE) { + ; // do nothing + } else if (par && increase_by > par->unused_guarantee) { + goto set_share_err; + } + + // Check my_limit for correctness + if (new->my_limit == CKRM_SHARE_UNCHANGED) { + ; // do nothing + } else if (new->my_limit == CKRM_SHARE_DONTCARE) { + ; // do nothing + } else if (par && new->my_limit > par->max_limit) { + // I can't get more limit than my parent's limit + goto set_share_err; + + } + + // make sure guarantee is lesser than limit + if (new->my_limit == CKRM_SHARE_DONTCARE) { + ; // do nothing + } else if (new->my_limit == CKRM_SHARE_UNCHANGED) { + if (new->my_guarantee == CKRM_SHARE_DONTCARE) { + ; // do nothing + } else if (new->my_guarantee == CKRM_SHARE_UNCHANGED) { + ; // do nothing earlier setting would 've taken care of it + } else if (new->my_guarantee > cur->my_limit) { + goto set_share_err; + } + } else { // new->my_limit has a valid value + if (new->my_guarantee == CKRM_SHARE_DONTCARE) { + ; // do nothing + } else if (new->my_guarantee == CKRM_SHARE_UNCHANGED) { + if (cur->my_guarantee > new->my_limit) { + goto set_share_err; + } + } else if (new->my_guarantee > new->my_limit) { + goto set_share_err; + } + } + + if (new->my_guarantee != CKRM_SHARE_UNCHANGED) { + child_guarantee_changed(par, cur->my_guarantee, + new->my_guarantee); + cur->my_guarantee = new->my_guarantee; + } + + if (new->my_limit != CKRM_SHARE_UNCHANGED) { + child_maxlimit_changed(par, new->my_limit); + cur->my_limit = new->my_limit; + } + + if (new->total_guarantee != CKRM_SHARE_UNCHANGED) { + cur->unused_guarantee = new->total_guarantee - cur_usage_guar; + cur->total_guarantee = new->total_guarantee; + } + + if (new->max_limit != CKRM_SHARE_UNCHANGED) { + cur->max_limit = new->max_limit; + } + + rc = 0; +set_share_err: + return rc; +} + +EXPORT_SYMBOL(get_exe_path_name); +EXPORT_SYMBOL(child_guarantee_changed); +EXPORT_SYMBOL(child_maxlimit_changed); +EXPORT_SYMBOL(set_shares); + + diff --git a/kernel/compat.c b/kernel/compat.c index 57cc48e90..540574ce8 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -182,7 +182,7 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set) mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_sigpending((old_sigset_t __user *) &s); + ret = sys_sigpending(&s); set_fs(old_fs); if (ret == 0) ret = put_user(s, set); @@ -200,9 +200,7 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_sigprocmask(how, - set ? (old_sigset_t __user *) &s : NULL, - oset ? (old_sigset_t __user *) &s : NULL); + ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); set_fs(old_fs); if (ret == 0) if (oset) @@ -225,7 +223,7 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, int val, timeout = timespec_to_jiffies(&t) + 1; } if (op >= FUTEX_REQUEUE) - val2 = (int) (unsigned long) utime; + val2 = (int) (long) utime; return do_futex((unsigned long)uaddr, op, val, timeout, (unsigned long)uaddr2, val2, val3); @@ -252,7 +250,7 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, if (r.rlim_max == COMPAT_RLIM_INFINITY) r.rlim_max = RLIM_INFINITY; set_fs(KERNEL_DS); - ret = sys_setrlimit(resource, (struct rlimit __user *) &r); + ret = sys_setrlimit(resource, &r); set_fs(old_fs); return ret; } @@ -294,7 +292,7 @@ asmlinkage long compat_sys_getrlimit (unsigned int resource, mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getrlimit(resource, (struct rlimit __user *) &r); + ret = sys_getrlimit(resource, &r); set_fs(old_fs); if (!ret) { if (r.rlim_cur > COMPAT_RLIM_INFINITY) @@ -342,7 +340,7 @@ asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru) mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getrusage(who, (struct rusage __user *) &r); + ret = sys_getrusage(who, &r); set_fs(old_fs); if (ret) @@ -367,10 +365,7 @@ compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_wait4(pid, - (stat_addr ? - (unsigned int __user *) &status : NULL), - options, (struct rusage __user *) &r); + ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); if (ret > 0) { @@ -387,18 +382,18 @@ asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr) { - unsigned long kern_mask; + unsigned long kernel_mask; mm_segment_t old_fs; int ret; - if (get_user(kern_mask, user_mask_ptr)) + if (get_user(kernel_mask, user_mask_ptr)) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_sched_setaffinity(pid, - sizeof(kern_mask), - (unsigned long __user *) &kern_mask); + sizeof(kernel_mask), + &kernel_mask); set_fs(old_fs); return ret; @@ -407,20 +402,20 @@ asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr) { - unsigned long kern_mask; + unsigned long kernel_mask; mm_segment_t old_fs; int ret; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_sched_getaffinity(pid, - sizeof(kern_mask), - (unsigned long __user *) &kern_mask); + sizeof(kernel_mask), + &kernel_mask); set_fs(old_fs); if (ret > 0) { ret = sizeof(compat_ulong_t); - if (put_user(kern_mask, user_mask_ptr)) + if (put_user(kernel_mask, user_mask_ptr)) return -EFAULT; } @@ -459,9 +454,7 @@ long compat_timer_settime(timer_t timer_id, int flags, return -EFAULT; oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_timer_settime(timer_id, flags, - (struct itimerspec __user *) &newts, - (struct itimerspec __user *) &oldts); + err = sys_timer_settime(timer_id, flags, &newts, &oldts); set_fs(oldfs); if (!err && old && put_compat_itimerspec(old, &oldts)) return -EFAULT; @@ -474,11 +467,9 @@ long compat_timer_gettime(timer_t timer_id, long err; mm_segment_t oldfs; struct itimerspec ts; - oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_timer_gettime(timer_id, - (struct itimerspec __user *) &ts); + err = sys_timer_gettime(timer_id, &ts); set_fs(oldfs); if (!err && put_compat_itimerspec(setting, &ts)) return -EFAULT; @@ -491,13 +482,11 @@ long compat_clock_settime(clockid_t which_clock, long err; mm_segment_t oldfs; struct timespec ts; - if (get_compat_timespec(&ts, tp)) return -EFAULT; oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_clock_settime(which_clock, - (struct timespec __user *) &ts); + err = sys_clock_settime(which_clock, &ts); set_fs(oldfs); return err; } @@ -508,11 +497,9 @@ long compat_clock_gettime(clockid_t which_clock, long err; mm_segment_t oldfs; struct timespec ts; - oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_clock_gettime(which_clock, - (struct timespec __user *) &ts); + err = sys_clock_gettime(which_clock, &ts); set_fs(oldfs); if (!err && put_compat_timespec(&ts, tp)) return -EFAULT; @@ -525,11 +512,9 @@ long compat_clock_getres(clockid_t which_clock, long err; mm_segment_t oldfs; struct timespec ts; - oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_clock_getres(which_clock, - (struct timespec __user *) &ts); + err = sys_clock_getres(which_clock, &ts); set_fs(oldfs); if (!err && put_compat_timespec(&ts, tp)) return -EFAULT; @@ -543,15 +528,11 @@ long compat_clock_nanosleep(clockid_t which_clock, int flags, long err; mm_segment_t oldfs; struct timespec in, out; - if (get_compat_timespec(&in, rqtp)) return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_nanosleep(which_clock, flags, - (struct timespec __user *) &in, - (struct timespec __user *) &out); + set_fs(KERNEL_DS); + err = sys_clock_nanosleep(which_clock, flags, &in, &out); set_fs(oldfs); if ((err == -ERESTART_RESTARTBLOCK) && rmtp && put_compat_timespec(&out, rmtp)) diff --git a/kernel/exit.c b/kernel/exit.c index 3a51fec0a..ce724ebed 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -37,6 +39,11 @@ int getrusage(struct task_struct *, int, struct rusage __user *); static void __unhash_process(struct task_struct *p) { nr_threads--; + /* tasklist_lock is held, is this sufficient? */ + if (p->vx_info) { + atomic_dec(&p->vx_info->cacct.nr_threads); + atomic_dec(&p->vx_info->limit.res[RLIMIT_NPROC]); + } detach_pid(p, PIDTYPE_PID); detach_pid(p, PIDTYPE_TGID); if (thread_group_leader(p)) { @@ -236,6 +243,7 @@ void reparent_to_init(void) ptrace_unlink(current); /* Reparent to init */ REMOVE_LINKS(current); + /* FIXME handle vchild_reaper/initpid */ current->parent = child_reaper; current->real_parent = child_reaper; SET_LINKS(current); @@ -380,6 +388,7 @@ static inline void close_files(struct files_struct * files) struct file * file = xchg(&files->fd[i], NULL); if (file) filp_close(file, files); + vx_openfd_dec(fd); } i++; set >>= 1; @@ -599,6 +608,7 @@ static inline void forget_original_parent(struct task_struct * father) struct task_struct *p, *reaper = father; struct list_head *_p, *_n; + /* FIXME handle vchild_reaper/initpid */ reaper = father->group_leader; if (reaper == father) reaper = child_reaper; @@ -639,6 +649,8 @@ static void exit_notify(struct task_struct *tsk) int state; struct task_struct *t; + ckrm_cb_exit(tsk); + if (signal_pending(tsk) && !tsk->signal->group_exit && !thread_group_empty(tsk)) { /* @@ -740,7 +752,7 @@ static void exit_notify(struct task_struct *tsk) * Clear these here so that update_process_times() won't try to deliver * itimer, profile or rlimit signals to this task while it is in late exit. */ - tsk->it_virt_value = 0; + tsk->it_virt_incr = 0; tsk->it_prof_value = 0; tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY; @@ -793,6 +805,13 @@ asmlinkage NORET_TYPE void do_exit(long code) } acct_process(code); + if (current->tux_info) { +#ifdef CONFIG_TUX_DEBUG + printk("Possibly unexpected TUX-thread exit(%ld) at %p?\n", + code, __builtin_return_address(0)); +#endif + current->tux_exit(); + } __exit_mm(tsk); exit_sem(tsk); @@ -812,6 +831,7 @@ asmlinkage NORET_TYPE void do_exit(long code) module_put(tsk->binfmt->module); tsk->exit_code = code; + numtasks_put_ref(tsk->taskclass); exit_notify(tsk); schedule(); BUG(); diff --git a/kernel/fork.c b/kernel/fork.c index 0cbc27f48..e0d588ee1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -36,6 +36,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -78,6 +82,9 @@ static kmem_cache_t *task_struct_cachep; static void free_task(struct task_struct *tsk) { free_thread_info(tsk->thread_info); + vxdprintk("freeing up task %p\n", tsk); + clr_vx_info(&tsk->vx_info); + clr_nx_info(&tsk->nx_info); free_task_struct(tsk); } @@ -260,6 +267,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) tsk->thread_info = ti; ti->task = tsk; + ckrm_cb_newtask(tsk); /* One for us, one for whoever does the "release_task()" (usually parent) */ atomic_set(&tsk->usage,2); return tsk; @@ -271,7 +279,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) struct vm_area_struct * mpnt, *tmp, **pprev; struct rb_node **rb_link, *rb_parent; int retval; - unsigned long charge; + unsigned long charge = 0; struct mempolicy *pol; down_write(&oldmm->mmap_sem); @@ -304,12 +312,11 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) if(mpnt->vm_flags & VM_DONTCOPY) continue; - charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if (security_vm_enough_memory(len)) goto fail_nomem; - charge = len; + charge += len; } tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) @@ -361,7 +368,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) tmp->vm_ops->open(tmp); if (retval) - goto out; + goto fail; } retval = 0; @@ -373,10 +380,10 @@ fail_nomem_policy: kmem_cache_free(vm_area_cachep, tmp); fail_nomem: retval = -ENOMEM; +fail: vm_unacct_memory(charge); goto out; } - static inline int mm_alloc_pgd(struct mm_struct * mm) { mm->pgd = pgd_alloc(mm); @@ -417,6 +424,10 @@ static struct mm_struct * mm_init(struct mm_struct * mm) if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; +#ifdef __HAVE_ARCH_MMAP_TOP + mm->mmap_top = mmap_top(); +#endif + set_vx_info(&mm->mm_vx_info, current->vx_info); return mm; } free_mm(mm); @@ -448,6 +459,7 @@ void fastcall __mmdrop(struct mm_struct *mm) BUG_ON(mm == &init_mm); mm_free_pgd(mm); destroy_context(mm); + clr_vx_info(&mm->mm_vx_info); free_mm(mm); } @@ -517,7 +529,7 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm) * not set up a proper pointer then tough luck. */ put_user(0, tidptr); - sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); + sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL); } } @@ -562,6 +574,7 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) /* Copy the current MM stuff.. */ memcpy(mm, oldmm, sizeof(*mm)); + mm->mm_vx_info = NULL; if (!mm_init(mm)) goto fail_nomem; @@ -873,6 +886,7 @@ struct task_struct *copy_process(unsigned long clone_flags, { int retval; struct task_struct *p = NULL; + struct vx_info *vxi; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -897,11 +911,35 @@ struct task_struct *copy_process(unsigned long clone_flags, goto fork_out; retval = -ENOMEM; + p = dup_task_struct(current); if (!p) goto fork_out; + p->tux_info = NULL; + + p->vx_info = NULL; + set_vx_info(&p->vx_info, current->vx_info); + p->nx_info = NULL; + set_nx_info(&p->nx_info, current->nx_info); + + /* check vserver memory */ + if (p->mm && !(clone_flags & CLONE_VM)) { + if (vx_vmpages_avail(p->mm, p->mm->total_vm)) + vx_pages_add(p->mm->mm_vx_info, RLIMIT_AS, p->mm->total_vm); + else + goto bad_fork_free; + } + if (p->mm && vx_flags(VXF_FORK_RSS, 0)) { + if (!vx_rsspages_avail(p->mm, p->mm->rss)) + goto bad_fork_free; + } retval = -EAGAIN; + vxi = current->vx_info; + if (vxi && (atomic_read(&vxi->limit.res[RLIMIT_NPROC]) + >= vxi->limit.rlim[RLIMIT_NPROC])) + goto bad_fork_free; + if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) { if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && @@ -1094,6 +1132,10 @@ struct task_struct *copy_process(unsigned long clone_flags, link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid); nr_threads++; + if (vxi) { + atomic_inc(&vxi->cacct.nr_threads); + atomic_inc(&vxi->limit.res[RLIMIT_NPROC]); + } write_unlock_irq(&tasklist_lock); retval = 0; @@ -1181,6 +1223,10 @@ long do_fork(unsigned long clone_flags, clone_flags |= CLONE_PTRACE; } + if (numtasks_get_ref(current->taskclass, 0) == 0) { + return -ENOMEM; + } + p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr); /* * Do this prior waking up the new thread - the thread pointer @@ -1191,6 +1237,8 @@ long do_fork(unsigned long clone_flags, if (!IS_ERR(p)) { struct completion vfork; + ckrm_cb_fork(p); + if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); @@ -1246,6 +1294,8 @@ long do_fork(unsigned long clone_flags, * COW overhead when the child exec()s afterwards. */ set_need_resched(); + } else { + numtasks_put_ref(current->taskclass); } return pid; } diff --git a/kernel/futex.c b/kernel/futex.c index abae250cf..f7afaf5d3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -38,7 +38,6 @@ #include #include #include -#include #define FUTEX_HASHBITS 8 @@ -355,7 +354,7 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2, before *uaddr1. */ smp_mb(); - if (get_user(curval, (int __user *)uaddr1) != 0) { + if (get_user(curval, (int *)uaddr1) != 0) { ret = -EFAULT; goto out; } diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 21387087b..d0db18848 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -318,7 +318,5 @@ int __init kallsyms_init(void) entry->proc_fops = &kallsyms_operations; return 0; } -__initcall(kallsyms_init); -EXPORT_SYMBOL(kallsyms_lookup); EXPORT_SYMBOL(__print_symbol); diff --git a/kernel/kmod.c b/kernel/kmod.c index ea62192b7..10d2e8fc5 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -47,7 +47,7 @@ static struct workqueue_struct *khelper_wq; /* modprobe_path is set via /proc/sys. */ -char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; +char modprobe_path[256] = "/sbin/modprobe"; /** * request_module - try to load a kernel module @@ -132,7 +132,7 @@ EXPORT_SYMBOL(request_module); events. the command is expected to load drivers when necessary, and may perform additional system setup. */ -char hotplug_path[KMOD_PATH_LEN] = "/sbin/hotplug"; +char hotplug_path[256] = "/sbin/hotplug"; EXPORT_SYMBOL(hotplug_path); @@ -192,20 +192,10 @@ static int wait_for_helper(void *data) allow_signal(SIGCHLD); pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD); - if (pid < 0) { + if (pid < 0) sub_info->retval = pid; - } else { - /* - * Normally it is bogus to call wait4() from in-kernel because - * wait4() wants to write the exit code to a userspace address. - * But wait_for_helper() always runs as keventd, and put_user() - * to a kernel address works OK for kernel threads, due to their - * having an mm_segment_t which spans the entire address space. - * - * Thus the __user pointer cast is valid here. - */ - sys_wait4(pid, (int __user *) &sub_info->retval, 0, NULL); - } + else + sys_wait4(pid, &sub_info->retval, 0, NULL); complete(sub_info->complete); return 0; diff --git a/kernel/pid.c b/kernel/pid.c index 6ed44f56c..a8b7eb3c2 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -224,7 +224,8 @@ void fastcall detach_pid(task_t *task, enum pid_type type) task_t *find_task_by_pid(int nr) { - struct pid *pid = find_pid(PIDTYPE_PID, nr); + struct pid *pid = find_pid(PIDTYPE_PID, + vx_rmap_tgid(current->vx_info, nr)); if (!pid) return NULL; diff --git a/kernel/printk.c b/kernel/printk.c index 9e34ce41b..8bffe0433 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -247,7 +247,10 @@ int do_syslog(int type, char __user * buf, int len) unsigned long i, j, limit, count; int do_clear = 0; char c; - int error = 0; + int error = -EPERM; + + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + return error; error = security_syslog(type); if (error) diff --git a/kernel/sched.c b/kernel/sched.c index 10c2581f4..bf76682b6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,8 @@ #include #include #include +#include +#include #include @@ -232,6 +235,8 @@ struct runqueue { task_t *migration_thread; struct list_head migration_queue; #endif + struct list_head hold_queue; + int idle_tokens; }; static DEFINE_PER_CPU(struct runqueue, runqueues); @@ -353,6 +358,9 @@ static int effective_prio(task_t *p) bonus = CURRENT_BONUS(p) - MAX_BONUS / 2; prio = p->static_prio - bonus; + if (__vx_task_flags(p, VXF_SCHED_PRIO, 0)) + prio += effective_vavavoom(p, MAX_USER_PRIO); + if (prio < MAX_RT_PRIO) prio = MAX_RT_PRIO; if (prio > MAX_PRIO-1) @@ -762,13 +770,6 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) load = source_load(cpu); this_load = target_load(this_cpu); - /* - * If sync wakeup then subtract the (maximum possible) effect of - * the currently running task from the load of the current CPU: - */ - if (sync) - this_load -= SCHED_LOAD_SCALE; - /* Don't pull the task off an idle CPU to a busy one */ if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2) goto out_set_cpu; @@ -2000,6 +2001,9 @@ void scheduler_tick(int user_ticks, int sys_ticks) } if (p == rq->idle) { + if (!--rq->idle_tokens && !list_empty(&rq->hold_queue)) + set_need_resched(); + if (atomic_read(&rq->nr_iowait) > 0) cpustat->iowait += sys_ticks; else @@ -2044,7 +2048,7 @@ void scheduler_tick(int user_ticks, int sys_ticks) } goto out_unlock; } - if (!--p->time_slice) { + if (vx_need_resched(p)) { dequeue_task(p, rq->active); set_tsk_need_resched(p); p->prio = effective_prio(p); @@ -2191,6 +2195,10 @@ asmlinkage void __sched schedule(void) unsigned long long now; unsigned long run_time; int cpu, idx; +#ifdef CONFIG_VSERVER_HARDCPU + struct vx_info *vxi; + int maxidle = -HZ; +#endif /* * Test if we are atomic. Since do_exit() needs to call into @@ -2241,6 +2249,37 @@ need_resched: } cpu = smp_processor_id(); +#ifdef CONFIG_VSERVER_HARDCPU + if (!list_empty(&rq->hold_queue)) { + struct list_head *l, *n; + int ret; + + vxi = NULL; + list_for_each_safe(l, n, &rq->hold_queue) { + next = list_entry(l, task_t, run_list); + if (vxi == next->vx_info) + continue; + + vxi = next->vx_info; + ret = vx_tokens_recalc(vxi); + // tokens = vx_tokens_avail(next); + + if (ret > 0) { + list_del(&next->run_list); + next->state &= ~TASK_ONHOLD; + recalc_task_prio(next, now); + __activate_task(next, rq); + // printk("··· unhold %p\n", next); + break; + } + if ((ret < 0) && (maxidle < ret)) + maxidle = ret; + } + } + rq->idle_tokens = -maxidle; + +pick_next: +#endif if (unlikely(!rq->nr_running)) { idle_balance(cpu, rq); if (!rq->nr_running) { @@ -2272,6 +2311,23 @@ need_resched: goto switch_tasks; } +#ifdef CONFIG_VSERVER_HARDCPU + vxi = next->vx_info; + if (vxi && __vx_flags(vxi->vx_flags, + VXF_SCHED_PAUSE|VXF_SCHED_HARD, 0)) { + int ret = vx_tokens_recalc(vxi); + + if (unlikely(ret <= 0)) { + if (ret && (rq->idle_tokens > -ret)) + rq->idle_tokens = -ret; + deactivate_task(next, rq); + list_add_tail(&next->run_list, &rq->hold_queue); + next->state |= TASK_ONHOLD; + goto pick_next; + } + } +#endif + if (!rt_task(next) && next->activated > 0) { unsigned long long delta = now - next->timestamp; @@ -2295,9 +2351,12 @@ switch_tasks: if (!(HIGH_CREDIT(prev) || LOW_CREDIT(prev))) prev->interactive_credit--; } + add_delay_ts(prev,runcpu_total,prev->timestamp,now); prev->timestamp = now; if (likely(prev != next)) { + add_delay_ts(next,waitcpu_total,next->timestamp,now); + inc_delay(next,runs); next->timestamp = now; rq->nr_switches++; rq->curr = next; @@ -2501,10 +2560,21 @@ EXPORT_SYMBOL(wait_for_completion); __remove_wait_queue(q, &wait); \ spin_unlock_irqrestore(&q->lock, flags); +#define SLEEP_ON_BKLCHECK \ + if (unlikely(!kernel_locked()) && \ + sleep_on_bkl_warnings < 10) { \ + sleep_on_bkl_warnings++; \ + WARN_ON(1); \ + } + +static int sleep_on_bkl_warnings; + void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q) { SLEEP_ON_VAR + SLEEP_ON_BKLCHECK + current->state = TASK_INTERRUPTIBLE; SLEEP_ON_HEAD @@ -2518,6 +2588,8 @@ long fastcall __sched interruptible_sleep_on_timeout(wait_queue_head_t *q, long { SLEEP_ON_VAR + SLEEP_ON_BKLCHECK + current->state = TASK_INTERRUPTIBLE; SLEEP_ON_HEAD @@ -2529,23 +2601,12 @@ long fastcall __sched interruptible_sleep_on_timeout(wait_queue_head_t *q, long EXPORT_SYMBOL(interruptible_sleep_on_timeout); -void fastcall __sched sleep_on(wait_queue_head_t *q) -{ - SLEEP_ON_VAR - - current->state = TASK_UNINTERRUPTIBLE; - - SLEEP_ON_HEAD - schedule(); - SLEEP_ON_TAIL -} - -EXPORT_SYMBOL(sleep_on); - long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR + SLEEP_ON_BKLCHECK + current->state = TASK_UNINTERRUPTIBLE; SLEEP_ON_HEAD @@ -3050,10 +3111,13 @@ EXPORT_SYMBOL(yield); void __sched io_schedule(void) { struct runqueue *rq = this_rq(); + def_delay_var(dstart); + start_delay_set(dstart,PF_IOWAIT); atomic_inc(&rq->nr_iowait); schedule(); atomic_dec(&rq->nr_iowait); + add_io_delay(dstart); } EXPORT_SYMBOL(io_schedule); @@ -3062,10 +3126,13 @@ long __sched io_schedule_timeout(long timeout) { struct runqueue *rq = this_rq(); long ret; + def_delay_var(dstart); + start_delay_set(dstart,PF_IOWAIT); atomic_inc(&rq->nr_iowait); ret = schedule_timeout(timeout); atomic_dec(&rq->nr_iowait); + add_io_delay(dstart); return ret; } @@ -3933,6 +4000,7 @@ void __init sched_init(void) rq->migration_thread = NULL; INIT_LIST_HEAD(&rq->migration_queue); #endif + INIT_LIST_HEAD(&rq->hold_queue); atomic_set(&rq->nr_iowait, 0); for (j = 0; j < 2; j++) { @@ -4029,3 +4097,12 @@ void __sched __preempt_write_lock(rwlock_t *lock) EXPORT_SYMBOL(__preempt_write_lock); #endif /* defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) */ + +#ifdef CONFIG_DELAY_ACCT +int task_running_sys(struct task_struct *p) +{ + return task_running(task_rq(p),p); +} +EXPORT_SYMBOL(task_running_sys); +#endif + diff --git a/kernel/signal.c b/kernel/signal.c index e734221af..1ef2d5432 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -417,6 +417,7 @@ flush_signal_handlers(struct task_struct *t, int force_default) } } +EXPORT_SYMBOL_GPL(flush_signal_handlers); /* Notify the system that a driver wants to block all signals for this * process, and wants to be notified if any signals at all were to be @@ -1051,6 +1052,9 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) unsigned long flags; int ret; + if (!vx_check(vx_task_xid(p), VX_ADMIN|VX_WATCH|VX_IDENT)) + return -ESRCH; + ret = check_kill_permission(sig, info, p); if (!ret && sig && p->sighand) { spin_lock_irqsave(&p->sighand->siglock, flags); @@ -1546,6 +1550,34 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent) spin_unlock_irqrestore(&sighand->siglock, flags); } +int print_fatal_signals = 0; + +static void print_fatal_signal(struct pt_regs *regs, int signr) +{ + int i; + unsigned char insn; + printk("%s/%d: potentially unexpected fatal signal %d.\n", + current->comm, current->pid, signr); + +#ifdef __i386__ + printk("code at %08lx: ", regs->eip); + for (i = 0; i < 16; i++) { + __get_user(insn, (unsigned char *)(regs->eip + i)); + printk("%02x ", insn); + } +#endif + printk("\n"); + show_regs(regs); +} + +static int __init setup_print_fatal_signals(char *str) +{ + get_option (&str, &print_fatal_signals); + + return 1; +} + +__setup("print-fatal-signals=", setup_print_fatal_signals); #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER @@ -1737,6 +1769,11 @@ relock: if (!signr) break; /* will return 0 */ + if ((signr == SIGSEGV) && print_fatal_signals) { + spin_unlock_irq(¤t->sighand->siglock); + print_fatal_signal(regs, signr); + spin_lock_irq(¤t->sighand->siglock); + } if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { ptrace_signal_deliver(regs, cookie); @@ -1841,6 +1878,8 @@ relock: * Anything else is fatal, maybe with a core dump. */ current->flags |= PF_SIGNALED; + if (print_fatal_signals) + print_fatal_signal(regs, signr); if (sig_kernel_coredump(signr) && do_coredump((long)signr, signr, regs)) { /* @@ -2475,9 +2514,10 @@ sys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset) out: return error; } -#endif /* __ARCH_WANT_SYS_SIGPROCMASK */ -#ifdef __ARCH_WANT_SYS_RT_SIGACTION +#endif /* SIGPROCMASK */ + +#ifndef __sparc__ asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, @@ -2505,7 +2545,7 @@ sys_rt_sigaction(int sig, out: return ret; } -#endif /* __ARCH_WANT_SYS_RT_SIGACTION */ +#endif /* __sparc__ */ #ifdef __ARCH_WANT_SYS_SGETMASK diff --git a/kernel/sys.c b/kernel/sys.c index 1bbc66a60..6f2b0f170 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include @@ -343,7 +345,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) if (!who) user = current->user; else - user = find_user(who); + user = find_user(vx_current_xid(), who); if (!user) goto out_unlock; @@ -404,7 +406,7 @@ asmlinkage long sys_getpriority(int which, int who) if (!who) user = current->user; else - user = find_user(who); + user = find_user(vx_current_xid(), who); if (!user) goto out_unlock; @@ -426,6 +428,72 @@ out_unlock: return retval; } +/* + * vshelper path is set via /proc/sys + * invoked by vserver sys_reboot(), with + * the following arguments + * + * argv [0] = vshelper_path; + * argv [1] = action: "restart", "halt", "poweroff", ... + * argv [2] = context identifier + * argv [3] = additional argument (restart2) + * + * envp [*] = type-specific parameters + */ +char vshelper_path[255] = "/sbin/vshelper"; + +long vs_reboot(unsigned int cmd, void * arg) +{ + char id_buf[8], cmd_buf[32]; + char uid_buf[32], pid_buf[32]; + char buffer[256]; + + char *argv[] = {vshelper_path, NULL, id_buf, NULL, 0}; + char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + uid_buf, pid_buf, cmd_buf, 0}; + + snprintf(id_buf, sizeof(id_buf)-1, "%d", vx_current_xid()); + + snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); + snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current->uid); + snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid); + + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + argv[1] = "restart"; + break; + + case LINUX_REBOOT_CMD_HALT: + argv[1] = "halt"; + break; + + case LINUX_REBOOT_CMD_POWER_OFF: + argv[1] = "poweroff"; + break; + + case LINUX_REBOOT_CMD_SW_SUSPEND: + argv[1] = "swsusp"; + break; + + case LINUX_REBOOT_CMD_RESTART2: + if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) + return -EFAULT; + argv[3] = buffer; + default: + argv[1] = "restart2"; + break; + } + + /* maybe we should wait ? */ + if (call_usermodehelper(*argv, argv, envp, 0)) { + printk( KERN_WARNING + "vs_reboot(): failed to exec (%s %s %s %s)\n", + vshelper_path, argv[1], argv[2], argv[3]); + return -EPERM; + } + return 0; +} /* * Reboot system call: for obvious reasons only root may call it, @@ -451,6 +519,9 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL; + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + return vs_reboot(cmd, arg); + lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: @@ -601,6 +672,9 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) current->fsgid = new_egid; current->egid = new_egid; current->gid = new_rgid; + + ckrm_cb_gid(); + return 0; } @@ -638,6 +712,9 @@ asmlinkage long sys_setgid(gid_t gid) } else return -EPERM; + + ckrm_cb_gid(); + return 0; } @@ -645,7 +722,7 @@ static int set_user(uid_t new_ruid, int dumpclear) { struct user_struct *new_user; - new_user = alloc_uid(new_ruid); + new_user = alloc_uid(vx_current_xid(), new_ruid); if (!new_user) return -EAGAIN; @@ -726,6 +803,8 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) current->suid = current->euid; current->fsuid = current->euid; + ckrm_cb_uid(); + return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); } @@ -771,6 +850,8 @@ asmlinkage long sys_setuid(uid_t uid) current->fsuid = current->euid = uid; current->suid = new_suid; + ckrm_cb_uid(); + return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); } @@ -817,6 +898,8 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) if (suid != (uid_t) -1) current->suid = suid; + ckrm_cb_uid(); + return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } @@ -866,6 +949,9 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) current->gid = rgid; if (sgid != (gid_t) -1) current->sgid = sgid; + + ckrm_cb_gid(); + return 0; } @@ -1393,7 +1479,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name) int errno = 0; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (copy_to_user(name, vx_new_utsname(), sizeof *name)) errno = -EFAULT; up_read(&uts_sem); return errno; @@ -1404,15 +1490,17 @@ asmlinkage long sys_sethostname(char __user *name, int len) int errno; char tmp[__NEW_UTS_LEN]; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SET_UTSNAME)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - memcpy(system_utsname.nodename, tmp, len); - system_utsname.nodename[len] = 0; + char *ptr = vx_new_uts(nodename); + + memcpy(ptr, tmp, len); + ptr[len] = 0; errno = 0; } up_write(&uts_sem); @@ -1424,15 +1512,17 @@ asmlinkage long sys_sethostname(char __user *name, int len) asmlinkage long sys_gethostname(char __user *name, int len) { int i, errno; + char *ptr; if (len < 0) return -EINVAL; down_read(&uts_sem); - i = 1 + strlen(system_utsname.nodename); + ptr = vx_new_uts(nodename); + i = 1 + strlen(ptr); if (i > len) i = len; errno = 0; - if (copy_to_user(name, system_utsname.nodename, i)) + if (copy_to_user(name, ptr, i)) errno = -EFAULT; up_read(&uts_sem); return errno; @@ -1449,7 +1539,7 @@ asmlinkage long sys_setdomainname(char __user *name, int len) int errno; char tmp[__NEW_UTS_LEN]; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SET_UTSNAME)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -1457,8 +1547,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len) down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(tmp, name, len)) { - memcpy(system_utsname.domainname, tmp, len); - system_utsname.domainname[len] = 0; + char *ptr = vx_new_uts(domainname); + + memcpy(ptr, tmp, len); + ptr[len] = 0; errno = 0; } up_write(&uts_sem); @@ -1510,7 +1602,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && - !capable(CAP_SYS_RESOURCE)) + !capable(CAP_SYS_RESOURCE) && vx_ccaps(VXC_SET_RLIMIT)) return -EPERM; if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ae990887f..40b0d358c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -65,6 +65,29 @@ extern int min_free_kbytes; extern int printk_ratelimit_jiffies; extern int printk_ratelimit_burst; +extern unsigned int vdso_enabled; + +int exec_shield = 1; +int exec_shield_randomize = 1; + +static int __init setup_exec_shield(char *str) +{ + get_option (&str, &exec_shield); + + return 1; +} + +__setup("exec-shield=", setup_exec_shield); + +static int __init setup_exec_shield_randomize(char *str) +{ + get_option (&str, &exec_shield_randomize); + + return 1; +} + +__setup("exec-shield-randomize=", setup_exec_shield_randomize); + /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; static int minolduid; @@ -77,6 +100,7 @@ extern char modprobe_path[]; #ifdef CONFIG_HOTPLUG extern char hotplug_path[]; #endif +extern char vshelper_path[]; #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; #endif @@ -218,7 +242,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_OSTYPE, .procname = "ostype", .data = system_utsname.sysname, - .maxlen = sizeof(system_utsname.sysname), + .maxlen = 64, .mode = 0444, .proc_handler = &proc_doutsstring, .strategy = &sysctl_string, @@ -227,7 +251,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_OSRELEASE, .procname = "osrelease", .data = system_utsname.release, - .maxlen = sizeof(system_utsname.release), + .maxlen = 64, .mode = 0444, .proc_handler = &proc_doutsstring, .strategy = &sysctl_string, @@ -236,7 +260,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_VERSION, .procname = "version", .data = system_utsname.version, - .maxlen = sizeof(system_utsname.version), + .maxlen = 64, .mode = 0444, .proc_handler = &proc_doutsstring, .strategy = &sysctl_string, @@ -245,7 +269,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_NODENAME, .procname = "hostname", .data = system_utsname.nodename, - .maxlen = sizeof(system_utsname.nodename), + .maxlen = 64, .mode = 0644, .proc_handler = &proc_doutsstring, .strategy = &sysctl_string, @@ -254,7 +278,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_DOMAINNAME, .procname = "domainname", .data = system_utsname.domainname, - .maxlen = sizeof(system_utsname.domainname), + .maxlen = 64, .mode = 0644, .proc_handler = &proc_doutsstring, .strategy = &sysctl_string, @@ -267,6 +291,40 @@ static ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = KERN_PANIC, + .procname = "exec-shield", + .data = &exec_shield, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_PANIC, + .procname = "exec-shield-randomize", + .data = &exec_shield_randomize, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_PANIC, + .procname = "print-fatal-signals", + .data = &print_fatal_signals, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#if __i386__ + { + .ctl_name = KERN_PANIC, + .procname = "vdso", + .data = &vdso_enabled, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif { .ctl_name = KERN_CORE_USES_PID, .procname = "core_uses_pid", @@ -392,7 +450,7 @@ static ctl_table kern_table[] = { .ctl_name = KERN_MODPROBE, .procname = "modprobe", .data = &modprobe_path, - .maxlen = KMOD_PATH_LEN, + .maxlen = 256, .mode = 0644, .proc_handler = &proc_dostring, .strategy = &sysctl_string, @@ -403,12 +461,21 @@ static ctl_table kern_table[] = { .ctl_name = KERN_HOTPLUG, .procname = "hotplug", .data = &hotplug_path, - .maxlen = KMOD_PATH_LEN, + .maxlen = 256, .mode = 0644, .proc_handler = &proc_dostring, .strategy = &sysctl_string, }, #endif + { + .ctl_name = KERN_VSHELPER, + .procname = "vshelper", + .data = &vshelper_path, + .maxlen = 256, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, #ifdef CONFIG_CHR_DEV_SG { .ctl_name = KERN_SG_BIG_BUFF, @@ -738,14 +805,6 @@ static ctl_table vm_table[] = { .extra1 = (void *)&hugetlb_zero, .extra2 = (void *)&hugetlb_infinity, }, - { - .ctl_name = VM_HUGETLB_GROUP, - .procname = "hugetlb_shm_group", - .data = &sysctl_hugetlb_shm_group, - .maxlen = sizeof(gid_t), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, #endif { .ctl_name = VM_LOWER_ZONE_PROTECTION, @@ -1917,56 +1976,56 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, #else /* CONFIG_PROC_FS */ int proc_dostring(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } static int proc_doutsstring(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } @@ -2141,13 +2200,13 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, } int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { return -ENOSYS; } diff --git a/kernel/timer.c b/kernel/timer.c index 3a8162b97..0e4b116a7 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -996,7 +998,7 @@ asmlinkage unsigned long sys_alarm(unsigned int seconds) */ asmlinkage long sys_getpid(void) { - return current->tgid; + return vx_map_tgid(current->vx_info, current->tgid); } /* @@ -1040,7 +1042,7 @@ asmlinkage long sys_getppid(void) #endif break; } - return pid; + return vx_map_tgid(current->vx_info, pid); } asmlinkage long sys_getuid(void) @@ -1249,6 +1251,8 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info) tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC; tp.tv_sec++; } + if (vx_flags(VXF_VIRT_UPTIME, 0)) + vx_vsi_uptime(&tp, NULL); val.uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); @@ -1258,6 +1262,9 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info) val.procs = nr_threads; } while (read_seqretry(&xtime_lock, seq)); +/* if (vx_flags(VXF_VIRT_CPU, 0)) + vx_vsi_cpu(val); +*/ si_meminfo(&val); si_swapinfo(&val); diff --git a/kernel/user.c b/kernel/user.c index 60e942b8f..209a7d1fa 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -20,8 +20,8 @@ #define UIDHASH_BITS 8 #define UIDHASH_SZ (1 << UIDHASH_BITS) #define UIDHASH_MASK (UIDHASH_SZ - 1) -#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) -#define uidhashentry(uid) (uidhash_table + __uidhashfn((uid))) +#define __uidhashfn(xid,uid) ((((uid) >> UIDHASH_BITS) + ((uid)^(xid))) & UIDHASH_MASK) +#define uidhashentry(xid,uid) (uidhash_table + __uidhashfn((xid),(uid))) static kmem_cache_t *uid_cachep; static struct list_head uidhash_table[UIDHASH_SZ]; @@ -46,7 +46,7 @@ static inline void uid_hash_remove(struct user_struct *up) list_del(&up->uidhash_list); } -static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *hashent) +static inline struct user_struct *uid_hash_find(xid_t xid, uid_t uid, struct list_head *hashent) { struct list_head *up; @@ -55,7 +55,7 @@ static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *has user = list_entry(up, struct user_struct, uidhash_list); - if(user->uid == uid) { + if(user->uid == uid && user->xid == xid) { atomic_inc(&user->__count); return user; } @@ -70,12 +70,12 @@ static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *has * * If the user_struct could not be found, return NULL. */ -struct user_struct *find_user(uid_t uid) +struct user_struct *find_user(xid_t xid, uid_t uid) { struct user_struct *ret; spin_lock(&uidhash_lock); - ret = uid_hash_find(uid, uidhashentry(uid)); + ret = uid_hash_find(xid, uid, uidhashentry(xid, uid)); spin_unlock(&uidhash_lock); return ret; } @@ -89,13 +89,13 @@ void free_uid(struct user_struct *up) } } -struct user_struct * alloc_uid(uid_t uid) +struct user_struct * alloc_uid(xid_t xid, uid_t uid) { - struct list_head *hashent = uidhashentry(uid); + struct list_head *hashent = uidhashentry(xid, uid); struct user_struct *up; spin_lock(&uidhash_lock); - up = uid_hash_find(uid, hashent); + up = uid_hash_find(xid, uid, hashent); spin_unlock(&uidhash_lock); if (!up) { @@ -105,6 +105,7 @@ struct user_struct * alloc_uid(uid_t uid) if (!new) return NULL; new->uid = uid; + new->xid = xid; atomic_set(&new->__count, 1); atomic_set(&new->processes, 0); atomic_set(&new->files, 0); @@ -114,7 +115,7 @@ struct user_struct * alloc_uid(uid_t uid) * on adding the same user already.. */ spin_lock(&uidhash_lock); - up = uid_hash_find(uid, hashent); + up = uid_hash_find(xid, uid, hashent); if (up) { kmem_cache_free(uid_cachep, new); } else { @@ -156,7 +157,7 @@ static int __init uid_cache_init(void) /* Insert the root user immediately (init already runs as root) */ spin_lock(&uidhash_lock); - uid_hash_insert(&root_user, uidhashentry(0)); + uid_hash_insert(&root_user, uidhashentry(0,0)); spin_unlock(&uidhash_lock); return 0; diff --git a/kernel/vserver/Kconfig b/kernel/vserver/Kconfig new file mode 100644 index 000000000..635d8d488 --- /dev/null +++ b/kernel/vserver/Kconfig @@ -0,0 +1,72 @@ +# +# Linux VServer configuration +# + +menu "Linux VServer" + +config VSERVER_LEGACY + bool "Enable Legacy Kernel API" + default y + help + This enables the legacy API used in vs1.xx, which allows + to use older tools (for migration purposes). + +config PROC_SECURE + bool "Enable Proc Security" + depends on PROC_FS + default y + help + Hide proc entries by default for xid>1 + +config VSERVER_HARDCPU + bool "Enable Hard CPU Limits" + depends on EXPERIMENTAL + default n + help + Activate the Hard CPU Limits + +choice + prompt "Persistent Inode Context Tagging" + default INOXID_GID24 + help + This adds persistent context information to filesystems + mounted with the tagxid option. Tagging is a requirement + for per context disk limits and per context quota. + + +config INOXID_NONE + bool "Disabled" + help + no context information is store for inodes + +config INOXID_GID16 + bool "UID32/GID16" + help + reduces GID to 16 bit, but leaves UID at 32 bit. + +config INOXID_GID24 + bool "UID24/GID24" + help + uses the upper 8bit from UID and GID for XID tagging + which leaves 24bit for UID/GID each, which should be + more than sufficient for normal use. + +config INOXID_GID32 + bool "UID32/GID32" + help + this uses otherwise reserved inode fields in the on + disk representation, which limits the use to a few + filesystems (currently ext2 and ext3) + +config INOXID_MAGIC + bool "Runtime" + depends on EXPERIMENTAL + help + inodes are tagged when first accessed, this doesn't + require any persistant information, but might give + funny results for mixed access. + +endchoice + +endmenu + diff --git a/kernel/vserver/Makefile b/kernel/vserver/Makefile new file mode 100644 index 000000000..de2ff2846 --- /dev/null +++ b/kernel/vserver/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Linux vserver routines. +# + + +obj-y += vserver.o + +vserver-y := switch.o context.o namespace.o sched.o network.o inode.o \ + limit.o cvirt.o signal.o proc.o sysctl.o helper.o init.o \ + dlimit.o + +vserver-$(CONFIG_VSERVER_LEGACY) += legacy.o + diff --git a/kernel/vserver/context.c b/kernel/vserver/context.c new file mode 100644 index 000000000..533e10439 --- /dev/null +++ b/kernel/vserver/context.c @@ -0,0 +1,700 @@ +/* + * linux/kernel/vserver/context.c + * + * Virtual Server: Context Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 context helper + * V0.02 vx_ctx_kill syscall command + * V0.03 replaced context_info calls + * V0.04 redesign of struct (de)alloc + * V0.05 rlimit basic implementation + * V0.06 task_xid and info commands + * V0.07 context flags and caps + * V0.08 switch to RCU based hash + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* __alloc_vx_info() + + * allocate an initialized vx_info struct + * doesn't make it visible (hash) */ + +static struct vx_info *__alloc_vx_info(xid_t xid) +{ + struct vx_info *new = NULL; + + vxdprintk("alloc_vx_info(%d)\n", xid); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct vx_info), GFP_KERNEL); + if (!new) + return 0; + + memset (new, 0, sizeof(struct vx_info)); + new->vx_id = xid; + INIT_RCU_HEAD(&new->vx_rcu); + INIT_HLIST_NODE(&new->vx_hlist); + atomic_set(&new->vx_refcnt, 0); + atomic_set(&new->vx_usecnt, 0); + + /* rest of init goes here */ + vx_info_init_limit(&new->limit); + vx_info_init_sched(&new->sched); + vx_info_init_cvirt(&new->cvirt); + vx_info_init_cacct(&new->cacct); + + new->vx_flags = VXF_STATE_SETUP|VXF_STATE_INIT; + new->vx_bcaps = CAP_INIT_EFF_SET; + new->vx_ccaps = 0; + + vxdprintk("alloc_vx_info(%d) = %p\n", xid, new); + return new; +} + +/* __dealloc_vx_info() + + * final disposal of vx_info */ + +static void __dealloc_vx_info(struct vx_info *vxi) +{ + vxdprintk("dealloc_vx_info(%p)\n", vxi); + + vxi->vx_hlist.next = LIST_POISON1; + vxi->vx_id = -1; + + if (vxi->vx_namespace) + put_namespace(vxi->vx_namespace); + if (vxi->vx_fs) + put_fs_struct(vxi->vx_fs); + + vx_info_exit_limit(&vxi->limit); + vx_info_exit_sched(&vxi->sched); + vx_info_exit_cvirt(&vxi->cvirt); + vx_info_exit_cacct(&vxi->cacct); + + BUG_ON(atomic_read(&vxi->vx_usecnt)); + BUG_ON(atomic_read(&vxi->vx_refcnt)); + + kfree(vxi); +} + + +/* hash table for vx_info hash */ + +#define VX_HASH_SIZE 13 + +struct hlist_head vx_info_hash[VX_HASH_SIZE]; + +static spinlock_t vx_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(xid_t xid) +{ + return (xid % VX_HASH_SIZE); +} + + + +/* __hash_vx_info() + + * add the vxi to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_vx_info(struct vx_info *vxi) +{ + struct hlist_head *head; + + vxdprintk("__hash_vx_info: %p[#%d]\n", vxi, vxi->vx_id); + get_vx_info(vxi); + head = &vx_info_hash[__hashval(vxi->vx_id)]; + hlist_add_head_rcu(&vxi->vx_hlist, head); +} + +/* __unhash_vx_info() + + * remove the vxi from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_vx_info(struct vx_info *vxi) +{ + vxdprintk("__unhash_vx_info: %p[#%d]\n", vxi, vxi->vx_id); + hlist_del_rcu(&vxi->vx_hlist); + put_vx_info(vxi); +} + + +/* __lookup_vx_info() + + * requires the rcu_read_lock() + * doesn't increment the vx_refcnt */ + +static inline struct vx_info *__lookup_vx_info(xid_t xid) +{ + struct hlist_head *head = &vx_info_hash[__hashval(xid)]; + struct hlist_node *pos; + + hlist_for_each_rcu(pos, head) { + struct vx_info *vxi = + hlist_entry(pos, struct vx_info, vx_hlist); + + if (vxi->vx_id == xid) { + return vxi; + } + } + return NULL; +} + + +/* __vx_dynamic_id() + + * find unused dynamic xid + * requires the hash_lock to be held */ + +static inline xid_t __vx_dynamic_id(void) +{ + static xid_t seq = MAX_S_CONTEXT; + xid_t barrier = seq; + + do { + if (++seq > MAX_S_CONTEXT) + seq = MIN_D_CONTEXT; + if (!__lookup_vx_info(seq)) + return seq; + } while (barrier != seq); + return 0; +} + +/* __loc_vx_info() + + * locate or create the requested context + * get() it and if new hash it */ + +static struct vx_info * __loc_vx_info(int id, int *err) +{ + struct vx_info *new, *vxi = NULL; + + vxdprintk("loc_vx_info(%d)\n", id); + + if (!(new = __alloc_vx_info(id))) { + *err = -ENOMEM; + return NULL; + } + + spin_lock(&vx_info_hash_lock); + + /* dynamic context requested */ + if (id == VX_DYNAMIC_ID) { + id = __vx_dynamic_id(); + if (!id) { + printk(KERN_ERR "no dynamic context available.\n"); + goto out_unlock; + } + new->vx_id = id; + } + /* existing context requested */ + else if ((vxi = __lookup_vx_info(id))) { + /* context in setup is not available */ + if (vxi->vx_flags & VXF_STATE_SETUP) { + vxdprintk("loc_vx_info(%d) = %p (not available)\n", id, vxi); + vxi = NULL; + *err = -EBUSY; + } else { + vxdprintk("loc_vx_info(%d) = %p (found)\n", id, vxi); + get_vx_info(vxi); + *err = 0; + } + goto out_unlock; + } + + /* new context requested */ + vxdprintk("loc_vx_info(%d) = %p (new)\n", id, new); + __hash_vx_info(get_vx_info(new)); + vxi = new, new = NULL; + *err = 1; + +out_unlock: + spin_unlock(&vx_info_hash_lock); + if (new) + __dealloc_vx_info(new); + return vxi; +} + + + +/* exported stuff */ + + + +void rcu_free_vx_info(void *obj) +{ + struct vx_info *vxi = obj; + int usecnt, refcnt; + + BUG_ON(!vxi); + + usecnt = atomic_read(&vxi->vx_usecnt); + BUG_ON(usecnt < 0); + + refcnt = atomic_read(&vxi->vx_refcnt); + BUG_ON(refcnt < 0); + + if (!usecnt) + __dealloc_vx_info(vxi); + else + printk("!!! rcu didn't free\n"); +} + +void unhash_vx_info(struct vx_info *vxi) +{ + spin_lock(&vx_info_hash_lock); + __unhash_vx_info(vxi); + spin_unlock(&vx_info_hash_lock); +} + +/* locate_vx_info() + + * search for a vx_info and get() it + * negative id means current */ + +struct vx_info *locate_vx_info(int id) +{ + struct vx_info *vxi; + + if (id < 0) { + vxi = get_vx_info(current->vx_info); + } else { + rcu_read_lock(); + vxi = get_vx_info(__lookup_vx_info(id)); + rcu_read_unlock(); + } + return vxi; +} + +/* vx_info_is_hashed() + + * verify that xid is still hashed */ + +int vx_info_is_hashed(xid_t xid) +{ + int hashed; + + rcu_read_lock(); + hashed = (__lookup_vx_info(xid) != NULL); + rcu_read_unlock(); + return hashed; +} + +#ifdef CONFIG_VSERVER_LEGACY + +#if 0 +struct vx_info *alloc_vx_info(xid_t xid) +{ + return __alloc_vx_info(xid); +} +#endif + +struct vx_info *locate_or_create_vx_info(int id) +{ + int err; + + return __loc_vx_info(id, &err); +} + +#endif + +#ifdef CONFIG_PROC_FS + +#define hlist_for_each_rcu(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +int get_xid_list(int index, unsigned int *xids, int size) +{ + int hindex, nr_xids = 0; + + rcu_read_lock(); + for (hindex = 0; hindex < VX_HASH_SIZE; hindex++) { + struct hlist_head *head = &vx_info_hash[hindex]; + struct hlist_node *pos; + + hlist_for_each_rcu(pos, head) { + struct vx_info *vxi; + + if (--index > 0) + continue; + + vxi = hlist_entry(pos, struct vx_info, vx_hlist); + xids[nr_xids] = vxi->vx_id; + if (++nr_xids >= size) + goto out; + } + } +out: + rcu_read_unlock(); + return nr_xids; +} +#endif + +int vx_migrate_user(struct task_struct *p, struct vx_info *vxi) +{ + struct user_struct *new_user, *old_user; + + if (!p || !vxi) + BUG(); + new_user = alloc_uid(vxi->vx_id, p->uid); + if (!new_user) + return -ENOMEM; + + old_user = p->user; + if (new_user != old_user) { + atomic_inc(&new_user->processes); + atomic_dec(&old_user->processes); + p->user = new_user; + } + free_uid(old_user); + return 0; +} + +void vx_mask_bcaps(struct task_struct *p) +{ + struct vx_info *vxi = p->vx_info; + + p->cap_effective &= vxi->vx_bcaps; + p->cap_inheritable &= vxi->vx_bcaps; + p->cap_permitted &= vxi->vx_bcaps; +} + + +#include + +static inline int vx_nofiles_task(struct task_struct *tsk) +{ + struct files_struct *files = tsk->files; + const unsigned long *obptr, *cbptr; + int count, total; + + spin_lock(&files->file_lock); + obptr = files->open_fds->fds_bits; + cbptr = files->close_on_exec->fds_bits; + count = files->max_fds / (sizeof(unsigned long) * 8); + for (total = 0; count > 0; count--) { + if (*obptr) + total += hweight_long(*obptr); + obptr++; + /* if (*cbptr) + total += hweight_long(*cbptr); + cbptr++; */ + } + spin_unlock(&files->file_lock); + return total; +} + +static inline int vx_openfd_task(struct task_struct *tsk) +{ + struct files_struct *files = tsk->files; + const unsigned long *bptr; + int count, total; + + spin_lock(&files->file_lock); + bptr = files->open_fds->fds_bits; + count = files->max_fds / (sizeof(unsigned long) * 8); + for (total = 0; count > 0; count--) { + if (*bptr) + total += hweight_long(*bptr); + bptr++; + } + spin_unlock(&files->file_lock); + return total; +} + +/* + * migrate task to new context + * gets vxi, puts old_vxi on change + */ + +int vx_migrate_task(struct task_struct *p, struct vx_info *vxi) +{ + struct vx_info *old_vxi; + int ret = 0; + + if (!p || !vxi) + BUG(); + + old_vxi = task_get_vx_info(p); + if (old_vxi == vxi) + goto out; + + vxdprintk("vx_migrate_task(%p,%p[#%d.%d)\n", p, vxi, + vxi->vx_id, atomic_read(&vxi->vx_usecnt)); + + if (!(ret = vx_migrate_user(p, vxi))) { + int openfd, nofiles; + + task_lock(p); + openfd = vx_openfd_task(p); + nofiles = vx_nofiles_task(p); + + if (old_vxi) { + atomic_dec(&old_vxi->cacct.nr_threads); + atomic_dec(&old_vxi->limit.rcur[RLIMIT_NPROC]); + atomic_sub(nofiles, &vxi->limit.rcur[RLIMIT_NOFILE]); + atomic_sub(openfd, &vxi->limit.rcur[RLIMIT_OPENFD]); + } + atomic_inc(&vxi->cacct.nr_threads); + atomic_inc(&vxi->limit.rcur[RLIMIT_NPROC]); + atomic_add(nofiles, &vxi->limit.rcur[RLIMIT_NOFILE]); + atomic_add(openfd, &vxi->limit.rcur[RLIMIT_OPENFD]); + /* should be handled in set_vx_info !! */ + if (old_vxi) + clr_vx_info(&p->vx_info); + set_vx_info(&p->vx_info, vxi); + p->xid = vxi->vx_id; + vx_mask_bcaps(p); + task_unlock(p); + + /* obsoleted by clr/set */ + // put_vx_info(old_vxi); + } +out: + put_vx_info(old_vxi); + return ret; +} + +int vx_set_init(struct vx_info *vxi, struct task_struct *p) +{ + if (!vxi) + return -EINVAL; + if (vxi->vx_initpid) + return -EPERM; + + vxi->vx_initpid = p->tgid; + return 0; +} + + +/* vserver syscall commands below here */ + +/* taks xid and vx_info functions */ + +#include + + +int vc_task_xid(uint32_t id, void __user *data) +{ + xid_t xid; + + if (id) { + struct task_struct *tsk; + + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + return -EPERM; + + read_lock(&tasklist_lock); + tsk = find_task_by_pid(id); + xid = (tsk) ? tsk->xid : -ESRCH; + read_unlock(&tasklist_lock); + } + else + xid = current->xid; + return xid; +} + + +int vc_vx_info(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_vx_info_v0 vc_data; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + vc_data.xid = vxi->vx_id; + vc_data.initpid = vxi->vx_initpid; + put_vx_info(vxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +/* context functions */ + +int vc_ctx_create(uint32_t xid, void __user *data) +{ + struct vx_info *new_vxi; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if ((xid >= MIN_D_CONTEXT) && (xid != VX_DYNAMIC_ID)) + return -EINVAL; + + if (xid < 1) + return -EINVAL; + + new_vxi = __loc_vx_info(xid, &ret); + if (!new_vxi) + return ret; + if (!(new_vxi->vx_flags & VXF_STATE_SETUP)) { + ret = -EEXIST; + goto out_put; + } + + ret = new_vxi->vx_id; + vx_migrate_task(current, new_vxi); + /* if this fails, we might end up with a hashed vx_info */ +out_put: + put_vx_info(new_vxi); + return ret; +} + + +int vc_ctx_migrate(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* dirty hack until Spectator becomes a cap */ + if (id == 1) { + current->xid = 1; + return 0; + } + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + vx_migrate_task(current, vxi); + put_vx_info(vxi); + return 0; +} + + +int vc_get_cflags(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_flags_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + vc_data.flagword = vxi->vx_flags; + + /* special STATE flag handling */ + vc_data.mask = vx_mask_flags(~0UL, vxi->vx_flags, VXF_ONE_TIME); + + put_vx_info(vxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_cflags(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_flags_v0 vc_data; + uint64_t mask, trigger; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + /* special STATE flag handling */ + mask = vx_mask_mask(vc_data.mask, vxi->vx_flags, VXF_ONE_TIME); + trigger = (mask & vxi->vx_flags) ^ (mask & vc_data.flagword); + + if (trigger & VXF_STATE_SETUP) + vx_mask_bcaps(current); + if (trigger & VXF_STATE_INIT) + if (vxi == current->vx_info) + vx_set_init(vxi, current); + + vxi->vx_flags = vx_mask_flags(vxi->vx_flags, + vc_data.flagword, mask); + put_vx_info(vxi); + return 0; +} + +int vc_get_ccaps(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_caps_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + vc_data.bcaps = vxi->vx_bcaps; + vc_data.ccaps = vxi->vx_ccaps; + vc_data.cmask = ~0UL; + put_vx_info(vxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_ccaps(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_caps_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + vxi->vx_bcaps &= vc_data.bcaps; + vxi->vx_ccaps = vx_mask_flags(vxi->vx_ccaps, + vc_data.ccaps, vc_data.cmask); + put_vx_info(vxi); + return 0; +} + +#include + +EXPORT_SYMBOL_GPL(rcu_free_vx_info); +EXPORT_SYMBOL_GPL(vx_info_hash_lock); +EXPORT_SYMBOL_GPL(unhash_vx_info); + diff --git a/kernel/vserver/cvirt.c b/kernel/vserver/cvirt.c new file mode 100644 index 000000000..cdcb86a13 --- /dev/null +++ b/kernel/vserver/cvirt.c @@ -0,0 +1,43 @@ +/* + * linux/kernel/vserver/cvirt.c + * + * Virtual Server: Context Virtualization + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 broken out from limit.c + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle) +{ + struct vx_info *vxi = current->vx_info; + + set_normalized_timespec(uptime, + uptime->tv_sec - vxi->cvirt.bias_tp.tv_sec, + uptime->tv_nsec - vxi->cvirt.bias_tp.tv_nsec); + if (!idle) + return; + set_normalized_timespec(idle, + idle->tv_sec - vxi->cvirt.bias_idle.tv_sec, + idle->tv_nsec - vxi->cvirt.bias_idle.tv_nsec); + return; +} + +uint64_t vx_idle_jiffies() +{ + return init_task.utime + init_task.stime; +} + diff --git a/kernel/vserver/dlimit.c b/kernel/vserver/dlimit.c new file mode 100644 index 000000000..eb9282f9f --- /dev/null +++ b/kernel/vserver/dlimit.c @@ -0,0 +1,439 @@ +/* + * linux/kernel/vserver/dlimit.c + * + * Virtual Server: Context Disk Limits + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 initial version + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* __alloc_dl_info() + + * allocate an initialized dl_info struct + * doesn't make it visible (hash) */ + +static struct dl_info *__alloc_dl_info(struct super_block *sb, xid_t xid) +{ + struct dl_info *new = NULL; + + vxdprintk("alloc_dl_info(%p,%d)\n", sb, xid); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct dl_info), GFP_KERNEL); + if (!new) + return 0; + + memset (new, 0, sizeof(struct dl_info)); + new->dl_xid = xid; + new->dl_sb = sb; + INIT_RCU_HEAD(&new->dl_rcu); + INIT_HLIST_NODE(&new->dl_hlist); + spin_lock_init(&new->dl_lock); + atomic_set(&new->dl_refcnt, 0); + atomic_set(&new->dl_usecnt, 0); + + /* rest of init goes here */ + + vxdprintk("alloc_dl_info(%p,%d) = %p\n", sb, xid, new); + return new; +} + +/* __dealloc_dl_info() + + * final disposal of dl_info */ + +static void __dealloc_dl_info(struct dl_info *dli) +{ + vxdprintk("dealloc_dl_info(%p)\n", dli); + + dli->dl_hlist.next = LIST_POISON1; + dli->dl_xid = -1; + dli->dl_sb = 0; + + BUG_ON(atomic_read(&dli->dl_usecnt)); + BUG_ON(atomic_read(&dli->dl_refcnt)); + + kfree(dli); +} + + +/* hash table for dl_info hash */ + +#define DL_HASH_SIZE 13 + +struct hlist_head dl_info_hash[DL_HASH_SIZE]; + +static spinlock_t dl_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(struct super_block *sb, xid_t xid) +{ + return ((xid ^ (unsigned int)sb) % DL_HASH_SIZE); +} + + + +/* __hash_dl_info() + + * add the dli to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_dl_info(struct dl_info *dli) +{ + struct hlist_head *head; + + vxdprintk("__hash_dl_info: %p[#%d]\n", dli, dli->dl_xid); + get_dl_info(dli); + head = &dl_info_hash[__hashval(dli->dl_sb, dli->dl_xid)]; + hlist_add_head_rcu(&dli->dl_hlist, head); +} + +/* __unhash_dl_info() + + * remove the dli from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_dl_info(struct dl_info *dli) +{ + vxdprintk("__unhash_dl_info: %p[#%d]\n", dli, dli->dl_xid); + hlist_del_rcu(&dli->dl_hlist); + put_dl_info(dli); +} + + +#define hlist_for_each_rcu(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + + +/* __lookup_dl_info() + + * requires the rcu_read_lock() + * doesn't increment the dl_refcnt */ + +static inline struct dl_info *__lookup_dl_info(struct super_block *sb, xid_t xid) +{ + struct hlist_head *head = &dl_info_hash[__hashval(sb, xid)]; + struct hlist_node *pos; + + hlist_for_each_rcu(pos, head) { + struct dl_info *dli = + hlist_entry(pos, struct dl_info, dl_hlist); + + if (dli->dl_xid == xid && dli->dl_sb == sb) { + return dli; + } + } + return NULL; +} + + +struct dl_info *locate_dl_info(struct super_block *sb, xid_t xid) +{ + struct dl_info *dli; + + rcu_read_lock(); + dli = get_dl_info(__lookup_dl_info(sb, xid)); + rcu_read_unlock(); + return dli; +} + +void rcu_free_dl_info(void *obj) +{ + struct dl_info *dli = obj; + int usecnt, refcnt; + + BUG_ON(!dli); + + usecnt = atomic_read(&dli->dl_usecnt); + BUG_ON(usecnt < 0); + + refcnt = atomic_read(&dli->dl_refcnt); + BUG_ON(refcnt < 0); + + if (!usecnt) + __dealloc_dl_info(dli); + else + printk("!!! rcu didn't free\n"); +} + + + + +int vc_add_dlimit(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_dlimit_base_v0 vc_data; + int ret; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!nd.dentry->d_inode) + goto out_release; + if (!(sb = nd.dentry->d_inode->i_sb)) + goto out_release; + + dli = __alloc_dl_info(sb, id); + spin_lock(&dl_info_hash_lock); + + ret = -EEXIST; + if (__lookup_dl_info(sb, id)) + goto out_unlock; + __hash_dl_info(dli); + dli = NULL; + ret = 0; + + out_unlock: + spin_unlock(&dl_info_hash_lock); + if (dli) + __dealloc_dl_info(dli); + out_release: + path_release(&nd); + } + return ret; +} + + +int vc_rem_dlimit(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_dlimit_base_v0 vc_data; + int ret; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!nd.dentry->d_inode) + goto out_release; + if (!(sb = nd.dentry->d_inode->i_sb)) + goto out_release; + + spin_lock(&dl_info_hash_lock); + dli = __lookup_dl_info(sb, id); + + ret = -ESRCH; + if (!dli) + goto out_unlock; + + __unhash_dl_info(dli); + ret = 0; + + out_unlock: + spin_unlock(&dl_info_hash_lock); + out_release: + path_release(&nd); + } + return ret; +} + + +int vc_set_dlimit(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_dlimit_v0 vc_data; + int ret; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!nd.dentry->d_inode) + goto out_release; + if (!(sb = nd.dentry->d_inode->i_sb)) + goto out_release; + if (vc_data.reserved > 100 || + vc_data.inodes_used > vc_data.inodes_total || + vc_data.space_used > vc_data.space_total) + goto out_release; + + ret = -ESRCH; + dli = locate_dl_info(sb, id); + if (!dli) + goto out_release; + + spin_lock(&dli->dl_lock); + + if (vc_data.inodes_used != (uint32_t)CDLIM_KEEP) + dli->dl_inodes_used = vc_data.inodes_used; + if (vc_data.inodes_total != (uint32_t)CDLIM_KEEP) + dli->dl_inodes_total = vc_data.inodes_total; + if (vc_data.space_used != (uint32_t)CDLIM_KEEP) { + dli->dl_space_used = vc_data.space_used; + dli->dl_space_used <<= 10; + } + if (vc_data.space_total == (uint32_t)CDLIM_INFINITY) + dli->dl_space_total = (uint64_t)CDLIM_INFINITY; + else if (vc_data.space_total != (uint32_t)CDLIM_KEEP) { + dli->dl_space_total = vc_data.space_total; + dli->dl_space_total <<= 10; + } + if (vc_data.reserved != (uint32_t)CDLIM_KEEP) + dli->dl_nrlmult = (1 << 10) * (100 - vc_data.reserved) / 100; + + spin_unlock(&dli->dl_lock); + + put_dl_info(dli); + ret = 0; + + out_release: + path_release(&nd); + } + return ret; +} + +int vc_get_dlimit(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_dlimit_v0 vc_data; + int ret; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!nd.dentry->d_inode) + goto out_release; + if (!(sb = nd.dentry->d_inode->i_sb)) + goto out_release; + if (vc_data.reserved > 100 || + vc_data.inodes_used > vc_data.inodes_total || + vc_data.space_used > vc_data.space_total) + goto out_release; + + ret = -ESRCH; + dli = locate_dl_info(sb, id); + if (!dli) + goto out_release; + + spin_lock(&dli->dl_lock); + vc_data.inodes_used = dli->dl_inodes_used; + vc_data.inodes_total = dli->dl_inodes_total; + vc_data.space_used = dli->dl_space_used >> 10; + if (dli->dl_space_total == (uint64_t)CDLIM_INFINITY) + vc_data.space_total = (uint32_t)CDLIM_INFINITY; + else + vc_data.space_total = dli->dl_space_total >> 10; + + vc_data.reserved = 100 - ((dli->dl_nrlmult * 100 + 512) >> 10); + spin_unlock(&dli->dl_lock); + + put_dl_info(dli); + ret = -EFAULT; + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + goto out_release; + + ret = 0; + out_release: + path_release(&nd); + } + return ret; +} + + +void vx_vsi_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct dl_info *dli; + __u64 blimit, bfree, bavail; + __u32 ifree; + + dli = locate_dl_info(sb, current->xid); + if (!dli) + return; + + spin_lock(&dli->dl_lock); + if (dli->dl_inodes_total == (uint32_t)CDLIM_INFINITY) + goto no_ilim; + + /* reduce max inodes available to limit */ + if (buf->f_files > dli->dl_inodes_total) + buf->f_files = dli->dl_inodes_total; + + ifree = dli->dl_inodes_total - dli->dl_inodes_used; + /* reduce free inodes to min */ + if (ifree < buf->f_ffree) + buf->f_ffree = ifree; + +no_ilim: + if (dli->dl_space_total == (uint64_t)CDLIM_INFINITY) + goto no_blim; + + blimit = dli->dl_space_total >> sb->s_blocksize_bits; + + if (dli->dl_space_total < dli->dl_space_used) + bfree = 0; + else + bfree = (dli->dl_space_total - dli->dl_space_used) + >> sb->s_blocksize_bits; + + bavail = ((dli->dl_space_total >> 10) * dli->dl_nrlmult); + if (bavail < dli->dl_space_used) + bavail = 0; + else + bavail = (bavail - dli->dl_space_used) + >> sb->s_blocksize_bits; + + /* reduce max space available to limit */ + if (buf->f_blocks > blimit) + buf->f_blocks = blimit; + + /* reduce free space to min */ + if (bfree < buf->f_bfree) + buf->f_bfree = bfree; + + /* reduce avail space to min */ + if (bavail < buf->f_bavail) + buf->f_bavail = bavail; + +no_blim: + spin_unlock(&dli->dl_lock); + put_dl_info(dli); + + return; +} + diff --git a/kernel/vserver/helper.c b/kernel/vserver/helper.c new file mode 100644 index 000000000..880b84335 --- /dev/null +++ b/kernel/vserver/helper.c @@ -0,0 +1,92 @@ +/* + * linux/kernel/vserver/helper.c + * + * Virtual Context Support + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 basic helper + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +char vshelper_path[255] = "/sbin/vshelper"; + + +/* + * vshelper path is set via /proc/sys + * invoked by vserver sys_reboot(), with + * the following arguments + * + * argv [0] = vshelper_path; + * argv [1] = action: "restart", "halt", "poweroff", ... + * argv [2] = context identifier + * argv [3] = additional argument (restart2) + * + * envp [*] = type-specific parameters + */ + +long vs_reboot(unsigned int cmd, void * arg) +{ + char id_buf[8], cmd_buf[32]; + char uid_buf[32], pid_buf[32]; + char buffer[256]; + + char *argv[] = {vshelper_path, NULL, id_buf, NULL, 0}; + char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + uid_buf, pid_buf, cmd_buf, 0}; + + snprintf(id_buf, sizeof(id_buf)-1, "%d", vx_current_xid()); + + snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); + snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current->uid); + snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid); + + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + argv[1] = "restart"; + break; + + case LINUX_REBOOT_CMD_HALT: + argv[1] = "halt"; + break; + + case LINUX_REBOOT_CMD_POWER_OFF: + argv[1] = "poweroff"; + break; + + case LINUX_REBOOT_CMD_SW_SUSPEND: + argv[1] = "swsusp"; + break; + + case LINUX_REBOOT_CMD_RESTART2: + if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) + return -EFAULT; + argv[3] = buffer; + default: + argv[1] = "restart2"; + break; + } + + /* maybe we should wait ? */ + if (call_usermodehelper(*argv, argv, envp, 0)) { + printk( KERN_WARNING + "vs_reboot(): failed to exec (%s %s %s %s)\n", + vshelper_path, argv[1], argv[2], argv[3]); + return -EPERM; + } + return 0; +} + diff --git a/kernel/vserver/init.c b/kernel/vserver/init.c new file mode 100644 index 000000000..4a20f268c --- /dev/null +++ b/kernel/vserver/init.c @@ -0,0 +1,41 @@ +/* + * linux/kernel/init.c + * + * Virtual Server Init + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 basic structure + * + */ + +#include +#include +#include +#include +#include + +int vserver_register_sysctl(void); +void vserver_unregister_sysctl(void); + + +static int __init init_vserver(void) +{ + int ret = 0; + + vserver_register_sysctl(); + return ret; +} + + +static void __exit exit_vserver(void) +{ + + vserver_unregister_sysctl(); + return; +} + + +module_init(init_vserver); +module_exit(exit_vserver); + diff --git a/kernel/vserver/inode.c b/kernel/vserver/inode.c new file mode 100644 index 000000000..dda881895 --- /dev/null +++ b/kernel/vserver/inode.c @@ -0,0 +1,221 @@ +/* + * linux/kernel/vserver/inode.c + * + * Virtual Server: File System Support + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 separated from vcontext V0.05 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static int __vc_get_iattr(struct inode *in, uint32_t *xid, uint32_t *flags, uint32_t *mask) +{ + if (!in || !in->i_sb) + return -ESRCH; + + *flags = IATTR_XID + | (IS_BARRIER(in) ? IATTR_BARRIER : 0) + | (IS_IUNLINK(in) ? IATTR_IUNLINK : 0) + | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0); + *mask = IATTR_IUNLINK | IATTR_IMMUTABLE; + + if (S_ISDIR(in->i_mode)) + *mask |= IATTR_BARRIER; + + if (in->i_sb->s_flags & MS_TAGXID) { + *xid = in->i_xid; + *mask |= IATTR_XID; + } + + if (in->i_sb->s_magic == PROC_SUPER_MAGIC) { + struct proc_dir_entry *entry = PROC_I(in)->pde; + + // check for specific inodes ? + if (entry) + *mask |= IATTR_FLAGS; + if (entry) + *flags |= (entry->vx_flags & IATTR_FLAGS); + else + *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS); + } + return 0; +} + +int vc_get_iattr(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_iattr_v1 vc_data; + int ret; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + ret = __vc_get_iattr(nd.dentry->d_inode, + &vc_data.xid, &vc_data.flags, &vc_data.mask); + path_release(&nd); + } + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + +static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask) +{ + struct inode *in = de->d_inode; + int error = 0, is_proc = 0; + + if (!in || !in->i_sb) + return -ESRCH; + + is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC); + if ((*mask & IATTR_FLAGS) && !is_proc) + return -EINVAL; + if ((*mask & IATTR_XID) && !(in->i_sb->s_flags & MS_TAGXID)) + return -EINVAL; + + down(&in->i_sem); + if (*mask & IATTR_XID) + in->i_xid = *xid; + + if (*mask & IATTR_FLAGS) { + struct proc_dir_entry *entry = PROC_I(in)->pde; + unsigned int iflags = PROC_I(in)->vx_flags; + + iflags = (iflags & ~(*mask & IATTR_FLAGS)) + | (*flags & IATTR_FLAGS); + PROC_I(in)->vx_flags = iflags; + if (entry) + entry->vx_flags = iflags; + } + + if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) { + struct iattr attr; + + attr.ia_valid = ATTR_ATTR_FLAG; + attr.ia_attr_flags = + (IS_IMMUTABLE(in) ? ATTR_FLAG_IMMUTABLE : 0) | + (IS_IUNLINK(in) ? ATTR_FLAG_IUNLINK : 0) | + (IS_BARRIER(in) ? ATTR_FLAG_BARRIER : 0); + + if (*mask & IATTR_IMMUTABLE) { + if (*flags & IATTR_IMMUTABLE) + attr.ia_attr_flags |= ATTR_FLAG_IMMUTABLE; + else + attr.ia_attr_flags &= ~ATTR_FLAG_IMMUTABLE; + } + if (*mask & IATTR_IUNLINK) { + if (*flags & IATTR_IUNLINK) + attr.ia_attr_flags |= ATTR_FLAG_IUNLINK; + else + attr.ia_attr_flags &= ~ATTR_FLAG_IUNLINK; + } + if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) { + if (*flags & IATTR_BARRIER) + attr.ia_attr_flags |= ATTR_FLAG_BARRIER; + else + attr.ia_attr_flags &= ~ATTR_FLAG_BARRIER; + } + if (in->i_op && in->i_op->setattr) + error = in->i_op->setattr(de, &attr); + else { + error = inode_change_ok(in, &attr); + if (!error) + error = inode_setattr(in, &attr); + } + } + + mark_inode_dirty(in); + up(&in->i_sem); + return 0; +} + +int vc_set_iattr(uint32_t id, void __user *data) +{ + struct nameidata nd; + struct vcmd_ctx_iattr_v1 vc_data; + int ret; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_path_walk_link(vc_data.name, &nd); + if (!ret) { + ret = __vc_set_iattr(nd.dentry, + &vc_data.xid, &vc_data.flags, &vc_data.mask); + path_release(&nd); + } + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + + +#ifdef CONFIG_VSERVER_LEGACY +#include + +#define PROC_DYNAMIC_FIRST 0xF0000000UL + +int vx_proc_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + struct proc_dir_entry *entry; + int error = 0; + int flags; + + if (inode->i_ino < PROC_DYNAMIC_FIRST) + return -ENOTTY; + + entry = PROC_I(inode)->pde; + + switch(cmd) { + case FIOC_GETXFLG: { + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + flags = entry->vx_flags; + if (capable(CAP_CONTEXT)) + error = put_user(flags, (int *) arg); + break; + } + case FIOC_SETXFLG: { + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + if (!capable(CAP_CONTEXT)) + break; + error = -EROFS; + if (IS_RDONLY(inode)) + break; + error = -EFAULT; + if (get_user(flags, (int *) arg)) + break; + error = 0; + entry->vx_flags = flags; + break; + } + default: + return -ENOTTY; + } + return error; +} +#endif + diff --git a/kernel/vserver/legacy.c b/kernel/vserver/legacy.c new file mode 100644 index 000000000..0e78e5eac --- /dev/null +++ b/kernel/vserver/legacy.c @@ -0,0 +1,170 @@ +/* + * linux/kernel/vserver/legacy.c + * + * Virtual Server: Legacy Funtions + * + * Copyright (C) 2001-2003 Jacques Gelinas + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 broken out from vcontext.c V0.05 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +static int vx_set_initpid(struct vx_info *vxi, int pid) +{ + if (vxi->vx_initpid) + return -EPERM; + + vxi->vx_initpid = pid; + return 0; +} + +int vc_new_s_context(uint32_t ctx, void __user *data) +{ + int ret = -ENOMEM; + struct vcmd_new_s_context_v1 vc_data; + struct vx_info *new_vxi; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + /* legacy hack, will be removed soon */ + if (ctx == -2) { + /* assign flags and initpid */ + if (!current->vx_info) + return -EINVAL; + ret = 0; + if (vc_data.flags & VX_INFO_INIT) + ret = vx_set_initpid(current->vx_info, current->tgid); + if (ret == 0) { + /* We keep the same vx_id, but lower the capabilities */ + current->vx_info->vx_bcaps &= (~vc_data.remove_cap); + // current->cap_bset &= (~vc_data.remove_cap); + ret = vx_current_xid(); + current->vx_info->vx_flags |= vc_data.flags; + } + return ret; + } + + if (!vx_check(0, VX_ADMIN) || + !capable(CAP_SYS_ADMIN) || vx_flags(VX_INFO_LOCK, 0)) + return -EPERM; + + /* ugly hack for Spectator */ + if (ctx == 1) { + current->xid = 1; + return 0; + } + + if (((ctx > MAX_S_CONTEXT) && (ctx != VX_DYNAMIC_ID)) || + (ctx == 0)) + return -EINVAL; + + if ((ctx == VX_DYNAMIC_ID) || (ctx < MIN_D_CONTEXT)) + new_vxi = locate_or_create_vx_info(ctx); + else + new_vxi = locate_vx_info(ctx); + + if (!new_vxi) + return -EINVAL; + new_vxi->vx_flags &= ~(VXF_STATE_SETUP|VXF_STATE_INIT); + + ret = vx_migrate_task(current, new_vxi); + if (ret == 0) { + current->vx_info->vx_bcaps &= (~vc_data.remove_cap); + // current->cap_bset &= (~vc_data.remove_cap); + new_vxi->vx_flags |= vc_data.flags; + if (vc_data.flags & VX_INFO_INIT) + vx_set_initpid(new_vxi, current->tgid); + if (vc_data.flags & VX_INFO_NAMESPACE) + vx_set_namespace(new_vxi, + current->namespace, current->fs); + if (vc_data.flags & VX_INFO_NPROC) + new_vxi->limit.rlim[RLIMIT_NPROC] = + current->rlim[RLIMIT_NPROC].rlim_max; + ret = new_vxi->vx_id; + } + put_vx_info(new_vxi); + return ret; +} + + +extern struct nx_info *create_nx_info(void); + +/* set ipv4 root (syscall) */ + +int vc_set_ipv4root(uint32_t nbip, void __user *data) +{ + int i, err = -EPERM; + struct vcmd_set_ipv4root_v3 vc_data; + struct nx_info *new_nxi, *nxi = current->nx_info; + + if (nbip < 0 || nbip > NB_IPV4ROOT) + return -EINVAL; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if (!nxi || nxi->ipv4[0] == 0 || capable(CAP_NET_ADMIN)) + // We are allowed to change everything + err = 0; + else if (nxi) { + int found = 0; + + // We are allowed to select a subset of the currently + // installed IP numbers. No new one allowed + // We can't change the broadcast address though + for (i=0; inbipv4; j++) { + if (nxip == nxi->ipv4[j]) { + found++; + break; + } + } + } + if ((found == nbip) && + (vc_data.broadcast == nxi->v4_bcast)) + err = 0; + } + if (err) + return err; + + new_nxi = create_nx_info(); + if (!new_nxi) + return -EINVAL; + + new_nxi->nbipv4 = nbip; + for (i=0; iipv4[i] = vc_data.nx_mask_pair[i].ip; + new_nxi->mask[i] = vc_data.nx_mask_pair[i].mask; + } + new_nxi->v4_bcast = vc_data.broadcast; + // current->nx_info = new_nxi; + if (nxi) { + printk("!!! switching nx_info %p->%p\n", nxi, new_nxi); + clr_nx_info(¤t->nx_info); + } + nx_migrate_task(current, new_nxi); + // set_nx_info(¤t->nx_info, new_nxi); + // current->nid = new_nxi->nx_id; + put_nx_info(new_nxi); + return 0; +} + + diff --git a/kernel/vserver/limit.c b/kernel/vserver/limit.c new file mode 100644 index 000000000..94064117d --- /dev/null +++ b/kernel/vserver/limit.c @@ -0,0 +1,151 @@ +/* + * linux/kernel/vserver/limit.c + * + * Virtual Server: Context Limits + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static int is_valid_rlimit(int id) +{ + int valid = 0; + + switch (id) { + case RLIMIT_NPROC: + case RLIMIT_AS: + case RLIMIT_RSS: + case RLIMIT_MEMLOCK: + case RLIMIT_NOFILE: + valid = 1; + break; + } + return valid; +} + +static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id) +{ + unsigned long limit; + + limit = vxi->limit.rlim[id]; + if (limit == RLIM_INFINITY) + return CRLIM_INFINITY; + return limit; +} + +int vc_get_rlimit(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_rlimit_v0 vc_data; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + if (!is_valid_rlimit(vc_data.id)) + return -ENOTSUPP; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + vc_data.maximum = vc_get_rlim(vxi, vc_data.id); + vc_data.minimum = CRLIM_UNSET; + vc_data.softlimit = CRLIM_UNSET; + put_vx_info(vxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_rlimit(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_ctx_rlimit_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + if (!is_valid_rlimit(vc_data.id)) + return -ENOTSUPP; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + if (vc_data.maximum != CRLIM_KEEP) + vxi->limit.rlim[vc_data.id] = vc_data.maximum; + printk("setting [%d] = %d\n", vc_data.id, (int)vc_data.maximum); + put_vx_info(vxi); + + return 0; +} + +int vc_get_rlimit_mask(uint32_t id, void __user *data) +{ + static struct vcmd_ctx_rlimit_mask_v0 mask = { + /* minimum */ + 0 + , /* softlimit */ + 0 + , /* maximum */ + (1 << RLIMIT_NPROC) | + (1 << RLIMIT_NOFILE) | + (1 << RLIMIT_MEMLOCK) | + (1 << RLIMIT_AS) | + (1 << RLIMIT_RSS) + }; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) + return -EPERM; + if (copy_to_user(data, &mask, sizeof(mask))) + return -EFAULT; + return 0; +} + + +void vx_vsi_meminfo(struct sysinfo *val) +{ + struct vx_info *vxi = current->vx_info; + unsigned long v; + + v = vxi->limit.rlim[RLIMIT_RSS]; + if (v != RLIM_INFINITY) + val->totalram = min(val->totalram, v); + v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]); + val->freeram = (v < val->totalram) ? val->totalram - v : 0; + val->bufferram = 0; + val->totalhigh = 0; + val->freehigh = 0; + return; +} + +void vx_vsi_swapinfo(struct sysinfo *val) +{ + struct vx_info *vxi = current->vx_info; + unsigned long w,v; + + v = vxi->limit.rlim[RLIMIT_RSS]; + w = vxi->limit.rlim[RLIMIT_AS]; + if (w != RLIM_INFINITY) + val->totalswap = min(val->totalswap, w - + ((v != RLIM_INFINITY) ? v : 0)); + w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]); + val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0; + return; +} + diff --git a/kernel/vserver/namespace.c b/kernel/vserver/namespace.c new file mode 100644 index 000000000..3dc0f351c --- /dev/null +++ b/kernel/vserver/namespace.c @@ -0,0 +1,194 @@ +/* + * linux/kernel/vserver/namespace.c + * + * Virtual Server: Context Namespace Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 broken out from context.c 0.07 + * V0.02 added task locking for namespace + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* virtual host info names */ + +static char * vx_vhi_name(struct vx_info *vxi, int id) +{ + switch (id) { + case VHIN_CONTEXT: + return vxi->vx_name; + case VHIN_SYSNAME: + return vxi->cvirt.utsname.sysname; + case VHIN_NODENAME: + return vxi->cvirt.utsname.nodename; + case VHIN_RELEASE: + return vxi->cvirt.utsname.release; + case VHIN_VERSION: + return vxi->cvirt.utsname.version; + case VHIN_MACHINE: + return vxi->cvirt.utsname.machine; + case VHIN_DOMAINNAME: + return vxi->cvirt.utsname.domainname; + default: + return NULL; + } + return NULL; +} + +int vc_set_vhi_name(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_vx_vhi_name_v0 vc_data; + char *name; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + name = vx_vhi_name(vxi, vc_data.field); + if (name) + memcpy(name, vc_data.name, 65); + put_vx_info(vxi); + return (name ? 0 : -EFAULT); +} + +int vc_get_vhi_name(uint32_t id, void __user *data) +{ + struct vx_info *vxi; + struct vcmd_vx_vhi_name_v0 vc_data; + char *name; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + name = vx_vhi_name(vxi, vc_data.field); + if (!name) + goto out_put; + + memcpy(vc_data.name, name, 65); + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; +out_put: + put_vx_info(vxi); + return (name ? 0 : -EFAULT); +} + +/* namespace functions */ + +#include + +int vx_set_namespace(struct vx_info *vxi, struct namespace *ns, struct fs_struct *fs) +{ + struct fs_struct *fs_copy; + + if (vxi->vx_namespace) + return -EPERM; + if (!ns || !fs) + return -EINVAL; + + fs_copy = copy_fs_struct(fs); + if (!fs_copy) + return -ENOMEM; + + get_namespace(ns); + vxi->vx_namespace = ns; + vxi->vx_fs = fs_copy; + return 0; +} + +int vc_enter_namespace(uint32_t id, void *data) +{ + struct vx_info *vxi; + struct fs_struct *old_fs, *fs; + struct namespace *old_ns; + int ret = 0; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + ret = -EINVAL; + if (!vxi->vx_namespace) + goto out_put; + + ret = -ENOMEM; + fs = copy_fs_struct(vxi->vx_fs); + if (!fs) + goto out_put; + + ret = 0; + task_lock(current); + old_ns = current->namespace; + old_fs = current->fs; + get_namespace(vxi->vx_namespace); + current->namespace = vxi->vx_namespace; + current->fs = fs; + task_unlock(current); + + put_namespace(old_ns); + put_fs_struct(old_fs); +out_put: + put_vx_info(vxi); + return ret; +} + +int vc_cleanup_namespace(uint32_t id, void *data) +{ + down_write(¤t->namespace->sem); + spin_lock(&vfsmount_lock); + umount_unused(current->namespace->root, current->fs); + spin_unlock(&vfsmount_lock); + up_write(¤t->namespace->sem); + return 0; +} + +int vc_set_namespace(uint32_t id, void __user *data) +{ + struct fs_struct *fs; + struct namespace *ns; + struct vx_info *vxi; + int ret; + + if (vx_check(0, VX_ADMIN|VX_WATCH)) + return -ENOSYS; + + task_lock(current); + vxi = get_vx_info(current->vx_info); + fs = current->fs; + atomic_inc(&fs->count); + ns = current->namespace; + get_namespace(current->namespace); + task_unlock(current); + + ret = vx_set_namespace(vxi, ns, fs); + + put_namespace(ns); + put_fs_struct(fs); + put_vx_info(vxi); + return ret; +} + diff --git a/kernel/vserver/network.c b/kernel/vserver/network.c new file mode 100644 index 000000000..b9b9327e8 --- /dev/null +++ b/kernel/vserver/network.c @@ -0,0 +1,649 @@ +/* + * linux/kernel/vserver/network.c + * + * Virtual Server: Network Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * V0.02 cleaned up implementation + * V0.03 added equiv nx commands + * V0.04 switch to RCU based hash + * + */ + +#include +#include +#include +#include +#include +#include + +#include + + +/* __alloc_nx_info() + + * allocate an initialized nx_info struct + * doesn't make it visible (hash) */ + +static struct nx_info *__alloc_nx_info(nid_t nid) +{ + struct nx_info *new = NULL; + + nxdprintk("alloc_nx_info()\n"); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct nx_info), GFP_KERNEL); + if (!new) + return 0; + + memset (new, 0, sizeof(struct nx_info)); + new->nx_id = nid; + INIT_RCU_HEAD(&new->nx_rcu); + INIT_HLIST_NODE(&new->nx_hlist); + atomic_set(&new->nx_refcnt, 0); + atomic_set(&new->nx_usecnt, 0); + + /* rest of init goes here */ + + nxdprintk("alloc_nx_info() = %p\n", new); + return new; +} + +/* __dealloc_nx_info() + + * final disposal of nx_info */ + +static void __dealloc_nx_info(struct nx_info *nxi) +{ + nxdprintk("dealloc_nx_info(%p)\n", nxi); + + nxi->nx_hlist.next = LIST_POISON1; + nxi->nx_id = -1; + + BUG_ON(atomic_read(&nxi->nx_usecnt)); + BUG_ON(atomic_read(&nxi->nx_refcnt)); + + kfree(nxi); +} + + +/* hash table for nx_info hash */ + +#define NX_HASH_SIZE 13 + +struct hlist_head nx_info_hash[NX_HASH_SIZE]; + +static spinlock_t nx_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(nid_t nid) +{ + return (nid % NX_HASH_SIZE); +} + + + +/* __hash_nx_info() + + * add the nxi to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_nx_info(struct nx_info *nxi) +{ + struct hlist_head *head; + + nxdprintk("__hash_nx_info: %p[#%d]\n", nxi, nxi->nx_id); + get_nx_info(nxi); + head = &nx_info_hash[__hashval(nxi->nx_id)]; + hlist_add_head_rcu(&nxi->nx_hlist, head); +} + +/* __unhash_nx_info() + + * remove the nxi from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_nx_info(struct nx_info *nxi) +{ + nxdprintk("__unhash_nx_info: %p[#%d]\n", nxi, nxi->nx_id); + hlist_del_rcu(&nxi->nx_hlist); + put_nx_info(nxi); +} + + +/* __lookup_nx_info() + + * requires the rcu_read_lock() + * doesn't increment the nx_refcnt */ + +static inline struct nx_info *__lookup_nx_info(nid_t nid) +{ + struct hlist_head *head = &nx_info_hash[__hashval(nid)]; + struct hlist_node *pos; + + hlist_for_each_rcu(pos, head) { + struct nx_info *nxi = + hlist_entry(pos, struct nx_info, nx_hlist); + + if (nxi->nx_id == nid) { + return nxi; + } + } + return NULL; +} + + +/* __nx_dynamic_id() + + * find unused dynamic nid + * requires the hash_lock to be held */ + +static inline nid_t __nx_dynamic_id(void) +{ + static nid_t seq = MAX_N_CONTEXT; + nid_t barrier = seq; + + do { + if (++seq > MAX_N_CONTEXT) + seq = MIN_D_CONTEXT; + if (!__lookup_nx_info(seq)) + return seq; + } while (barrier != seq); + return 0; +} + +/* __loc_nx_info() + + * locate or create the requested context + * get() it and if new hash it */ + +static struct nx_info * __loc_nx_info(int id, int *err) +{ + struct nx_info *new, *nxi = NULL; + + nxdprintk("loc_nx_info(%d)\n", id); + + if (!(new = __alloc_nx_info(id))) { + *err = -ENOMEM; + return NULL; + } + + spin_lock(&nx_info_hash_lock); + + /* dynamic context requested */ + if (id == NX_DYNAMIC_ID) { + id = __nx_dynamic_id(); + if (!id) { + printk(KERN_ERR "no dynamic context available.\n"); + goto out_unlock; + } + new->nx_id = id; + } + /* existing context requested */ + else if ((nxi = __lookup_nx_info(id))) { + /* context in setup is not available */ + if (nxi->nx_flags & VXF_STATE_SETUP) { + nxdprintk("loc_nx_info(%d) = %p (not available)\n", id, nxi); + nxi = NULL; + *err = -EBUSY; + } else { + nxdprintk("loc_nx_info(%d) = %p (found)\n", id, nxi); + get_nx_info(nxi); + *err = 0; + } + goto out_unlock; + } + + /* new context requested */ + nxdprintk("loc_nx_info(%d) = %p (new)\n", id, new); + __hash_nx_info(get_nx_info(new)); + nxi = new, new = NULL; + *err = 1; + +out_unlock: + spin_unlock(&nx_info_hash_lock); + if (new) + __dealloc_nx_info(new); + return nxi; +} + + + +/* exported stuff */ + + + + +void rcu_free_nx_info(void *obj) +{ + struct nx_info *nxi = obj; + int usecnt, refcnt; + + usecnt = atomic_read(&nxi->nx_usecnt); + BUG_ON(usecnt < 0); + + refcnt = atomic_read(&nxi->nx_refcnt); + BUG_ON(refcnt < 0); + + if (!usecnt) + __dealloc_nx_info(nxi); + else + printk("!!! rcu didn't free\n"); +} + +void unhash_nx_info(struct nx_info *nxi) +{ + spin_lock(&nx_info_hash_lock); + __unhash_nx_info(nxi); + spin_unlock(&nx_info_hash_lock); +} + +/* locate_nx_info() + + * search for a nx_info and get() it + * negative id means current */ + +struct nx_info *locate_nx_info(int id) +{ + struct nx_info *nxi; + + if (id < 0) { + nxi = get_nx_info(current->nx_info); + } else { + rcu_read_lock(); + nxi = get_nx_info(__lookup_nx_info(id)); + rcu_read_unlock(); + } + return nxi; +} + +/* nx_info_is_hashed() + + * verify that nid is still hashed */ + +int nx_info_is_hashed(nid_t nid) +{ + int hashed; + + rcu_read_lock(); + hashed = (__lookup_nx_info(nid) != NULL); + rcu_read_unlock(); + return hashed; +} + +#ifdef CONFIG_VSERVER_LEGACY + +struct nx_info *locate_or_create_nx_info(int id) +{ + int err; + + return __loc_nx_info(id, &err); +} + +struct nx_info *create_nx_info(void) +{ + struct nx_info *new; + int err; + + nxdprintk("create_nx_info()\n"); + if (!(new = __loc_nx_info(NX_DYNAMIC_ID, &err))) + return NULL; + return new; +} + + +#endif + +#ifdef CONFIG_PROC_FS + +#define hlist_for_each_rcu(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +int get_nid_list(int index, unsigned int *nids, int size) +{ + int hindex, nr_nids = 0; + + rcu_read_lock(); + for (hindex = 0; hindex < NX_HASH_SIZE; hindex++) { + struct hlist_head *head = &nx_info_hash[hindex]; + struct hlist_node *pos; + + hlist_for_each_rcu(pos, head) { + struct nx_info *nxi; + + if (--index > 0) + continue; + + nxi = hlist_entry(pos, struct nx_info, nx_hlist); + nids[nr_nids] = nxi->nx_id; + if (++nr_nids >= size) + goto out; + } + } +out: + rcu_read_unlock(); + return nr_nids; +} +#endif + + +/* + * migrate task to new network + */ + +int nx_migrate_task(struct task_struct *p, struct nx_info *nxi) +{ + struct nx_info *old_nxi; + int ret = 0; + + if (!p || !nxi) + BUG(); + + nxdprintk("nx_migrate_task(%p,%p[#%d.%d.%d])\n", + p, nxi, nxi->nx_id, + atomic_read(&nxi->nx_usecnt), + atomic_read(&nxi->nx_refcnt)); + + old_nxi = task_get_nx_info(p); + if (old_nxi == nxi) + goto out; + + task_lock(p); + /* should be handled in set_nx_info !! */ + if (old_nxi) + clr_nx_info(&p->nx_info); + set_nx_info(&p->nx_info, nxi); + p->nid = nxi->nx_id; + task_unlock(p); + + /* obsoleted by clr/set */ + // put_nx_info(old_nxi); +out: + put_nx_info(old_nxi); + return ret; +} + + +#include +#include + +static inline int __addr_in_nx_info(u32 addr, struct nx_info *nxi) +{ + int i, nbip; + + nbip = nxi->nbipv4; + for (i=0; iipv4[i] == addr) + return 1; + return 0; +} + +int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) +{ + if (nxi && ifa) + return __addr_in_nx_info(ifa->ifa_address, nxi); + return 1; +} + +int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) +{ + struct in_device *in_dev = __in_dev_get(dev); + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + + if (!nxi) + return 1; + if (!in_dev) + return 0; + + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (__addr_in_nx_info(ifa->ifa_address, nxi)) + return 1; + } + return 0; +} + + + + +/* vserver syscall commands below here */ + +/* taks nid and nx_info functions */ + +#include + + +int vc_task_nid(uint32_t id, void __user *data) +{ + nid_t nid; + + if (id) { + struct task_struct *tsk; + + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + return -EPERM; + + read_lock(&tasklist_lock); + tsk = find_task_by_pid(id); + nid = (tsk) ? tsk->nid : -ESRCH; + read_unlock(&tasklist_lock); + } + else + nid = current->nid; + return nid; +} + + +int vc_nx_info(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_nx_info_v0 vc_data; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + vc_data.nid = nxi->nx_id; + put_nx_info(nxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +/* network functions */ + +int vc_net_create(uint32_t nid, void __user *data) +{ + // int ret = -ENOMEM; + struct nx_info *new_nxi; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if ((nid >= MIN_D_CONTEXT) && (nid != VX_DYNAMIC_ID)) + return -EINVAL; + + if (nid < 1) + return -EINVAL; + + new_nxi = __loc_nx_info(nid, &ret); + if (!new_nxi) + return ret; + if (!(new_nxi->nx_flags & VXF_STATE_SETUP)) { + ret = -EEXIST; + goto out_put; + } + + ret = new_nxi->nx_id; + nx_migrate_task(current, new_nxi); +out_put: + put_nx_info(new_nxi); + return ret; +} + + +int vc_net_migrate(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + nx_migrate_task(current, nxi); + put_nx_info(nxi); + return 0; +} + +int vc_net_add(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_nx_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + // add ip to net context here + put_nx_info(nxi); + return 0; +} + +int vc_net_remove(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_nx_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + // rem ip from net context here + put_nx_info(nxi); + return 0; +} + + + +int vc_get_nflags(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_flags_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + vc_data.flagword = nxi->nx_flags; + + /* special STATE flag handling */ + vc_data.mask = vx_mask_flags(~0UL, nxi->nx_flags, IPF_ONE_TIME); + + put_nx_info(nxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_nflags(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_flags_v0 vc_data; + uint64_t mask, trigger; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + /* special STATE flag handling */ + mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, IPF_ONE_TIME); + trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword); + // if (trigger & IPF_STATE_SETUP) + + nxi->nx_flags = vx_mask_flags(nxi->nx_flags, + vc_data.flagword, mask); + put_nx_info(nxi); + return 0; +} + +int vc_get_ncaps(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_caps_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + vc_data.ncaps = nxi->nx_ncaps; + vc_data.cmask = ~0UL; + put_nx_info(nxi); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_ncaps(uint32_t id, void __user *data) +{ + struct nx_info *nxi; + struct vcmd_net_caps_v0 vc_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + nxi = locate_nx_info(id); + if (!nxi) + return -ESRCH; + + nxi->nx_ncaps = vx_mask_flags(nxi->nx_ncaps, + vc_data.ncaps, vc_data.cmask); + put_nx_info(nxi); + return 0; +} + + +#include + +EXPORT_SYMBOL_GPL(rcu_free_nx_info); +EXPORT_SYMBOL_GPL(nx_info_hash_lock); +EXPORT_SYMBOL_GPL(unhash_nx_info); + diff --git a/kernel/vserver/proc.c b/kernel/vserver/proc.c new file mode 100644 index 000000000..e957fd43b --- /dev/null +++ b/kernel/vserver/proc.c @@ -0,0 +1,868 @@ +/* + * linux/kernel/vserver/proc.c + * + * Virtual Context Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 basic structure + * V0.02 adaptation vs1.3.0 + * V0.03 proc permissions + * V0.04 locking/generic + * V0.05 next generation procfs + * V0.06 inode validation + * V0.07 generic rewrite vid + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static struct proc_dir_entry *proc_virtual; + +static struct proc_dir_entry *proc_vnet; + + +enum vid_directory_inos { + PROC_XID_INO = 32, + PROC_XID_INFO, + PROC_XID_STATUS, + PROC_XID_LIMIT, + PROC_XID_SCHED, + PROC_XID_CVIRT, + PROC_XID_CACCT, + + PROC_NID_INO = 64, + PROC_NID_INFO, + PROC_NID_STATUS, +}; + +#define PROC_VID_MASK 0x60 + + +/* first the actual feeds */ + + +static int proc_virtual_info(int vid, char *buffer) +{ + return sprintf(buffer, + "VCIVersion:\t%04x:%04x\n" + "VCISyscall:\t%d\n" + ,VCI_VERSION >> 16 + ,VCI_VERSION & 0xFFFF + ,__NR_vserver + ); +} + + +int proc_xid_info (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = sprintf(buffer, + "ID:\t%d\n" + "Info:\t%p\n" + "Init:\t%d\n" + ,vxi->vx_id + ,vxi + ,vxi->vx_initpid + ); + put_vx_info(vxi); + return length; +} + +int proc_xid_status (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = sprintf(buffer, + "UseCnt:\t%d\n" + "RefCnt:\t%d\n" + "Flags:\t%016llx\n" + "BCaps:\t%016llx\n" + "CCaps:\t%016llx\n" + "Ticks:\t%d\n" + ,atomic_read(&vxi->vx_usecnt) + ,atomic_read(&vxi->vx_refcnt) + ,(unsigned long long)vxi->vx_flags + ,(unsigned long long)vxi->vx_bcaps + ,(unsigned long long)vxi->vx_ccaps + ,atomic_read(&vxi->limit.ticks) + ); + put_vx_info(vxi); + return length; +} + +int proc_xid_limit (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = vx_info_proc_limit(&vxi->limit, buffer); + put_vx_info(vxi); + return length; +} + +int proc_xid_sched (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = vx_info_proc_sched(&vxi->sched, buffer); + put_vx_info(vxi); + return length; +} + +int proc_xid_cvirt (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = vx_info_proc_cvirt(&vxi->cvirt, buffer); + put_vx_info(vxi); + return length; +} + +int proc_xid_cacct (int vid, char *buffer) +{ + struct vx_info *vxi; + int length; + + vxi = locate_vx_info(vid); + if (!vxi) + return 0; + length = vx_info_proc_cacct(&vxi->cacct, buffer); + put_vx_info(vxi); + return length; +} + + +static int proc_vnet_info(int vid, char *buffer) +{ + return sprintf(buffer, + "VCIVersion:\t%04x:%04x\n" + "VCISyscall:\t%d\n" + ,VCI_VERSION >> 16 + ,VCI_VERSION & 0xFFFF + ,__NR_vserver + ); +} + +#define atoquad(a) \ + (((a)>>0) & 0xff), (((a)>>8) & 0xff), \ + (((a)>>16) & 0xff), (((a)>>24) & 0xff) + +int proc_nid_info (int vid, char *buffer) +{ + struct nx_info *nxi; + int length, i; + + nxi = locate_nx_info(vid); + if (!nxi) + return 0; + length = sprintf(buffer, + "ID:\t%d\n" + "Info:\t%p\n" + ,nxi->nx_id + ,nxi + ); + for (i=0; inbipv4; i++) { + length += sprintf(buffer + length, + "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i, + atoquad(nxi->ipv4[i]), + atoquad(nxi->mask[i])); + } + put_nx_info(nxi); + return length; +} + +int proc_nid_status (int vid, char *buffer) +{ + struct nx_info *nxi; + int length; + + nxi = locate_nx_info(vid); + if (!nxi) + return 0; + length = sprintf(buffer, + "UseCnt:\t%d\n" + "RefCnt:\t%d\n" + ,atomic_read(&nxi->nx_usecnt) + ,atomic_read(&nxi->nx_refcnt) + ); + put_nx_info(nxi); + return length; +} + +/* here the inode helpers */ + + + +#define fake_ino(id,ino) (((id)<<16)|(ino)) + +#define inode_vid(i) ((i)->i_ino >> 16) +#define inode_type(i) ((i)->i_ino & 0xFFFF) + +#define MAX_MULBY10 ((~0U-9)/10) + + +static struct inode *proc_vid_make_inode(struct super_block * sb, + int vid, int ino) +{ + struct inode *inode = new_inode(sb); + + if (!inode) + goto out; + + inode->i_mtime = inode->i_atime = + inode->i_ctime = CURRENT_TIME; + inode->i_ino = fake_ino(vid, ino); + + inode->i_uid = 0; + inode->i_gid = 0; + // inode->i_xid = xid; +out: + return inode; +} + +static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd) +{ + struct inode * inode = dentry->d_inode; + int vid, hashed=0; + + vid = inode_vid(inode); + switch (inode_type(inode) & PROC_VID_MASK) { + case PROC_XID_INO: + hashed = vx_info_is_hashed(vid); + break; + case PROC_NID_INO: + hashed = nx_info_is_hashed(vid); + break; + } + if (hashed) + return 1; + d_drop(dentry); + return 0; +} + +/* +static int proc_vid_delete_dentry(struct dentry * dentry) +{ + return 1; +} +*/ + + +#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) + +static ssize_t proc_vid_info_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = file->f_dentry->d_inode; + unsigned long page; + ssize_t length; + ssize_t end; + int vid; + + if (count > PROC_BLOCK_SIZE) + count = PROC_BLOCK_SIZE; + if (!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + vid = inode_vid(inode); + length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page); + + if (length < 0) { + free_page(page); + return length; + } + /* Static 4kB (or whatever) block capacity */ + if (*ppos >= length) { + free_page(page); + return 0; + } + if (count + *ppos > length) + count = length - *ppos; + end = count + *ppos; + copy_to_user(buf, (char *) page + *ppos, count); + *ppos = end; + free_page(page); + return count; +} + + + + + +/* here comes the lower level (vid) */ + +static struct file_operations proc_vid_info_file_operations = { + read: proc_vid_info_read, +}; + +static struct dentry_operations proc_vid_dentry_operations = { + d_revalidate: proc_vid_revalidate, +// d_delete: proc_vid_delete_dentry, +}; + + +struct vid_entry { + int type; + int len; + char *name; + mode_t mode; +}; + +#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)} + +static struct vid_entry vx_base_stuff[] = { + E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO), + E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO), + E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO), + E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO), + E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO), + E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO), + {0,0,NULL,0} +}; + +static struct vid_entry vn_base_stuff[] = { + E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO), + E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO), + {0,0,NULL,0} +}; + + + +static struct dentry *proc_vid_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode; + struct vid_entry *p; + int error; + + error = -ENOENT; + inode = NULL; + + switch (inode_type(dir)) { + case PROC_XID_INO: + p = vx_base_stuff; + break; + case PROC_NID_INO: + p = vn_base_stuff; + break; + default: + goto out; + } + + for (; p->name; p++) { + if (p->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, p->name, p->len)) + break; + } + if (!p->name) + goto out; + + error = -EINVAL; + inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type); + if (!inode) + goto out; + + switch(p->type) { + case PROC_XID_INFO: + PROC_I(inode)->op.proc_vid_read = proc_xid_info; + break; + case PROC_XID_STATUS: + PROC_I(inode)->op.proc_vid_read = proc_xid_status; + break; + case PROC_XID_LIMIT: + PROC_I(inode)->op.proc_vid_read = proc_xid_limit; + break; + case PROC_XID_SCHED: + PROC_I(inode)->op.proc_vid_read = proc_xid_sched; + break; + case PROC_XID_CVIRT: + PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt; + break; + case PROC_XID_CACCT: + PROC_I(inode)->op.proc_vid_read = proc_xid_cacct; + break; + + case PROC_NID_INFO: + PROC_I(inode)->op.proc_vid_read = proc_nid_info; + break; + case PROC_NID_STATUS: + PROC_I(inode)->op.proc_vid_read = proc_nid_status; + break; + + default: + printk("procfs: impossible type (%d)",p->type); + iput(inode); + return ERR_PTR(-EINVAL); + } + inode->i_mode = p->mode; +// inode->i_op = &proc_vid_info_inode_operations; + inode->i_fop = &proc_vid_info_file_operations; + inode->i_nlink = 1; + inode->i_flags|=S_IMMUTABLE; + + dentry->d_op = &proc_vid_dentry_operations; + d_add(dentry, inode); + error = 0; +out: + return ERR_PTR(error); +} + + +static int proc_vid_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + int i, size; + struct inode *inode = filp->f_dentry->d_inode; + struct vid_entry *p; + + i = filp->f_pos; + switch (i) { + case 0: + if (filldir(dirent, ".", 1, i, + inode->i_ino, DT_DIR) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, i, + PROC_ROOT_INO, DT_DIR) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + default: + i -= 2; + switch (inode_type(inode)) { + case PROC_XID_INO: + size = sizeof(vx_base_stuff); + p = vx_base_stuff + i; + break; + case PROC_NID_INO: + size = sizeof(vn_base_stuff); + p = vn_base_stuff + i; + break; + default: + return 1; + } + if (i >= size/sizeof(struct vid_entry)) + return 1; + while (p->name) { + if (filldir(dirent, p->name, p->len, + filp->f_pos, fake_ino(inode_vid(inode), + p->type), p->mode >> 12) < 0) + return 0; + filp->f_pos++; + p++; + } + } + return 1; +} + + + + +/* now the upper level (virtual) */ + +static struct file_operations proc_vid_file_operations = { + read: generic_read_dir, + readdir: proc_vid_readdir, +}; + +static struct inode_operations proc_vid_inode_operations = { + lookup: proc_vid_lookup, +}; + + + +static __inline__ int atovid(const char *str, int len) +{ + int vid, c; + + vid = 0; + while (len-- > 0) { + c = *str - '0'; + str++; + if (c > 9) + return -1; + if (vid >= MAX_MULBY10) + return -1; + vid *= 10; + vid += c; + if (!vid) + return -1; + } + return vid; +} + + +struct dentry *proc_virtual_lookup(struct inode *dir, + struct dentry * dentry, struct nameidata *nd) +{ + int xid, len, ret; + struct vx_info *vxi; + const char *name; + struct inode *inode; + + name = dentry->d_name.name; + len = dentry->d_name.len; + ret = -ENOMEM; + + if (len == 7 && !memcmp(name, "current", 7)) { + inode = new_inode(dir->i_sb); + if (!inode) + goto out; + inode->i_mtime = inode->i_atime = + inode->i_ctime = CURRENT_TIME; + inode->i_ino = fake_ino(1, PROC_XID_INO); + inode->i_mode = S_IFLNK|S_IRWXUGO; + inode->i_uid = inode->i_gid = 0; + inode->i_size = 64; +// inode->i_op = &proc_current_inode_operations; + d_add(dentry, inode); + return NULL; + } + if (len == 4 && !memcmp(name, "info", 4)) { + inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO); + if (!inode) + goto out; + inode->i_fop = &proc_vid_info_file_operations; + PROC_I(inode)->op.proc_vid_read = proc_virtual_info; + inode->i_mode = S_IFREG|S_IRUGO; +// inode->i_size = 64; +// inode->i_op = &proc_current_inode_operations; + d_add(dentry, inode); + return NULL; + } + + ret = -ENOENT; + xid = atovid(name, len); + if (xid < 0) + goto out; + vxi = locate_vx_info(xid); + if (!vxi) + goto out; + + inode = NULL; + if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT)) + inode = proc_vid_make_inode(dir->i_sb, + vxi->vx_id, PROC_XID_INO); + if (!inode) + goto out_release; + + inode->i_mode = S_IFDIR|S_IRUGO; + inode->i_op = &proc_vid_inode_operations; + inode->i_fop = &proc_vid_file_operations; + inode->i_nlink = 2; + inode->i_flags|=S_IMMUTABLE; + + dentry->d_op = &proc_vid_dentry_operations; + d_add(dentry, inode); + ret = 0; + +out_release: + put_vx_info(vxi); +out: + return ERR_PTR(ret); +} + + +struct dentry *proc_vnet_lookup(struct inode *dir, + struct dentry * dentry, struct nameidata *nd) +{ + int nid, len, ret; + struct nx_info *nxi; + const char *name; + struct inode *inode; + + name = dentry->d_name.name; + len = dentry->d_name.len; + ret = -ENOMEM; + if (len == 7 && !memcmp(name, "current", 7)) { + inode = new_inode(dir->i_sb); + if (!inode) + goto out; + inode->i_mtime = inode->i_atime = + inode->i_ctime = CURRENT_TIME; + inode->i_ino = fake_ino(1, PROC_NID_INO); + inode->i_mode = S_IFLNK|S_IRWXUGO; + inode->i_uid = inode->i_gid = 0; + inode->i_size = 64; +// inode->i_op = &proc_current_inode_operations; + d_add(dentry, inode); + return NULL; + } + if (len == 4 && !memcmp(name, "info", 4)) { + inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO); + if (!inode) + goto out; + inode->i_fop = &proc_vid_info_file_operations; + PROC_I(inode)->op.proc_vid_read = proc_vnet_info; + inode->i_mode = S_IFREG|S_IRUGO; +// inode->i_size = 64; +// inode->i_op = &proc_current_inode_operations; + d_add(dentry, inode); + return NULL; + } + + ret = -ENOENT; + nid = atovid(name, len); + if (nid < 0) + goto out; + nxi = locate_nx_info(nid); + if (!nxi) + goto out; + + inode = NULL; + if (1) + inode = proc_vid_make_inode(dir->i_sb, + nxi->nx_id, PROC_NID_INO); + if (!inode) + goto out_release; + + inode->i_mode = S_IFDIR|S_IRUGO; + inode->i_op = &proc_vid_inode_operations; + inode->i_fop = &proc_vid_file_operations; + inode->i_nlink = 2; + inode->i_flags|=S_IMMUTABLE; + + dentry->d_op = &proc_vid_dentry_operations; + d_add(dentry, inode); + ret = 0; + +out_release: + put_nx_info(nxi); +out: + return ERR_PTR(ret); +} + + + + +#define PROC_NUMBUF 10 +#define PROC_MAXVIDS 32 + +int proc_virtual_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + unsigned int xid_array[PROC_MAXVIDS]; + char buf[PROC_NUMBUF]; + unsigned int nr = filp->f_pos-3; + unsigned int nr_xids, i; + ino_t ino; + + switch ((long)filp->f_pos) { + case 0: + ino = fake_ino(0, PROC_XID_INO); + if (filldir(dirent, ".", 1, + filp->f_pos, ino, DT_DIR) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 1: + ino = filp->f_dentry->d_parent->d_inode->i_ino; + if (filldir(dirent, "..", 2, + filp->f_pos, ino, DT_DIR) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 2: + ino = fake_ino(0, PROC_XID_INFO); + if (filldir(dirent, "info", 4, + filp->f_pos, ino, DT_LNK) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 3: + if (current->xid > 1) { + ino = fake_ino(1, PROC_XID_INO); + if (filldir(dirent, "current", 7, + filp->f_pos, ino, DT_LNK) < 0) + return 0; + } + filp->f_pos++; + } + + nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS); + for (i = 0; i < nr_xids; i++) { + int xid = xid_array[i]; + ino_t ino = fake_ino(xid, PROC_XID_INO); + unsigned int j = PROC_NUMBUF; + + do buf[--j] = '0' + (xid % 10); while (xid/=10); + + if (filldir(dirent, buf+j, PROC_NUMBUF-j, + filp->f_pos, ino, DT_DIR) < 0) + break; + filp->f_pos++; + } + return 0; +} + + +static struct file_operations proc_virtual_dir_operations = { + read: generic_read_dir, + readdir: proc_virtual_readdir, +}; + +static struct inode_operations proc_virtual_dir_inode_operations = { + lookup: proc_virtual_lookup, +}; + + +int proc_vnet_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + unsigned int nid_array[PROC_MAXVIDS]; + char buf[PROC_NUMBUF]; + unsigned int nr = filp->f_pos-3; + unsigned int nr_nids, i; + ino_t ino; + + switch ((long)filp->f_pos) { + case 0: + ino = fake_ino(0, PROC_NID_INO); + if (filldir(dirent, ".", 1, + filp->f_pos, ino, DT_DIR) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 1: + ino = filp->f_dentry->d_parent->d_inode->i_ino; + if (filldir(dirent, "..", 2, + filp->f_pos, ino, DT_DIR) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 2: + ino = fake_ino(0, PROC_NID_INFO); + if (filldir(dirent, "info", 4, + filp->f_pos, ino, DT_LNK) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 3: + if (current->xid > 1) { + ino = fake_ino(1, PROC_NID_INO); + if (filldir(dirent, "current", 7, + filp->f_pos, ino, DT_LNK) < 0) + return 0; + } + filp->f_pos++; + } + + nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS); + for (i = 0; i < nr_nids; i++) { + int nid = nid_array[i]; + ino_t ino = fake_ino(nid, PROC_NID_INO); + unsigned long j = PROC_NUMBUF; + + do buf[--j] = '0' + (nid % 10); while (nid/=10); + + if (filldir(dirent, buf+j, PROC_NUMBUF-j, + filp->f_pos, ino, DT_DIR) < 0) + break; + filp->f_pos++; + } + return 0; +} + + +static struct file_operations proc_vnet_dir_operations = { + read: generic_read_dir, + readdir: proc_vnet_readdir, +}; + +static struct inode_operations proc_vnet_dir_inode_operations = { + lookup: proc_vnet_lookup, +}; + + + +void proc_vx_init(void) +{ + struct proc_dir_entry *ent; + + ent = proc_mkdir("virtual", 0); + if (ent) { + ent->proc_fops = &proc_virtual_dir_operations; + ent->proc_iops = &proc_virtual_dir_inode_operations; + } + proc_virtual = ent; + + ent = proc_mkdir("vnet", 0); + if (ent) { + ent->proc_fops = &proc_vnet_dir_operations; + ent->proc_iops = &proc_vnet_dir_inode_operations; + } + proc_vnet = ent; +} + + + + +/* per pid info */ + + +char *task_vx_info(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, + "XID:\t%d\n" + ,p->xid); +} + +int proc_pid_vx_info(struct task_struct *p, char *buffer) +{ + char * orig = buffer; + + buffer = task_vx_info(p, buffer); + return buffer - orig; +} + +char *task_nx_info(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, + "NID:\t%d\n" + ,p->nid); +} + +int proc_pid_nx_info(struct task_struct *p, char *buffer) +{ + char * orig = buffer; + + buffer = task_nx_info(p, buffer); + return buffer - orig; +} + diff --git a/kernel/vserver/sched.c b/kernel/vserver/sched.c new file mode 100644 index 000000000..b2d45c23f --- /dev/null +++ b/kernel/vserver/sched.c @@ -0,0 +1,163 @@ +/* + * linux/kernel/vserver/sched.c + * + * Virtual Server: Scheduler Support + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 adapted Sam Vilains version to 2.6.3 + * V0.02 removed legacy interface + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * recalculate the context's scheduling tokens + * + * ret > 0 : number of tokens available + * ret = 0 : context is paused + * ret < 0 : number of jiffies until new tokens arrive + * + */ +int vx_tokens_recalc(struct vx_info *vxi) +{ + long delta, tokens = 0; + + if (__vx_flags(vxi->vx_flags, VXF_SCHED_PAUSE, 0)) + /* we are paused */ + return 0; + + delta = jiffies - vxi->sched.jiffies; + + if (delta >= vxi->sched.interval) { + /* lockdown scheduler info */ + spin_lock(&vxi->sched.tokens_lock); + + /* calc integral token part */ + delta = jiffies - vxi->sched.jiffies; + tokens = delta / vxi->sched.interval; + delta = tokens * vxi->sched.interval; + tokens *= vxi->sched.fill_rate; + + atomic_add(tokens, &vxi->sched.tokens); + vxi->sched.jiffies += delta; + tokens = atomic_read(&vxi->sched.tokens); + + if (tokens > vxi->sched.tokens_max) { + tokens = vxi->sched.tokens_max; + atomic_set(&vxi->sched.tokens, tokens); + } + spin_unlock(&vxi->sched.tokens_lock); + } else { + /* no new tokens */ + if ((tokens = vx_tokens_avail(vxi)) < vxi->sched.tokens_min) { + /* enough tokens will be available in */ + if (vxi->sched.tokens_min == 0) + return delta - vxi->sched.interval; + return delta - vxi->sched.interval * + vxi->sched.tokens_min / vxi->sched.fill_rate; + } + } + /* we have some tokens left */ + return tokens; +} + +/* + * effective_prio - return the priority that is based on the static + * priority but is modified by bonuses/penalties. + * + * We scale the actual sleep average [0 .... MAX_SLEEP_AVG] + * into a -4 ... 0 ... +4 bonus/penalty range. + * + * Additionally, we scale another amount based on the number of + * CPU tokens currently held by the context, if the process is + * part of a context (and the appropriate SCHED flag is set). + * This ranges from -5 ... 0 ... +15, quadratically. + * + * So, the total bonus is -9 .. 0 .. +19 + * We use ~50% of the full 0...39 priority range so that: + * + * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. + * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. + * unless that context is far exceeding its CPU allocation. + * + * Both properties are important to certain workloads. + */ +int effective_vavavoom(task_t *p, int max_prio) +{ + struct vx_info *vxi = p->vx_info; + int vavavoom, max; + + /* lots of tokens = lots of vavavoom + * no tokens = no vavavoom */ + if ((vavavoom = atomic_read(&vxi->sched.tokens)) >= 0) { + max = vxi->sched.tokens_max; + vavavoom = max - vavavoom; + max = max * max; + vavavoom = max_prio * VAVAVOOM_RATIO / 100 + * (vavavoom*vavavoom - (max >> 2)) / max; + /* alternative, geometric mapping + vavavoom = -( MAX_USER_PRIO*VAVAVOOM_RATIO/100 * vavavoom + / vxi->sched.tokens_max - + MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */ + } else + vavavoom = 0; + /* vavavoom = ( MAX_USER_PRIO*VAVAVOOM_RATIO/100*tokens_left(p) - + MAX_USER_PRIO*VAVAVOOM_RATIO/100/2); */ + + return vavavoom; +} + + +int vc_set_sched(uint32_t xid, void __user *data) +{ + struct vcmd_set_sched_v2 vc_data; + struct vx_info *vxi; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi = locate_vx_info(xid); + if (!vxi) + return -EINVAL; + + spin_lock(&vxi->sched.tokens_lock); + + if (vc_data.interval != SCHED_KEEP) + vxi->sched.interval = vc_data.interval; + if (vc_data.fill_rate != SCHED_KEEP) + vxi->sched.fill_rate = vc_data.fill_rate; + if (vc_data.tokens_min != SCHED_KEEP) + vxi->sched.tokens_min = vc_data.tokens_min; + if (vc_data.tokens_max != SCHED_KEEP) + vxi->sched.tokens_max = vc_data.tokens_max; + if (vc_data.tokens != SCHED_KEEP) + atomic_set(&vxi->sched.tokens, vc_data.tokens); + + /* Sanity check the resultant values */ + if (vxi->sched.fill_rate <= 0) + vxi->sched.fill_rate = 1; + if (vxi->sched.interval <= 0) + vxi->sched.interval = HZ; + if (vxi->sched.tokens_max == 0) + vxi->sched.tokens_max = 1; + if (atomic_read(&vxi->sched.tokens) > vxi->sched.tokens_max) + atomic_set(&vxi->sched.tokens, vxi->sched.tokens_max); + if (vxi->sched.tokens_min > vxi->sched.tokens_max) + vxi->sched.tokens_min = vxi->sched.tokens_max; + + spin_unlock(&vxi->sched.tokens_lock); + put_vx_info(vxi); + return 0; +} + diff --git a/kernel/vserver/signal.c b/kernel/vserver/signal.c new file mode 100644 index 000000000..91d8a3da2 --- /dev/null +++ b/kernel/vserver/signal.c @@ -0,0 +1,86 @@ +/* + * linux/kernel/vserver/signal.c + * + * Virtual Server: Signal Support + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * + */ + +#include +#include + +#include +#include + +#include +#include +#include + + +int vc_ctx_kill(uint32_t id, void __user *data) +{ + int retval, count=0; + struct vcmd_ctx_kill_v0 vc_data; + struct siginfo info; + struct task_struct *p; + struct vx_info *vxi; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + info.si_signo = vc_data.sig; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->pid; + info.si_uid = current->uid; + + vxi = locate_vx_info(id); + if (!vxi) + return -ESRCH; + + retval = -ESRCH; + read_lock(&tasklist_lock); + switch (vc_data.pid) { + case -1: + case 0: + for_each_process(p) { + int err = 0; + + if (vx_task_xid(p) != id || p->pid <= 1 || + (vc_data.pid && vxi->vx_initpid == p->pid) || + !thread_group_leader(p)) + continue; + + err = send_sig_info(vc_data.sig, &info, p); + ++count; + if (err != -EPERM) + retval = err; + } + break; + + default: + p = find_task_by_pid(vc_data.pid); + if (p) { + if (!thread_group_leader(p)) { + struct task_struct *tg; + + tg = find_task_by_pid(p->tgid); + if (tg) + p = tg; + } + if ((id == -1) || (vx_task_xid(p) == id)) + retval = send_sig_info(vc_data.sig, &info, p); + } + break; + } + read_unlock(&tasklist_lock); + put_vx_info(vxi); + return retval; +} + + diff --git a/kernel/vserver/switch.c b/kernel/vserver/switch.c new file mode 100644 index 000000000..25c1083e3 --- /dev/null +++ b/kernel/vserver/switch.c @@ -0,0 +1,181 @@ +/* + * linux/kernel/vserver/switch.c + * + * Virtual Server: Syscall Switch + * + * Copyright (C) 2003-2004 Herbert Pötzl + * + * V0.01 syscall switch + * V0.02 added signal to context + * V0.03 added rlimit functions + * V0.04 added iattr, task/xid functions + * + */ + +#include +#include +#include + +#include +#include +#include + + +static inline int +vc_get_version(uint32_t id) +{ + return VCI_VERSION; +} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern unsigned int vx_debug_switch; + + +extern asmlinkage long +sys_vserver(uint32_t cmd, uint32_t id, void __user *data) +{ + + if (vx_debug_switch) + printk( "vc: VCMD_%02d_%d[%d], %d\n", + VC_CATEGORY(cmd), VC_COMMAND(cmd), + VC_VERSION(cmd), id); + + switch (cmd) { + case VCMD_get_version: + return vc_get_version(id); + +#ifdef CONFIG_VSERVER_LEGACY + case VCMD_new_s_context: + return vc_new_s_context(id, data); + case VCMD_set_ipv4root: + return vc_set_ipv4root(id, data); +#endif + + case VCMD_task_xid: + return vc_task_xid(id, data); + case VCMD_vx_info: + return vc_vx_info(id, data); + + case VCMD_task_nid: + return vc_task_nid(id, data); + case VCMD_nx_info: + return vc_nx_info(id, data); + + case VCMD_set_namespace: + return vc_set_namespace(id, data); + case VCMD_cleanup_namespace: + return vc_cleanup_namespace(id, data); + } + + /* those are allowed while in setup too */ + if (!vx_check(0, VX_ADMIN|VX_WATCH) && + !vx_flags(VXF_STATE_SETUP,0)) + return -EPERM; + +#ifdef CONFIG_VSERVER_LEGACY + switch (cmd) { + case VCMD_set_cflags: + case VCMD_set_ccaps: + if (vx_check(0, VX_WATCH)) + return 0; + } +#endif + + switch (cmd) { + case VCMD_get_rlimit: + return vc_get_rlimit(id, data); + case VCMD_set_rlimit: + return vc_set_rlimit(id, data); + case VCMD_get_rlimit_mask: + return vc_get_rlimit_mask(id, data); + + case VCMD_vx_get_vhi_name: + return vc_get_vhi_name(id, data); + case VCMD_vx_set_vhi_name: + return vc_set_vhi_name(id, data); + + case VCMD_set_cflags: + return vc_set_cflags(id, data); + case VCMD_get_cflags: + return vc_get_cflags(id, data); + + case VCMD_set_ccaps: + return vc_set_ccaps(id, data); + case VCMD_get_ccaps: + return vc_get_ccaps(id, data); + + case VCMD_set_nflags: + return vc_set_nflags(id, data); + case VCMD_get_nflags: + return vc_get_nflags(id, data); + + case VCMD_set_ncaps: + return vc_set_ncaps(id, data); + case VCMD_get_ncaps: + return vc_get_ncaps(id, data); + + case VCMD_set_sched: + return vc_set_sched(id, data); + + case VCMD_add_dlimit: + return vc_add_dlimit(id, data); + case VCMD_rem_dlimit: + return vc_rem_dlimit(id, data); + case VCMD_set_dlimit: + return vc_set_dlimit(id, data); + case VCMD_get_dlimit: + return vc_get_dlimit(id, data); + } + + /* below here only with VX_ADMIN */ + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + return -EPERM; + + switch (cmd) { + case VCMD_ctx_kill: + return vc_ctx_kill(id, data); + +#ifdef CONFIG_VSERVER_LEGACY + case VCMD_create_context: + return vc_ctx_create(id, data); +#endif + + case VCMD_get_iattr: + return vc_get_iattr(id, data); + case VCMD_set_iattr: + return vc_set_iattr(id, data); + + case VCMD_enter_namespace: + return vc_enter_namespace(id, data); + + case VCMD_ctx_create: +#ifdef CONFIG_VSERVER_LEGACY + if (id == 1) { + current->xid = 1; + return 1; + } +#endif + return vc_ctx_create(id, data); + case VCMD_ctx_migrate: + return vc_ctx_migrate(id, data); + + case VCMD_net_create: + return vc_net_create(id, data); + case VCMD_net_migrate: + return vc_net_migrate(id, data); + + } + return -ENOSYS; +} + diff --git a/kernel/vserver/sysctl.c b/kernel/vserver/sysctl.c new file mode 100644 index 000000000..32fde9a93 --- /dev/null +++ b/kernel/vserver/sysctl.c @@ -0,0 +1,160 @@ +/* + * linux/kernel/sysctl.c + * + * Virtual Context Support + * + * Copyright (C) 2004 Herbert Pötzl + * + * V0.01 basic structure + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define CTL_VSERVER 4242 /* unused? */ + +enum { + CTL_DEBUG_SWITCH = 1, + CTL_DEBUG_LIMIT, + CTL_DEBUG_DLIMIT, +}; + + +unsigned int vx_debug_switch = 0; +unsigned int vx_debug_limit = 0; +unsigned int vx_debug_dlimit = 0; + + +static struct ctl_table_header *vserver_table_header; +static ctl_table vserver_table[]; + + +void vserver_register_sysctl(void) +{ + if (!vserver_table_header) { + vserver_table_header = register_sysctl_table(vserver_table, 1); +#ifdef CONFIG_PROC_FS +// if (vserver_table[0].de) +// vserver_table[0].de->owner = THIS_MODULE; +#endif + } + +} + +void vserver_unregister_sysctl(void) +{ + if (vserver_table_header) { + unregister_sysctl_table(vserver_table_header); + vserver_table_header = NULL; + } +} + + +static int proc_dodebug(ctl_table *table, int write, + struct file *file, void *buffer, size_t *lenp) +{ + char tmpbuf[20], *p, c; + unsigned int value; + size_t left, len; + + if ((file->f_pos && !write) || !*lenp) { + *lenp = 0; + return 0; + } + + left = *lenp; + + if (write) { + if (!access_ok(VERIFY_READ, buffer, left)) + return -EFAULT; + p = (char *) buffer; + while (left && __get_user(c, p) >= 0 && isspace(c)) + left--, p++; + if (!left) + goto done; + + if (left > sizeof(tmpbuf) - 1) + return -EINVAL; + if (copy_from_user(tmpbuf, p, left)) + return -EFAULT; + tmpbuf[left] = '\0'; + + for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--) + value = 10 * value + (*p - '0'); + if (*p && !isspace(*p)) + return -EINVAL; + while (left && isspace(*p)) + left--, p++; + *(unsigned int *) table->data = value; + } else { + if (!access_ok(VERIFY_WRITE, buffer, left)) + return -EFAULT; + len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data); + if (len > left) + len = left; + if (__copy_to_user(buffer, tmpbuf, len)) + return -EFAULT; + if ((left -= len) > 0) { + if (put_user('\n', (char *)buffer + len)) + return -EFAULT; + left--; + } + } + +done: + *lenp -= left; + file->f_pos += *lenp; + return 0; +} + + + +static ctl_table debug_table[] = { + { + .ctl_name = CTL_DEBUG_SWITCH, + .procname = "debug_switch", + .data = &vx_debug_switch, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dodebug + }, + { + .ctl_name = CTL_DEBUG_LIMIT, + .procname = "debug_limit", + .data = &vx_debug_limit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dodebug + }, + { + .ctl_name = CTL_DEBUG_DLIMIT, + .procname = "debug_dlimit", + .data = &vx_debug_dlimit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dodebug + }, + { .ctl_name = 0 } +}; + +static ctl_table vserver_table[] = { + { + .ctl_name = CTL_VSERVER, + .procname = "vserver", + .mode = 0555, + .child = debug_table + }, + { .ctl_name = 0 } +}; + diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 987fbc298..b4beaca8f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -218,33 +218,6 @@ static int worker_thread(void *__cwq) return 0; } -static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq) -{ - if (cwq->thread == current) { - /* - * Probably keventd trying to flush its own queue. So simply run - * it by hand rather than deadlocking. - */ - run_workqueue(cwq); - } else { - DEFINE_WAIT(wait); - long sequence_needed; - - spin_lock_irq(&cwq->lock); - sequence_needed = cwq->insert_sequence; - - while (sequence_needed - cwq->remove_sequence > 0) { - prepare_to_wait(&cwq->work_done, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&cwq->lock); - schedule(); - spin_lock_irq(&cwq->lock); - } - finish_wait(&cwq->work_done, &wait); - spin_unlock_irq(&cwq->lock); - } -} - /* * flush_workqueue - ensure that any scheduled work has run to completion. * @@ -261,19 +234,43 @@ static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq) */ void fastcall flush_workqueue(struct workqueue_struct *wq) { + struct cpu_workqueue_struct *cwq; + int cpu; + might_sleep(); - if (is_single_threaded(wq)) { - /* Always use cpu 0's area. */ - flush_cpu_workqueue(wq->cpu_wq + 0); - } else { - int cpu; + lock_cpu_hotplug(); + for_each_online_cpu(cpu) { + DEFINE_WAIT(wait); + long sequence_needed; - lock_cpu_hotplug(); - for_each_online_cpu(cpu) - flush_cpu_workqueue(wq->cpu_wq + cpu); - unlock_cpu_hotplug(); + if (is_single_threaded(wq)) + cwq = wq->cpu_wq + 0; /* Always use cpu 0's area. */ + else + cwq = wq->cpu_wq + cpu; + + if (cwq->thread == current) { + /* + * Probably keventd trying to flush its own queue. + * So simply run it by hand rather than deadlocking. + */ + run_workqueue(cwq); + continue; + } + spin_lock_irq(&cwq->lock); + sequence_needed = cwq->insert_sequence; + + while (sequence_needed - cwq->remove_sequence > 0) { + prepare_to_wait(&cwq->work_done, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&cwq->lock); + schedule(); + spin_lock_irq(&cwq->lock); + } + finish_wait(&cwq->work_done, &wait); + spin_unlock_irq(&cwq->lock); } + unlock_cpu_hotplug(); } static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq, diff --git a/mm/Makefile b/mm/Makefile index d22feb38a..754c174a7 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -13,5 +13,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ $(mmu-y) obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o +obj-$(CONFIG_X86_4G) += usercopy.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o +obj-$(CONFIG_PROC_MM) += proc_mm.o diff --git a/mm/filemap.c b/mm/filemap.c index 6e59faaa6..248ec21c7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -647,7 +647,8 @@ void do_generic_mapping_read(struct address_space *mapping, struct file * filp, loff_t *ppos, read_descriptor_t * desc, - read_actor_t actor) + read_actor_t actor, + int nonblock) { struct inode *inode = mapping->host; unsigned long index, offset; @@ -682,11 +683,21 @@ void do_generic_mapping_read(struct address_space *mapping, find_page: page = find_get_page(mapping, index); if (unlikely(page == NULL)) { + if (nonblock) { + desc->error = -EWOULDBLOCKIO; + break; + } handle_ra_miss(mapping, &ra, index); goto no_cached_page; } - if (!PageUptodate(page)) + if (!PageUptodate(page)) { + if (nonblock) { + page_cache_release(page); + desc->error = -EWOULDBLOCKIO; + break; + } goto page_not_up_to_date; + } page_ok: /* If users can be writing to this page using arbitrary * virtual addresses, take care about potential aliasing @@ -896,7 +907,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (desc.count == 0) continue; desc.error = 0; - do_generic_file_read(filp,ppos,&desc,file_read_actor); + do_generic_file_read(filp,ppos,&desc,file_read_actor,0); retval += desc.written; if (!retval) { retval = desc.error; @@ -970,7 +981,7 @@ ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos, desc.buf = target; desc.error = 0; - do_generic_file_read(in_file, ppos, &desc, actor); + do_generic_file_read(in_file, ppos, &desc, actor, 0); if (desc.written) return desc.written; return desc.error; diff --git a/mm/fremap.c b/mm/fremap.c index eb056db90..6c38dc8f7 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -38,7 +38,8 @@ static inline void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma, set_page_dirty(page); page_remove_rmap(page); page_cache_release(page); - mm->rss--; + // mm->rss--; + vx_rsspages_dec(mm); } } } else { @@ -61,15 +62,12 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, pmd_t *pmd; pte_t pte_val; - /* - * We use page_add_file_rmap below: if install_page is - * ever extended to anonymous pages, this will warn us. - */ - BUG_ON(!page_mapping(page)); - pgd = pgd_offset(mm, addr); spin_lock(&mm->page_table_lock); + if (!vx_rsspages_avail(mm, 1)) + goto err_unlock; + pmd = pmd_alloc(mm, pgd, addr); if (!pmd) goto err_unlock; @@ -80,7 +78,8 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, zap_pte(mm, vma, addr, pte); - mm->rss++; + // mm->rss++; + vx_rsspages_inc(mm); flush_icache_page(vma, page); set_pte(pte, mk_pte(page, prot)); page_add_file_rmap(page); diff --git a/mm/memory.c b/mm/memory.c index 3df1f05e7..44f80c9c5 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -108,7 +108,8 @@ static inline void free_one_pmd(struct mmu_gather *tlb, pmd_t * dir) pte_free_tlb(tlb, page); } -static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) +static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir, + int pgd_idx) { int j; pmd_t * pmd; @@ -122,8 +123,11 @@ static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) } pmd = pmd_offset(dir, 0); pgd_clear(dir); - for (j = 0; j < PTRS_PER_PMD ; j++) + for (j = 0; j < PTRS_PER_PMD ; j++) { + if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE) + break; free_one_pmd(tlb, pmd+j); + } pmd_free_tlb(tlb, pmd); } @@ -136,11 +140,13 @@ static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir) void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr) { pgd_t * page_dir = tlb->mm->pgd; + int pgd_idx = first; page_dir += first; do { - free_one_pgd(tlb, page_dir); + free_one_pgd(tlb, page_dir, pgd_idx); page_dir++; + pgd_idx++; } while (--nr); } @@ -273,6 +279,10 @@ skip_copy_pte_range: struct page *page; unsigned long pfn; + if (!vx_rsspages_avail(dst, 1)) { + spin_unlock(&src->page_table_lock); + goto nomem; + } /* copy_one_pte */ if (pte_none(pte)) @@ -316,7 +326,8 @@ skip_copy_pte_range: pte = pte_mkclean(pte); pte = pte_mkold(pte); get_page(page); - dst->rss++; + // dst->rss++; + vx_rsspages_inc(dst); set_pte(dst_pte, pte); page_dup_rmap(page); cont_copy_pte_range_noset: @@ -432,7 +443,7 @@ static void zap_pmd_range(struct mmu_gather *tlb, unsigned long size, struct zap_details *details) { pmd_t * pmd; - unsigned long end; + unsigned long end, pgd_boundary; if (pgd_none(*dir)) return; @@ -443,8 +454,9 @@ static void zap_pmd_range(struct mmu_gather *tlb, } pmd = pmd_offset(dir, address); end = address + size; - if (end > ((address + PGDIR_SIZE) & PGDIR_MASK)) - end = ((address + PGDIR_SIZE) & PGDIR_MASK); + pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK); + if (pgd_boundary && (end > pgd_boundary)) + end = pgd_boundary; do { zap_pte_range(tlb, pmd, address, end - address, details); address = (address + PMD_SIZE) & PMD_MASK; @@ -637,13 +649,74 @@ follow_page(struct mm_struct *mm, unsigned long address, int write) if (pte_present(pte)) { if (write && !pte_write(pte)) goto out; + if (write && !pte_dirty(pte)) { + struct page *page = pte_page(pte); + if (!PageDirty(page)) + set_page_dirty(page); + } pfn = pte_pfn(pte); if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (write && !pte_dirty(pte) && !PageDirty(page)) + struct page *page = pfn_to_page(pfn); + + mark_page_accessed(page); + return page; + } + } + +out: + return NULL; +} + +struct page * +follow_page_pfn(struct mm_struct *mm, unsigned long address, int write, + unsigned long *pfn_ptr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + unsigned long pfn; + struct page *page; + + *pfn_ptr = 0; + page = follow_huge_addr(mm, address, write); + if (!IS_ERR(page)) + return page; + + pgd = pgd_offset(mm, address); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + goto out; + + pmd = pmd_offset(pgd, address); + if (pmd_none(*pmd)) + goto out; + if (pmd_huge(*pmd)) + return follow_huge_pmd(mm, address, pmd, write); + if (pmd_bad(*pmd)) + goto out; + + ptep = pte_offset_map(pmd, address); + if (!ptep) + goto out; + + pte = *ptep; + pte_unmap(ptep); + if (pte_present(pte)) { + if (write && !pte_write(pte)) + goto out; + if (write && !pte_dirty(pte)) { + struct page *page = pte_page(pte); + if (!PageDirty(page)) set_page_dirty(page); + } + pfn = pte_pfn(pte); + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + mark_page_accessed(page); return page; + } else { + *pfn_ptr = pfn; + return NULL; } } @@ -651,6 +724,7 @@ out: return NULL; } + /* * Given a physical address, is there a useful struct page pointing to * it? This may become more complex in the future if we start dealing @@ -1081,7 +1155,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, page_table = pte_offset_map(pmd, address); if (likely(pte_same(*page_table, pte))) { if (PageReserved(old_page)) - ++mm->rss; + // ++mm->rss; + vx_rsspages_inc(mm); else page_remove_rmap(old_page); break_cow(vma, new_page, address, page_table); @@ -1330,6 +1405,10 @@ static int do_swap_page(struct mm_struct * mm, inc_page_state(pgmajfault); } + if (!vx_rsspages_avail(mm, 1)) { + ret = VM_FAULT_OOM; + goto out; + } mark_page_accessed(page); lock_page(page); @@ -1354,7 +1433,8 @@ static int do_swap_page(struct mm_struct * mm, if (vm_swap_full()) remove_exclusive_swap_page(page); - mm->rss++; + // mm->rss++; + vx_rsspages_inc(mm); pte = mk_pte(page, vma->vm_page_prot); if (write_access && can_share_swap_page(page)) { pte = maybe_mkwrite(pte_mkdirty(pte), vma); @@ -1394,6 +1474,11 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, pte_t entry; struct page * page = ZERO_PAGE(addr); + if (!vx_rsspages_avail(mm, 1)) { + spin_unlock(&mm->page_table_lock); + return VM_FAULT_OOM; + } + /* Read-only mapping of ZERO_PAGE. */ entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); @@ -1419,7 +1504,8 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, spin_unlock(&mm->page_table_lock); goto out; } - mm->rss++; + // mm->rss++; + vx_rsspages_inc(mm); entry = maybe_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)), vma); @@ -1482,6 +1568,8 @@ retry: return VM_FAULT_SIGBUS; if (new_page == NOPAGE_OOM) return VM_FAULT_OOM; + if (!vx_rsspages_avail(mm, 1)) + return VM_FAULT_OOM; /* * Should we do an early C-O-W break? @@ -1528,7 +1616,8 @@ retry: /* Only go through if we didn't race with anybody else... */ if (pte_none(*page_table)) { if (!PageReserved(new_page)) - ++mm->rss; + // ++mm->rss; + vx_rsspages_inc(mm); flush_icache_page(vma, new_page); entry = mk_pte(new_page, vma->vm_page_prot); if (write_access) @@ -1670,15 +1759,20 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma, * We need the page table lock to synchronize with kswapd * and the SMP-safe atomic PTE updates. */ + set_delay_flag(current,PF_MEMIO); spin_lock(&mm->page_table_lock); pmd = pmd_alloc(mm, pgd, address); if (pmd) { pte_t * pte = pte_alloc_map(mm, pmd, address); - if (pte) - return handle_pte_fault(mm, vma, address, write_access, pte, pmd); + if (pte) { + int rc = handle_pte_fault(mm, vma, address, write_access, pte, pmd); + clear_delay_flag(current,PF_MEMIO); + return rc; + } } spin_unlock(&mm->page_table_lock); + clear_delay_flag(current,PF_MEMIO); return VM_FAULT_OOM; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 1b11685f0..096a24904 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1002,7 +1002,8 @@ void mpol_free_shared_policy(struct shared_policy *p) up(&p->sem); } -static __init int numa_policy_init(void) +/* assumes fs == KERNEL_DS */ +void __init numa_policy_init(void) { policy_cache = kmem_cache_create("numa_policy", sizeof(struct mempolicy), @@ -1011,6 +1012,17 @@ static __init int numa_policy_init(void) sn_cache = kmem_cache_create("shared_policy_node", sizeof(struct sp_node), 0, SLAB_PANIC, NULL, NULL); - return 0; + + /* Set interleaving policy for system init. This way not all + the data structures allocated at system boot end up in node zero. */ + + if (sys_set_mempolicy(MPOL_INTERLEAVE, node_online_map, MAX_NUMNODES) < 0) + printk("numa_policy_init: interleaving failed\n"); +} + +/* Reset policy of current process to default. + * Assumes fs == KERNEL_DS */ +void numa_default_policy(void) +{ + sys_set_mempolicy(MPOL_DEFAULT, NULL, 0); } -module_init(numa_policy_init); diff --git a/mm/mlock.c b/mm/mlock.c index a9e37161d..14280637e 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -60,7 +60,7 @@ static int do_mlock(unsigned long start, size_t len, int on) struct vm_area_struct * vma, * next; int error; - if (on && !capable(CAP_IPC_LOCK)) + if (on && !can_do_mlock()) return -EPERM; len = PAGE_ALIGN(len); end = start + len; @@ -103,7 +103,7 @@ static int do_mlock(unsigned long start, size_t len, int on) asmlinkage long sys_mlock(unsigned long start, size_t len) { - unsigned long locked; + unsigned long locked, grow; unsigned long lock_limit; int error = -ENOMEM; @@ -111,15 +111,18 @@ asmlinkage long sys_mlock(unsigned long start, size_t len) len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; - locked = len >> PAGE_SHIFT; - locked += current->mm->locked_vm; + grow = len >> PAGE_SHIFT; + if (!vx_vmlocked_avail(current->mm, grow)) + goto out; + locked = current->mm->locked_vm + grow; lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; /* check against resource limits */ - if (locked <= lock_limit) + if ( (locked <= lock_limit) || capable(CAP_IPC_LOCK)) error = do_mlock(start, len, 1); +out: up_write(¤t->mm->mmap_sem); return error; } @@ -142,7 +145,7 @@ static int do_mlockall(int flags) unsigned int def_flags; struct vm_area_struct * vma; - if (!capable(CAP_IPC_LOCK)) + if (!can_do_mlock()) return -EPERM; def_flags = 0; @@ -177,7 +180,10 @@ asmlinkage long sys_mlockall(int flags) lock_limit >>= PAGE_SHIFT; ret = -ENOMEM; - if (current->mm->total_vm <= lock_limit) + if (!vx_vmlocked_avail(current->mm, current->mm->total_vm)) + goto out; + /* check vserver lock limits? */ + if ((current->mm->total_vm <= lock_limit) || capable(CAP_IPC_LOCK)) ret = do_mlockall(flags); out: up_write(¤t->mm->mmap_sem); diff --git a/mm/mmap.c b/mm/mmap.c index d6fd2fe13..cafada378 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -245,6 +245,8 @@ static inline void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent) { + if (vma->vm_flags & VM_EXEC) + arch_add_exec_range(mm, vma->vm_end); if (prev) { vma->vm_next = prev->vm_next; prev->vm_next = vma; @@ -293,8 +295,10 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node **rb_link, struct rb_node *rb_parent) { + vma_prio_tree_init(vma); __vma_link_list(mm, vma, prev, rb_parent); __vma_link_rb(mm, vma, rb_link, rb_parent); + __vma_link_file(vma); __anon_vma_link(vma); } @@ -310,10 +314,7 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma, if (mapping) spin_lock(&mapping->i_mmap_lock); anon_vma_lock(vma); - __vma_link(mm, vma, prev, rb_link, rb_parent); - __vma_link_file(vma); - anon_vma_unlock(vma); if (mapping) spin_unlock(&mapping->i_mmap_lock); @@ -324,9 +325,9 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma, } /* - * Helper for vma_adjust in the split_vma insert case: - * insert vm structure into list and rbtree and anon_vma, - * but it has already been inserted into prio_tree earlier. + * Insert vm structure into process list sorted by address and into the + * inode's i_mmap tree. The caller should hold mm->mmap_sem and + * ->f_mappping->i_mmap_lock if vm_file is non-NULL. */ static void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) @@ -338,7 +339,9 @@ __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) if (__vma && __vma->vm_start < vma->vm_end) BUG(); __vma_link(mm, vma, prev, rb_link, rb_parent); + mark_mm_hugetlb(mm, vma); mm->map_count++; + validate_mm(mm); } static inline void @@ -349,6 +352,8 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma, rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) mm->mmap_cache = prev; + if (vma->vm_flags & VM_EXEC) + arch_remove_exec_range(mm, vma->vm_end); } /* @@ -372,27 +377,20 @@ void vma_adjust(struct vm_area_struct *vma, unsigned long start, if (next && !insert) { if (end >= next->vm_end) { - /* - * vma expands, overlapping all the next, and - * perhaps the one after too (mprotect case 6). - */ again: remove_next = 1 + (end > next->vm_end); end = next->vm_end; anon_vma = next->anon_vma; - } else if (end > next->vm_start) { - /* - * vma expands, overlapping part of the next: - * mprotect case 5 shifting the boundary up. - */ - adjust_next = (end - next->vm_start) >> PAGE_SHIFT; - anon_vma = next->anon_vma; - } else if (end < vma->vm_end) { + } else if (end < vma->vm_end || end > next->vm_start) { /* * vma shrinks, and !insert tells it's not - * split_vma inserting another: so it must be - * mprotect case 4 shifting the boundary down. + * split_vma inserting another: so it must + * be mprotect shifting the boundary down. + * Or: + * vma expands, overlapping part of the next: + * must be mprotect shifting the boundary up. */ - adjust_next = - ((vma->vm_end - end) >> PAGE_SHIFT); + BUG_ON(vma->vm_end != next->vm_start); + adjust_next = end - next->vm_start; anon_vma = next->anon_vma; } } @@ -402,15 +400,6 @@ again: remove_next = 1 + (end > next->vm_end); if (!(vma->vm_flags & VM_NONLINEAR)) root = &mapping->i_mmap; spin_lock(&mapping->i_mmap_lock); - if (insert) { - /* - * Put into prio_tree now, so instantiated pages - * are visible to arm/parisc __flush_dcache_page - * throughout; but we cannot insert into address - * space until vma start or end is updated. - */ - __vma_link_file(insert); - } } /* @@ -433,8 +422,8 @@ again: remove_next = 1 + (end > next->vm_end); vma->vm_end = end; vma->vm_pgoff = pgoff; if (adjust_next) { - next->vm_start += adjust_next << PAGE_SHIFT; - next->vm_pgoff += adjust_next; + next->vm_start += adjust_next; + next->vm_pgoff += adjust_next >> PAGE_SHIFT; } if (root) { @@ -634,6 +623,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, } else /* cases 2, 5, 7 */ vma_adjust(prev, prev->vm_start, end, prev->vm_pgoff, NULL); + if (prev->vm_flags & VM_EXEC) + arch_add_exec_range(mm, prev->vm_end); return prev; } @@ -725,11 +716,11 @@ none: * The caller must hold down_write(current->mm->mmap_sem). */ -unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flags, unsigned long pgoff) +unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long pgoff) { - struct mm_struct * mm = current->mm; struct vm_area_struct * vma, * prev; struct inode *inode; unsigned int vm_flags; @@ -770,7 +761,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, /* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. */ - addr = get_unmapped_area(file, addr, len, pgoff, flags); + addr = get_unmapped_area(file, addr, len, pgoff, flags, prot & PROT_EXEC); if (addr & ~PAGE_MASK) return addr; @@ -782,15 +773,17 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; if (flags & MAP_LOCKED) { - if (!capable(CAP_IPC_LOCK)) + if (!can_do_mlock()) return -EPERM; vm_flags |= VM_LOCKED; } /* mlock MCL_FUTURE? */ if (vm_flags & VM_LOCKED) { - unsigned long locked = mm->locked_vm << PAGE_SHIFT; + unsigned long locked, lock_limit; + locked = mm->locked_vm << PAGE_SHIFT; + lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; locked += len; - if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; } @@ -863,6 +856,10 @@ munmap_back: > current->rlim[RLIMIT_AS].rlim_cur) return -ENOMEM; + /* check context space, maybe only Private writable mapping? */ + if (!vx_vmpages_avail(mm, len >> PAGE_SHIFT)) + return -ENOMEM; + if (accountable && (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1)) { if (vm_flags & VM_SHARED) { @@ -959,9 +956,11 @@ munmap_back: kmem_cache_free(vm_area_cachep, vma); } out: - mm->total_vm += len >> PAGE_SHIFT; + // mm->total_vm += len >> PAGE_SHIFT; + vx_vmpages_add(mm, len >> PAGE_SHIFT); if (vm_flags & VM_LOCKED) { - mm->locked_vm += len >> PAGE_SHIFT; + // mm->locked_vm += len >> PAGE_SHIFT; + vx_vmlocked_add(mm, len >> PAGE_SHIFT); make_pages_present(addr, addr + len); } if (flags & MAP_POPULATE) { @@ -1004,7 +1003,7 @@ EXPORT_SYMBOL(do_mmap_pgoff); #ifndef HAVE_ARCH_UNMAPPED_AREA static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) + unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; @@ -1049,12 +1048,12 @@ full_search: #else extern unsigned long arch_get_unmapped_area(struct file *, unsigned long, unsigned long, - unsigned long, unsigned long); + unsigned long, unsigned long, unsigned long); #endif unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) + unsigned long pgoff, unsigned long flags, unsigned long exec) { if (flags & MAP_FIXED) { unsigned long ret; @@ -1086,7 +1085,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags); - return arch_get_unmapped_area(file, addr, len, pgoff, flags); + return arch_get_unmapped_area(file, addr, len, pgoff, flags, exec); } EXPORT_SYMBOL(get_unmapped_area); @@ -1164,6 +1163,14 @@ out: return prev ? prev->vm_next : vma; } + +static int over_stack_limit(unsigned long sz) +{ + if (sz < EXEC_STACK_BIAS) + return 0; + return (sz - EXEC_STACK_BIAS) > current->rlim[RLIMIT_STACK].rlim_cur; +} + #ifdef CONFIG_STACK_GROWSUP /* * vma is the first one with address > vma->vm_end. Have to extend vma. @@ -1193,22 +1200,26 @@ int expand_stack(struct vm_area_struct * vma, unsigned long address) grow = (address - vma->vm_end) >> PAGE_SHIFT; /* Overcommit.. */ - if (security_vm_enough_memory(grow)) { + if (security_vm_enough_memory(grow) || + !vx_vmpages_avail(vma->vm_mm, grow)) { anon_vma_unlock(vma); return -ENOMEM; } - if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || + if (over_stack_limit(address - vma->vm_start) || ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { anon_vma_unlock(vma); vm_unacct_memory(grow); return -ENOMEM; } + vma->vm_end = address; - vma->vm_mm->total_vm += grow; + // vma->vm_mm->total_vm += grow; + vx_vmpages_add(vma->vm_mm, grow); if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; + // vma->vm_mm->locked_vm += grow; + vx_vmlocked_add(vma->vm_mm, grow); anon_vma_unlock(vma); return 0; } @@ -1254,23 +1265,27 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address) grow = (vma->vm_start - address) >> PAGE_SHIFT; /* Overcommit.. */ - if (security_vm_enough_memory(grow)) { + if (security_vm_enough_memory(grow) || + !vx_vmpages_avail(vma->vm_mm, grow)) { anon_vma_unlock(vma); return -ENOMEM; } - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || + if (over_stack_limit(vma->vm_end - address) || ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { anon_vma_unlock(vma); vm_unacct_memory(grow); return -ENOMEM; } + vma->vm_start = address; vma->vm_pgoff -= grow; - vma->vm_mm->total_vm += grow; + // vma->vm_mm->total_vm += grow; + vx_vmpages_add(vma->vm_mm, grow); if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; + // vma->vm_mm->locked_vm += grow; + vx_vmlocked_add(vma->vm_mm, grow); anon_vma_unlock(vma); return 0; } @@ -1372,18 +1387,28 @@ no_mmaps: static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area) { size_t len = area->vm_end - area->vm_start; + unsigned long old_end = area->vm_end; - area->vm_mm->total_vm -= len >> PAGE_SHIFT; + // area->vm_mm->total_vm -= len >> PAGE_SHIFT; + vx_vmpages_sub(area->vm_mm, len >> PAGE_SHIFT); + if (area->vm_flags & VM_LOCKED) - area->vm_mm->locked_vm -= len >> PAGE_SHIFT; + // area->vm_mm->locked_vm -= len >> PAGE_SHIFT; + vx_vmlocked_sub(area->vm_mm, len >> PAGE_SHIFT); /* * Is this a new hole at the lowest possible address? */ if (area->vm_start >= TASK_UNMAPPED_BASE && area->vm_start < area->vm_mm->free_area_cache) area->vm_mm->free_area_cache = area->vm_start; - + /* + * Is this a new hole at the highest possible address? + */ + if (area->vm_start > area->vm_mm->non_executable_cache) + area->vm_mm->non_executable_cache = area->vm_start; remove_vm_struct(area); + if (unlikely(area->vm_flags & VM_EXEC)) + arch_remove_exec_range(mm, old_end); } /* @@ -1471,7 +1496,6 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, /* most fields are the same, copy all, and then fixup */ *new = *vma; - vma_prio_tree_init(new); if (new_below) new->vm_end = addr; @@ -1493,10 +1517,14 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); - if (new_below) + if (new_below) { + unsigned long old_end = vma->vm_end; + vma_adjust(vma, addr, vma->vm_end, vma->vm_pgoff + ((addr - new->vm_start) >> PAGE_SHIFT), new); - else + if (vma->vm_flags & VM_EXEC) + arch_remove_exec_range(mm, old_end); + } else vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new); return 0; @@ -1612,10 +1640,13 @@ unsigned long do_brk(unsigned long addr, unsigned long len) * mlock MCL_FUTURE? */ if (mm->def_flags & VM_LOCKED) { - unsigned long locked = mm->locked_vm << PAGE_SHIFT; + unsigned long locked, lock_limit; + locked = mm->locked_vm << PAGE_SHIFT; + lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; locked += len; - if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; + /* vserver checks ? */ } /* @@ -1637,7 +1668,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len) if (mm->map_count > sysctl_max_map_count) return -ENOMEM; - if (security_vm_enough_memory(len >> PAGE_SHIFT)) + if (security_vm_enough_memory(len >> PAGE_SHIFT) || + !vx_vmpages_avail(mm, len >> PAGE_SHIFT)) return -ENOMEM; flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; @@ -1665,9 +1697,11 @@ unsigned long do_brk(unsigned long addr, unsigned long len) vma->vm_page_prot = protection_map[flags & 0x0f]; vma_link(mm, vma, prev, rb_link, rb_parent); out: - mm->total_vm += len >> PAGE_SHIFT; + // mm->total_vm += len >> PAGE_SHIFT; + vx_vmpages_add(mm, len >> PAGE_SHIFT); if (flags & VM_LOCKED) { - mm->locked_vm += len >> PAGE_SHIFT; + // mm->locked_vm += len >> PAGE_SHIFT; + vx_vmlocked_add(mm, len >> PAGE_SHIFT); make_pages_present(addr, addr + len); } return addr; @@ -1701,9 +1735,13 @@ void exit_mmap(struct mm_struct *mm) vma = mm->mmap; mm->mmap = mm->mmap_cache = NULL; mm->mm_rb = RB_ROOT; - mm->rss = 0; - mm->total_vm = 0; - mm->locked_vm = 0; + // mm->rss = 0; + vx_rsspages_sub(mm, mm->rss); + // mm->total_vm = 0; + vx_vmpages_sub(mm, mm->total_vm); + // mm->locked_vm = 0; + vx_vmlocked_sub(mm, mm->locked_vm); + arch_flush_exec_range(mm); spin_unlock(&mm->page_table_lock); @@ -1784,7 +1822,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (new_vma) { *new_vma = *vma; - vma_prio_tree_init(new_vma); pol = mpol_copy(vma_policy(vma)); if (IS_ERR(pol)) { kmem_cache_free(vm_area_cachep, new_vma); diff --git a/mm/mprotect.c b/mm/mprotect.c index 5b438e1a0..ec0e1aa91 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -113,8 +114,9 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, unsigned long start, unsigned long end, unsigned int newflags) { struct mm_struct * mm = vma->vm_mm; - unsigned long charged = 0; + unsigned long charged = 0, old_end = vma->vm_end; pgprot_t newprot; + unsigned int oldflags; pgoff_t pgoff; int error; @@ -175,8 +177,11 @@ success: * vm_flags and vm_page_prot are protected by the mmap_sem * held in write mode. */ + oldflags = vma->vm_flags; vma->vm_flags = newflags; vma->vm_page_prot = newprot; + if (oldflags & VM_EXEC) + arch_remove_exec_range(current->mm, old_end); change_protection(vma, start, end, newprot); return 0; @@ -186,7 +191,8 @@ fail: } asmlinkage long -sys_mprotect(unsigned long start, size_t len, unsigned long prot) +do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, + unsigned long prot) { unsigned long vm_flags, nstart, end, tmp; struct vm_area_struct *vma, *prev; @@ -209,9 +215,9 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot) vm_flags = calc_vm_prot_bits(prot); - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); - vma = find_vma_prev(current->mm, start, &prev); + vma = find_vma_prev(mm, start, &prev); error = -ENOMEM; if (!vma) goto out; @@ -277,6 +283,11 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot) } } out: - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return error; } + +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + return(do_mprotect(current->mm, start, len, prot)); +} diff --git a/mm/mremap.c b/mm/mremap.c index 690b8002d..4b45b59d7 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -224,9 +224,11 @@ static unsigned long move_vma(struct vm_area_struct *vma, vma->vm_next->vm_flags |= VM_ACCOUNT; } - mm->total_vm += new_len >> PAGE_SHIFT; + // mm->total_vm += new_len >> PAGE_SHIFT; + vx_vmpages_add(mm, new_len >> PAGE_SHIFT); if (vm_flags & VM_LOCKED) { - mm->locked_vm += new_len >> PAGE_SHIFT; + // mm->locked_vm += new_len >> PAGE_SHIFT; + vx_vmlocked_add(mm, new_len >> PAGE_SHIFT); if (new_len > old_len) make_pages_present(new_addr + old_len, new_addr + new_len); @@ -325,16 +327,21 @@ unsigned long do_mremap(unsigned long addr, goto out; } if (vma->vm_flags & VM_LOCKED) { - unsigned long locked = current->mm->locked_vm << PAGE_SHIFT; + unsigned long locked, lock_limit; + locked = current->mm->locked_vm << PAGE_SHIFT; + lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; locked += new_len - old_len; ret = -EAGAIN; - if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) goto out; } ret = -ENOMEM; if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) > current->rlim[RLIMIT_AS].rlim_cur) goto out; + /* check context space, maybe only Private writable mapping? */ + if (!vx_vmpages_avail(current->mm, (new_len - old_len) >> PAGE_SHIFT)) + goto out; if (vma->vm_flags & VM_ACCOUNT) { charged = (new_len - old_len) >> PAGE_SHIFT; @@ -358,9 +365,11 @@ unsigned long do_mremap(unsigned long addr, vma_adjust(vma, vma->vm_start, addr + new_len, vma->vm_pgoff, NULL); - current->mm->total_vm += pages; + // current->mm->total_vm += pages; + vx_vmpages_add(current->mm, pages); if (vma->vm_flags & VM_LOCKED) { - current->mm->locked_vm += pages; + // current->mm->locked_vm += pages; + vx_vmlocked_add(current->mm, pages); make_pages_present(addr + old_len, addr + new_len); } @@ -381,7 +390,8 @@ unsigned long do_mremap(unsigned long addr, map_flags |= MAP_SHARED; new_addr = get_unmapped_area(vma->vm_file, 0, new_len, - vma->vm_pgoff, map_flags); + vma->vm_pgoff, map_flags, + vma->vm_flags & VM_EXEC); ret = new_addr; if (new_addr & ~PAGE_MASK) goto out; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 203923cbe..2f1529049 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -54,6 +54,7 @@ static int badness(struct task_struct *p) * The memory size of the process is the basis for the badness. */ points = p->mm->total_vm; + /* add vserver badness ;) */ /* * CPU time is in seconds and run time is in minutes. There is no @@ -245,6 +246,7 @@ void out_of_memory(void) * If it's been a long time since last failure, * we're not oom. */ + last = now; if (since > 5*HZ) goto reset; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a2aa511ad..d74d6adb7 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -99,22 +99,6 @@ EXPORT_SYMBOL(laptop_mode); static void background_writeout(unsigned long _min_pages); -struct writeback_state -{ - unsigned long nr_dirty; - unsigned long nr_unstable; - unsigned long nr_mapped; - unsigned long nr_writeback; -}; - -static void get_writeback_state(struct writeback_state *wbs) -{ - wbs->nr_dirty = read_page_state(nr_dirty); - wbs->nr_unstable = read_page_state(nr_unstable); - wbs->nr_mapped = read_page_state(nr_mapped); - wbs->nr_writeback = read_page_state(nr_writeback); -} - /* * Work out the current dirty-memory clamping and background writeout * thresholds. @@ -133,7 +117,7 @@ static void get_writeback_state(struct writeback_state *wbs) * clamping level. */ static void -get_dirty_limits(struct writeback_state *wbs, long *pbackground, long *pdirty) +get_dirty_limits(struct page_state *ps, long *pbackground, long *pdirty) { int background_ratio; /* Percentages */ int dirty_ratio; @@ -142,9 +126,9 @@ get_dirty_limits(struct writeback_state *wbs, long *pbackground, long *pdirty) long dirty; struct task_struct *tsk; - get_writeback_state(wbs); + get_page_state(ps); - unmapped_ratio = 100 - (wbs->nr_mapped * 100) / total_pages; + unmapped_ratio = 100 - (ps->nr_mapped * 100) / total_pages; dirty_ratio = vm_dirty_ratio; if (dirty_ratio > unmapped_ratio / 2) @@ -177,7 +161,7 @@ get_dirty_limits(struct writeback_state *wbs, long *pbackground, long *pdirty) */ static void balance_dirty_pages(struct address_space *mapping) { - struct writeback_state wbs; + struct page_state ps; long nr_reclaimable; long background_thresh; long dirty_thresh; @@ -194,9 +178,9 @@ static void balance_dirty_pages(struct address_space *mapping) .nr_to_write = write_chunk, }; - get_dirty_limits(&wbs, &background_thresh, &dirty_thresh); - nr_reclaimable = wbs.nr_dirty + wbs.nr_unstable; - if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh) + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); + nr_reclaimable = ps.nr_dirty + ps.nr_unstable; + if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) break; dirty_exceeded = 1; @@ -209,10 +193,10 @@ static void balance_dirty_pages(struct address_space *mapping) */ if (nr_reclaimable) { writeback_inodes(&wbc); - get_dirty_limits(&wbs, &background_thresh, + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); - nr_reclaimable = wbs.nr_dirty + wbs.nr_unstable; - if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh) + nr_reclaimable = ps.nr_dirty + ps.nr_unstable; + if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) break; pages_written += write_chunk - wbc.nr_to_write; if (pages_written >= write_chunk) @@ -221,7 +205,7 @@ static void balance_dirty_pages(struct address_space *mapping) blk_congestion_wait(WRITE, HZ/10); } - if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh) + if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) dirty_exceeded = 0; if (writeback_in_progress(bdi)) @@ -248,10 +232,10 @@ static void balance_dirty_pages(struct address_space *mapping) * which was newly dirtied. The function will periodically check the system's * dirty state and will initiate writeback if needed. * - * On really big machines, get_writeback_state is expensive, so try to avoid - * calling it too often (ratelimiting). But once we're over the dirty memory - * limit we decrease the ratelimiting by a lot, to prevent individual processes - * from overshooting the limit by (ratelimit_pages) each. + * On really big machines, get_page_state is expensive, so try to avoid calling + * it too often (ratelimiting). But once we're over the dirty memory limit we + * decrease the ratelimiting by a lot, to prevent individual processes from + * overshooting the limit by (ratelimit_pages) each. */ void balance_dirty_pages_ratelimited(struct address_space *mapping) { @@ -292,12 +276,12 @@ static void background_writeout(unsigned long _min_pages) }; for ( ; ; ) { - struct writeback_state wbs; + struct page_state ps; long background_thresh; long dirty_thresh; - get_dirty_limits(&wbs, &background_thresh, &dirty_thresh); - if (wbs.nr_dirty + wbs.nr_unstable < background_thresh + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); + if (ps.nr_dirty + ps.nr_unstable < background_thresh && min_pages <= 0) break; wbc.encountered_congestion = 0; @@ -322,10 +306,10 @@ static void background_writeout(unsigned long _min_pages) int wakeup_bdflush(long nr_pages) { if (nr_pages == 0) { - struct writeback_state wbs; + struct page_state ps; - get_writeback_state(&wbs); - nr_pages = wbs.nr_dirty + wbs.nr_unstable; + get_page_state(&ps); + nr_pages = ps.nr_dirty + ps.nr_unstable; } return pdflush_operation(background_writeout, nr_pages); } @@ -359,7 +343,7 @@ static void wb_kupdate(unsigned long arg) unsigned long start_jif; unsigned long next_jif; long nr_to_write; - struct writeback_state wbs; + struct page_state ps; struct writeback_control wbc = { .bdi = NULL, .sync_mode = WB_SYNC_NONE, @@ -371,11 +355,11 @@ static void wb_kupdate(unsigned long arg) sync_supers(); - get_writeback_state(&wbs); + get_page_state(&ps); oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100; start_jif = jiffies; next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100; - nr_to_write = wbs.nr_dirty + wbs.nr_unstable + + nr_to_write = ps.nr_dirty + ps.nr_unstable + (inodes_stat.nr_inodes - inodes_stat.nr_unused); while (nr_to_write > 0) { wbc.encountered_congestion = 0; @@ -450,8 +434,8 @@ void laptop_sync_completion(void) /* * If ratelimit_pages is too high then we can get into dirty-data overload * if a large number of processes all perform writes at the same time. - * If it is too low then SMP machines will call the (expensive) - * get_writeback_state too often. + * If it is too low then SMP machines will call the (expensive) get_page_state + * too often. * * Here we set ratelimit_pages to a level which ensures that when all CPUs are * dirtying in parallel, we cannot go more than 3% (1/32) over the dirty memory diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3dbbeb2f3..e511c287e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -279,6 +279,8 @@ void __free_pages_ok(struct page *page, unsigned int order) LIST_HEAD(list); int i; + arch_free_page(page, order); + mod_page_state(pgfree, 1 << order); for (i = 0 ; i < (1 << order) ; ++i) free_pages_check(__FUNCTION__, page + i); @@ -497,6 +499,8 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) struct per_cpu_pages *pcp; unsigned long flags; + arch_free_page(page, 0); + kernel_map_pages(page, 1, 0); inc_page_state(pgfree); free_pages_check(__FUNCTION__, page); @@ -988,23 +992,6 @@ void get_full_page_state(struct page_state *ret) __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long)); } -unsigned long __read_page_state(unsigned offset) -{ - unsigned long ret = 0; - int cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - unsigned long in; - - if (!cpu_possible(cpu)) - continue; - - in = (unsigned long)&per_cpu(page_states, cpu) + offset; - ret += *((unsigned long *)in); - } - return ret; -} - void get_zone_counts(unsigned long *active, unsigned long *inactive, unsigned long *free) { @@ -1034,6 +1021,8 @@ void si_meminfo(struct sysinfo *val) val->freehigh = 0; #endif val->mem_unit = PAGE_SIZE; + if (vx_flags(VXF_VIRT_MEM, 0)) + vx_vsi_meminfo(val); } EXPORT_SYMBOL(si_meminfo); diff --git a/mm/pdflush.c b/mm/pdflush.c index 1e682bed9..09e62cf1c 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -88,6 +88,8 @@ struct pdflush_work { unsigned long when_i_went_to_sleep; }; +void try_to_clip_inodes(void); + static int __pdflush(struct pdflush_work *my_work) { current->flags |= PF_FLUSHER; @@ -125,6 +127,8 @@ static int __pdflush(struct pdflush_work *my_work) spin_unlock_irq(&pdflush_lock); (*my_work->fn)(my_work->arg0); + + try_to_clip_inodes(); /* * Thread creation: For how long have there been zero diff --git a/mm/proc_mm.c b/mm/proc_mm.c new file mode 100644 index 000000000..5ceb506af --- /dev/null +++ b/mm/proc_mm.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/init.h" +#include "linux/proc_fs.h" +#include "linux/proc_mm.h" +#include "linux/file.h" +#include "asm/uaccess.h" +#include "asm/mmu_context.h" + +static struct file_operations proc_mm_fops; + +struct mm_struct *proc_mm_get_mm(int fd) +{ + struct mm_struct *ret = ERR_PTR(-EBADF); + struct file *file; + + file = fget(fd); + if (!file) + goto out; + + ret = ERR_PTR(-EINVAL); + if(file->f_op != &proc_mm_fops) + goto out_fput; + + ret = file->private_data; + out_fput: + fput(file); + out: + return(ret); +} + +extern long do_mmap2(struct mm_struct *mm, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long pgoff); + +static ssize_t write_proc_mm(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + struct mm_struct *mm = file->private_data; + struct proc_mm_op req; + int n, ret; + + if(count > sizeof(req)) + return(-EINVAL); + + n = copy_from_user(&req, buffer, count); + if(n != 0) + return(-EFAULT); + + ret = count; + switch(req.op){ + case MM_MMAP: { + struct mm_mmap *map = &req.u.mmap; + + ret = do_mmap2(mm, map->addr, map->len, map->prot, + map->flags, map->fd, map->offset >> PAGE_SHIFT); + if((ret & ~PAGE_MASK) == 0) + ret = count; + + break; + } + case MM_MUNMAP: { + struct mm_munmap *unmap = &req.u.munmap; + + down_write(&mm->mmap_sem); + ret = do_munmap(mm, unmap->addr, unmap->len); + up_write(&mm->mmap_sem); + + if(ret == 0) + ret = count; + break; + } + case MM_MPROTECT: { + struct mm_mprotect *protect = &req.u.mprotect; + + ret = do_mprotect(mm, protect->addr, protect->len, + protect->prot); + if(ret == 0) + ret = count; + break; + } + + case MM_COPY_SEGMENTS: { + struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments); + + if(IS_ERR(from)){ + ret = PTR_ERR(from); + break; + } + + mm_copy_segments(from, mm); + break; + } + default: + ret = -EINVAL; + break; + } + + return(ret); +} + +static int open_proc_mm(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = mm_alloc(); + int ret; + + ret = -ENOMEM; + if(mm == NULL) + goto out_mem; + + ret = init_new_context(current, mm); + if(ret) + goto out_free; + + spin_lock(&mmlist_lock); + list_add(&mm->mmlist, ¤t->mm->mmlist); + mmlist_nr++; + spin_unlock(&mmlist_lock); + + file->private_data = mm; + + return(0); + + out_free: + mmput(mm); + out_mem: + return(ret); +} + +static int release_proc_mm(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = file->private_data; + + mmput(mm); + return(0); +} + +static struct file_operations proc_mm_fops = { + .open = open_proc_mm, + .release = release_proc_mm, + .write = write_proc_mm, +}; + +static int make_proc_mm(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_entry("mm", 0222, &proc_root); + if(ent == NULL){ + printk("make_proc_mm : Failed to register /proc/mm\n"); + return(0); + } + ent->proc_fops = &proc_mm_fops; + + return(0); +} + +__initcall(make_proc_mm); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/mm/rmap.c b/mm/rmap.c index 1f3c84f8c..da85d34f4 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -193,7 +193,7 @@ vma_address(struct page *page, struct vm_area_struct *vma) * repeatedly from either page_referenced_anon or page_referenced_file. */ static int page_referenced_one(struct page *page, - struct vm_area_struct *vma, unsigned int *mapcount) + struct vm_area_struct *vma, unsigned int *mapcount, int *failed) { struct mm_struct *mm = vma->vm_mm; unsigned long address; @@ -208,8 +208,14 @@ static int page_referenced_one(struct page *page, if (address == -EFAULT) goto out; - if (!spin_trylock(&mm->page_table_lock)) + if (!spin_trylock(&mm->page_table_lock)) { + /* + * For debug we're currently warning if not all found, + * but in this case that's expected: suppress warning. + */ + (*failed)++; goto out; + } pgd = pgd_offset(mm, address); if (!pgd_present(*pgd)) @@ -245,14 +251,18 @@ static inline int page_referenced_anon(struct page *page) struct anon_vma *anon_vma = (struct anon_vma *) page->mapping; struct vm_area_struct *vma; int referenced = 0; + int failed = 0; spin_lock(&anon_vma->lock); BUG_ON(list_empty(&anon_vma->head)); list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { - referenced += page_referenced_one(page, vma, &mapcount); + referenced += page_referenced_one(page, vma, + &mapcount, &failed); if (!mapcount) - break; + goto out; } + WARN_ON(!failed); +out: spin_unlock(&anon_vma->lock); return referenced; } @@ -279,6 +289,7 @@ static inline int page_referenced_file(struct page *page) struct vm_area_struct *vma = NULL; struct prio_tree_iter iter; int referenced = 0; + int failed = 0; if (!spin_trylock(&mapping->i_mmap_lock)) return 0; @@ -288,13 +299,17 @@ static inline int page_referenced_file(struct page *page) if ((vma->vm_flags & (VM_LOCKED|VM_MAYSHARE)) == (VM_LOCKED|VM_MAYSHARE)) { referenced++; - break; + goto out; } - referenced += page_referenced_one(page, vma, &mapcount); + referenced += page_referenced_one(page, vma, + &mapcount, &failed); if (!mapcount) - break; + goto out; } + if (list_empty(&mapping->i_mmap_nonlinear)) + WARN_ON(!failed); +out: spin_unlock(&mapping->i_mmap_lock); return referenced; } @@ -470,23 +485,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) goto out_unmap; } - /* - * Don't pull an anonymous page out from under get_user_pages. - * GUP carefully breaks COW and raises page count (while holding - * page_table_lock, as we have here) to make sure that the page - * cannot be freed. If we unmap that page here, a user write - * access to the virtual address will bring back the page, but - * its raised count will (ironically) be taken to mean it's not - * an exclusive swap page, do_wp_page will replace it by a copy - * page, and the user never get to see the data GUP was holding - * the original page for. - */ - if (PageSwapCache(page) && - page_count(page) != page->mapcount + 2) { - ret = SWAP_FAIL; - goto out_unmap; - } - /* Nuke the page table entry. */ flush_cache_page(vma, address); pteval = ptep_clear_flush(vma, address, pte); @@ -507,7 +505,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) BUG_ON(pte_file(*pte)); } - mm->rss--; + // mm->rss--; + vx_rsspages_dec(mm); BUG_ON(!page->mapcount); page->mapcount--; page_cache_release(page); diff --git a/mm/shmem.c b/mm/shmem.c index 5a6d56a45..ada4f735c 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1161,17 +1161,36 @@ shmem_get_policy(struct vm_area_struct *vma, unsigned long addr) } #endif -void shmem_lock(struct file *file, int lock) +int shmem_lock(struct file *file, int lock) { struct inode *inode = file->f_dentry->d_inode; struct shmem_inode_info *info = SHMEM_I(inode); + struct mm_struct *mm = current->mm; + unsigned long lock_limit, locked; + int retval = -ENOMEM; spin_lock(&info->lock); + if (lock && !(info->flags & VM_LOCKED)) { + locked = inode->i_size >> PAGE_SHIFT; + locked += mm->locked_vm; + lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; + lock_limit >>= PAGE_SHIFT; + if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) + goto out_nomem; + mm->locked_vm = locked; + } + if (!lock && (info->flags & VM_LOCKED) && mm) { + locked = inode->i_size >> PAGE_SHIFT; + mm->locked_vm -= locked; + } if (lock) info->flags |= VM_LOCKED; else info->flags &= ~VM_LOCKED; + retval = 0; +out_nomem: spin_unlock(&info->lock); + return retval; } static int shmem_mmap(struct file *file, struct vm_area_struct *vma) @@ -1676,51 +1695,45 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s return 0; } -static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen) -{ - return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode)); -} - static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) { - return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode)); + nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode)); + return 0; } -static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen) +static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page = NULL; int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL); - if (res) - return res; - res = vfs_readlink(dentry, buffer, buflen, kmap(page)); - kunmap(page); - mark_page_accessed(page); - page_cache_release(page); - return res; + nd_set_link(nd, res ? ERR_PTR(res) : kmap(page)); + return 0; } -static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd) +static void shmem_put_link(struct dentry *dentry, struct nameidata *nd) { - struct page *page = NULL; - int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL); - if (res) - return res; - res = vfs_follow_link(nd, kmap(page)); - kunmap(page); - mark_page_accessed(page); - page_cache_release(page); - return res; + if (!IS_ERR(nd_get_link(nd))) { + struct page *page; + + page = find_get_page(dentry->d_inode->i_mapping, 0); + if (!page) + BUG(); + kunmap(page); + mark_page_accessed(page); + page_cache_release(page); + page_cache_release(page); + } } static struct inode_operations shmem_symlink_inline_operations = { - .readlink = shmem_readlink_inline, + .readlink = generic_readlink, .follow_link = shmem_follow_link_inline, }; static struct inode_operations shmem_symlink_inode_operations = { .truncate = shmem_truncate, - .readlink = shmem_readlink, + .readlink = generic_readlink, .follow_link = shmem_follow_link, + .put_link = shmem_put_link, }; static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes) diff --git a/mm/slab.c b/mm/slab.c index 45c5c0549..4f6ba9021 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1347,10 +1347,13 @@ next: * the cache that's used by kmalloc(24), otherwise * the creation of further caches will BUG(). */ - cachep->array[smp_processor_id()] = &initarray_generic.cache; + cachep->array[smp_processor_id()] = + &initarray_generic.cache; g_cpucache_up = PARTIAL; } else { - cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL); + cachep->array[smp_processor_id()] = + kmalloc(sizeof(struct arraycache_init), + GFP_KERNEL); } BUG_ON(!ac_data(cachep)); ac_data(cachep)->avail = 0; @@ -1364,7 +1367,7 @@ next: } cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; /* Need the semaphore to access the chain. */ down(&cache_chain_sem); @@ -1377,16 +1380,24 @@ next: list_for_each(p, &cache_chain) { kmem_cache_t *pc = list_entry(p, kmem_cache_t, next); char tmp; - /* This happens when the module gets unloaded and doesn't - destroy its slab cache and noone else reuses the vmalloc - area of the module. Print a warning. */ - if (__get_user(tmp,pc->name)) { - printk("SLAB: cache with size %d has lost its name\n", - pc->objsize); + + /* + * This happens when the module gets unloaded and + * doesn't destroy its slab cache and noone else reuses + * the vmalloc area of the module. Print a warning. + */ +#ifdef CONFIG_X86_UACCESS_INDIRECT + if (__direct_get_user(tmp,pc->name)) { +#else + if (__get_user(tmp,pc->name)) { +#endif + printk("SLAB: cache with size %d has lost its " + "name\n", pc->objsize); continue; } if (!strcmp(pc->name,name)) { - printk("kmem_cache_create: duplicate cache %s\n",name); + printk("kmem_cache_create: duplicate " + "cache %s\n",name); up(&cache_chain_sem); unlock_cpu_hotplug(); BUG(); diff --git a/mm/swap_state.c b/mm/swap_state.c index 571713576..6dd082556 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -6,7 +6,7 @@ * * Rewritten to use page cache, (C) 1998 Stephen Tweedie */ -#include + #include #include #include @@ -19,8 +19,7 @@ /* * swapper_space is a fiction, retained to simplify the path through - * vmscan's shrink_list, to make sync_page look nicer, and to allow - * future use of radix_tree tags in the swap cache. + * vmscan's shrink_list. Only those fields initialized below are used. */ static struct address_space_operations swap_aops = { .writepage = swap_writepage, @@ -37,10 +36,8 @@ struct address_space swapper_space = { .page_tree = RADIX_TREE_INIT(GFP_ATOMIC), .tree_lock = SPIN_LOCK_UNLOCKED, .a_ops = &swap_aops, - .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), .backing_dev_info = &swap_backing_dev_info, }; -EXPORT_SYMBOL(swapper_space); #define INC_CACHE_INFO(x) do { swap_cache_info.x++; } while (0) diff --git a/mm/swapfile.c b/mm/swapfile.c index 2eabfd19a..fc9b47d83 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -430,7 +430,8 @@ static void unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir, swp_entry_t entry, struct page *page) { - vma->vm_mm->rss++; + // vma->vm_mm->rss++; + vx_rsspages_inc(vma->vm_mm); get_page(page); set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); page_add_anon_rmap(page, vma, address); @@ -1573,6 +1574,8 @@ void si_swapinfo(struct sysinfo *val) val->freeswap = nr_swap_pages + nr_to_be_unused; val->totalswap = total_swap_pages + nr_to_be_unused; swap_list_unlock(); + if (vx_flags(VXF_VIRT_MEM, 0)) + vx_vsi_swapinfo(val); } /* diff --git a/mm/usercopy.c b/mm/usercopy.c new file mode 100644 index 000000000..a22b81fab --- /dev/null +++ b/mm/usercopy.c @@ -0,0 +1,302 @@ +/* + * linux/mm/usercopy.c + * + * (C) Copyright 2003 Ingo Molnar + * + * Generic implementation of all the user-VM access functions, without + * relying on being able to access the VM directly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Get kernel address of the user page and pin it. + */ +static inline struct page *pin_page(unsigned long addr, int write, + unsigned long *pfn) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page = NULL; + int ret; + + /* + * Do a quick atomic lookup first - this is the fastpath. + */ +retry: + page = follow_page_pfn(mm, addr, write, pfn); + if (likely(page != NULL)) { + if (!PageReserved(page)) + get_page(page); + return page; + } + if (*pfn) + return NULL; + /* + * No luck - bad address or need to fault in the page: + */ + + /* Release the lock so get_user_pages can sleep */ + spin_unlock(&mm->page_table_lock); + + /* + * In the context of filemap_copy_from_user(), we are not allowed + * to sleep. We must fail this usercopy attempt and allow + * filemap_copy_from_user() to recover: drop its atomic kmap and use + * a sleeping kmap instead. + */ + if (in_atomic()) { + spin_lock(&mm->page_table_lock); + return NULL; + } + + down_read(&mm->mmap_sem); + ret = get_user_pages(current, mm, addr, 1, write, 0, NULL, NULL); + up_read(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + + if (ret <= 0) + return NULL; + + /* + * Go try the follow_page again. + */ + goto retry; +} + +static inline void unpin_page(struct page *page) +{ + put_page(page); +} + +/* + * Access another process' address space. + * Source/target buffer must be kernel space, + * Do not walk the page table directly, use get_user_pages + */ +static int rw_vm(unsigned long addr, void *buf, int len, int write) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + + if (!len) + return 0; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + struct page *page = NULL; + unsigned long pfn = 0; + int bytes, offset; + void *maddr; + + page = pin_page(addr, write, &pfn); + if (!page && !pfn) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + if (page) + maddr = kmap_atomic(page, KM_USER_COPY); + else + maddr = kmap_atomic_nocache_pfn(pfn, KM_USER_COPY); + +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break; + + if (write) { + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(maddr + offset, buf, bytes); + } + } else { +#undef HANDLE_TYPE +#define HANDLE_TYPE(type) \ + case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break; + switch (bytes) { + HANDLE_TYPE(char); + HANDLE_TYPE(int); + HANDLE_TYPE(long long); + default: + memcpy(buf, maddr + offset, bytes); + } +#undef HANDLE_TYPE + } + kunmap_atomic(maddr, KM_USER_COPY); + if (page) + unpin_page(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +static int str_vm(unsigned long addr, void *buf0, int len, int copy) +{ + struct mm_struct *mm = current->mm ? : &init_mm; + struct page *page; + void *buf = buf0; + + if (!len) + return len; + + spin_lock(&mm->page_table_lock); + + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, offset, left, copied; + unsigned long pfn = 0; + char *maddr; + + page = pin_page(addr, copy == 2, &pfn); + if (!page && !pfn) { + spin_unlock(&mm->page_table_lock); + return -EFAULT; + } + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + if (page) + maddr = kmap_atomic(page, KM_USER_COPY); + else + maddr = kmap_atomic_nocache_pfn(pfn, KM_USER_COPY); + if (copy == 2) { + memset(maddr + offset, 0, bytes); + copied = bytes; + left = 0; + } else if (copy == 1) { + left = strncpy_count(buf, maddr + offset, bytes); + copied = bytes - left; + } else { + copied = strnlen(maddr + offset, bytes); + left = bytes - copied; + } + BUG_ON(bytes < 0 || copied < 0); + kunmap_atomic(maddr, KM_USER_COPY); + if (page) + unpin_page(page); + len -= copied; + buf += copied; + addr += copied; + if (left) + break; + } + spin_unlock(&mm->page_table_lock); + + return len; +} + +/* + * Copies memory from userspace (ptr) into kernelspace (val). + * + * returns # of bytes not copied. + */ +int get_user_size(unsigned int size, void *val, const void *ptr) +{ + int ret; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + ret = __direct_copy_from_user(val, ptr, size); + else + ret = rw_vm((unsigned long)ptr, val, size, 0); + if (ret) + /* + * Zero the rest: + */ + memset(val + size - ret, 0, ret); + return ret; +} + +/* + * Copies memory from kernelspace (val) into userspace (ptr). + * + * returns # of bytes not copied. + */ +int put_user_size(unsigned int size, const void *val, void *ptr) +{ + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return __direct_copy_to_user(ptr, val, size); + else + return rw_vm((unsigned long)ptr, (void *)val, size, 1); +} + +int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + left = strncpy_count(val, ptr, size); + copied = size - left; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, val, size, 1); + if (left < 0) + return left; + copied = size - left; + BUG_ON(copied < 0); + + return copied; +} + +int strlen_fromuser_size(unsigned int size, const void *ptr) +{ + int copied, left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + copied = strnlen(ptr, size) + 1; + BUG_ON(copied < 0); + + return copied; + } + left = str_vm((unsigned long)ptr, NULL, size, 0); + if (left < 0) + return 0; + copied = size - left + 1; + BUG_ON(copied < 0); + + return copied; +} + +int zero_user_size(unsigned int size, void *ptr) +{ + int left; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + memset(ptr, 0, size); + return 0; + } + left = str_vm((unsigned long)ptr, NULL, size, 2); + if (left < 0) + return size; + return left; +} + +EXPORT_SYMBOL(get_user_size); +EXPORT_SYMBOL(put_user_size); +EXPORT_SYMBOL(zero_user_size); +EXPORT_SYMBOL(copy_str_fromuser_size); +EXPORT_SYMBOL(strlen_fromuser_size); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 16e6f88c2..27400b9ed 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -455,6 +455,28 @@ void *vmalloc(unsigned long size) EXPORT_SYMBOL(vmalloc); +/** + * vmalloc_exec - allocate virtually contiguous, executable memory + * + * @size: allocation size + * + * Kernel-internal function to allocate enough pages to cover @size + * the page level allocator and map them into contiguous and + * executable kernel virtual space. + * + * For tight cotrol over page level allocator and protection flags + * use __vmalloc() instead. + */ + +#ifndef PAGE_KERNEL_EXEC +# define PAGE_KERNEL_EXEC PAGE_KERNEL +#endif + +void *vmalloc_exec(unsigned long size) +{ + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC); +} + /** * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) * diff --git a/mm/vmscan.c b/mm/vmscan.c index e5f0b0919..da9e1853e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -45,6 +45,11 @@ int vm_swappiness = 60; static long total_memory; + + +void try_to_clip_inodes(void); + + #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) #ifdef ARCH_HAS_PREFETCH @@ -240,107 +245,17 @@ static void handle_write_error(struct address_space *mapping, unlock_page(page); } -/* possible outcome of pageout() */ -typedef enum { - /* failed to write page out, page is locked */ - PAGE_KEEP, - /* move page to the active list, page is locked */ - PAGE_ACTIVATE, - /* page has been sent to the disk successfully, page is unlocked */ - PAGE_SUCCESS, - /* page is clean and locked */ - PAGE_CLEAN, -} pageout_t; - /* - * pageout is called by shrink_list() for each dirty page. Calls ->writepage(). + * shrink_list returns the number of reclaimed pages */ -static pageout_t pageout(struct page *page, struct address_space *mapping) -{ - /* - * If the page is dirty, only perform writeback if that write - * will be non-blocking. To prevent this allocation from being - * stalled by pagecache activity. But note that there may be - * stalls if we need to run get_block(). We could test - * PagePrivate for that. - * - * If this process is currently in generic_file_write() against - * this page's queue, we can perform writeback even if that - * will block. - * - * If the page is swapcache, write it back even if that would - * block, for some throttling. This happens by accident, because - * swap_backing_dev_info is bust: it doesn't reflect the - * congestion state of the swapdevs. Easy to fix, if needed. - * See swapfile.c:page_queue_congested(). - */ - if (!is_page_cache_freeable(page)) - return PAGE_KEEP; - if (!mapping) - return PAGE_KEEP; - if (mapping->a_ops->writepage == NULL) - return PAGE_ACTIVATE; - if (!may_write_to_queue(mapping->backing_dev_info)) - return PAGE_KEEP; - - if (clear_page_dirty_for_io(page)) { - int res; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_NONE, - .nr_to_write = SWAP_CLUSTER_MAX, - .nonblocking = 1, - .for_reclaim = 1, - }; - - SetPageReclaim(page); - res = mapping->a_ops->writepage(page, &wbc); - if (res < 0) - handle_write_error(mapping, page, res); - if (res == WRITEPAGE_ACTIVATE) { - ClearPageReclaim(page); - return PAGE_ACTIVATE; - } - if (!PageWriteback(page)) { - /* synchronous write or broken a_ops? */ - ClearPageReclaim(page); - } - - return PAGE_SUCCESS; - } - - return PAGE_CLEAN; -} - -struct scan_control { - /* Ask refill_inactive_zone, or shrink_cache to scan this many pages */ - unsigned long nr_to_scan; - - /* Incremented by the number of inactive pages that were scanned */ - unsigned long nr_scanned; - - /* Incremented by the number of pages reclaimed */ - unsigned long nr_reclaimed; - - unsigned long nr_mapped; /* From page_state */ - - /* Ask shrink_caches, or shrink_zone to scan at this priority */ - unsigned int priority; - - /* This context's GFP mask */ - unsigned int gfp_mask; - - int may_writepage; -}; - -/* - * shrink_list adds the number of reclaimed pages to sc->nr_reclaimed - */ -static int shrink_list(struct list_head *page_list, struct scan_control *sc) +static int +shrink_list(struct list_head *page_list, unsigned int gfp_mask, + int *nr_scanned, int do_writepage) { LIST_HEAD(ret_pages); struct pagevec freed_pvec; int pgactivate = 0; - int reclaimed = 0; + int ret = 0; cond_resched(); @@ -357,16 +272,15 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) if (TestSetPageLocked(page)) goto keep; + /* Double the slab pressure for mapped and swapcache pages */ + if (page_mapped(page) || PageSwapCache(page)) + (*nr_scanned)++; + BUG_ON(PageActive(page)); if (PageWriteback(page)) goto keep_locked; - sc->nr_scanned++; - /* Double the slab pressure for mapped and swapcache pages */ - if (page_mapped(page) || PageSwapCache(page)) - sc->nr_scanned++; - page_map_lock(page); referenced = page_referenced(page); if (referenced && page_mapping_inuse(page)) { @@ -391,8 +305,8 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) #endif /* CONFIG_SWAP */ mapping = page_mapping(page); - may_enter_fs = (sc->gfp_mask & __GFP_FS) || - (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); + may_enter_fs = (gfp_mask & __GFP_FS) || + (PageSwapCache(page) && (gfp_mask & __GFP_IO)); /* * The page is mapped into the page tables of one or more @@ -412,34 +326,60 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) } page_map_unlock(page); + /* + * If the page is dirty, only perform writeback if that write + * will be non-blocking. To prevent this allocation from being + * stalled by pagecache activity. But note that there may be + * stalls if we need to run get_block(). We could test + * PagePrivate for that. + * + * If this process is currently in generic_file_write() against + * this page's queue, we can perform writeback even if that + * will block. + * + * If the page is swapcache, write it back even if that would + * block, for some throttling. This happens by accident, because + * swap_backing_dev_info is bust: it doesn't reflect the + * congestion state of the swapdevs. Easy to fix, if needed. + * See swapfile.c:page_queue_congested(). + */ if (PageDirty(page)) { if (referenced) goto keep_locked; + if (!is_page_cache_freeable(page)) + goto keep_locked; + if (!mapping) + goto keep_locked; + if (mapping->a_ops->writepage == NULL) + goto activate_locked; if (!may_enter_fs) goto keep_locked; - if (laptop_mode && !sc->may_writepage) + if (!may_write_to_queue(mapping->backing_dev_info)) goto keep_locked; - - /* Page is dirty, try to write it out here */ - switch(pageout(page, mapping)) { - case PAGE_KEEP: + if (laptop_mode && !do_writepage) goto keep_locked; - case PAGE_ACTIVATE: - goto activate_locked; - case PAGE_SUCCESS: - if (PageWriteback(page) || PageDirty(page)) - goto keep; - /* - * A synchronous write - probably a ramdisk. Go - * ahead and try to reclaim the page. - */ - if (TestSetPageLocked(page)) - goto keep; - if (PageDirty(page) || PageWriteback(page)) - goto keep_locked; - mapping = page_mapping(page); - case PAGE_CLEAN: - ; /* try to free the page below */ + if (clear_page_dirty_for_io(page)) { + int res; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = SWAP_CLUSTER_MAX, + .nonblocking = 1, + .for_reclaim = 1, + }; + + SetPageReclaim(page); + res = mapping->a_ops->writepage(page, &wbc); + if (res < 0) + handle_write_error(mapping, page, res); + if (res == WRITEPAGE_ACTIVATE) { + ClearPageReclaim(page); + goto activate_locked; + } + if (!PageWriteback(page)) { + /* synchronous write or broken a_ops? */ + ClearPageReclaim(page); + } + goto keep; } } @@ -461,11 +401,11 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) * the pages which were not successfully invalidated in * truncate_complete_page(). We try to drop those buffers here * and if that worked, and the page is no longer mapped into - * process address space (page_count == 1) it can be freed. + * process address space (page_count == 0) it can be freed. * Otherwise, leave the page on the LRU so it is swappable. */ if (PagePrivate(page)) { - if (!try_to_release_page(page, sc->gfp_mask)) + if (!try_to_release_page(page, gfp_mask)) goto activate_locked; if (!mapping && page_count(page) == 1) goto free_it; @@ -503,7 +443,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) free_it: unlock_page(page); - reclaimed++; + ret++; if (!pagevec_add(&freed_pvec, page)) __pagevec_release_nonlru(&freed_pvec); continue; @@ -521,8 +461,7 @@ keep: if (pagevec_count(&freed_pvec)) __pagevec_release_nonlru(&freed_pvec); mod_page_state(pgactivate, pgactivate); - sc->nr_reclaimed += reclaimed; - return reclaimed; + return ret; } /* @@ -530,16 +469,19 @@ keep: * a batch of pages and working on them outside the lock. Any pages which were * not freed will be added back to the LRU. * - * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed + * shrink_cache() is passed the number of pages to scan and returns the number + * of pages which were reclaimed. * * For pagecache intensive workloads, the first loop here is the hottest spot * in the kernel (apart from the copy_*_user functions). */ -static void shrink_cache(struct zone *zone, struct scan_control *sc) +static int +shrink_cache(struct zone *zone, unsigned int gfp_mask, + int max_scan, int *total_scanned, int do_writepage) { LIST_HEAD(page_list); struct pagevec pvec; - int max_scan = sc->nr_to_scan; + int ret = 0; pagevec_init(&pvec, 1); @@ -585,11 +527,17 @@ static void shrink_cache(struct zone *zone, struct scan_control *sc) mod_page_state_zone(zone, pgscan_kswapd, nr_scan); else mod_page_state_zone(zone, pgscan_direct, nr_scan); - nr_freed = shrink_list(&page_list, sc); + nr_freed = shrink_list(&page_list, gfp_mask, + total_scanned, do_writepage); + *total_scanned += nr_taken; if (current_is_kswapd()) mod_page_state(kswapd_steal, nr_freed); mod_page_state_zone(zone, pgsteal, nr_freed); + ret += nr_freed; + if (nr_freed <= 0 && list_empty(&page_list)) + goto done; + spin_lock_irq(&zone->lru_lock); /* * Put back any unfreeable pages. @@ -613,6 +561,7 @@ static void shrink_cache(struct zone *zone, struct scan_control *sc) spin_unlock_irq(&zone->lru_lock); done: pagevec_release(&pvec); + return ret; } /* @@ -633,12 +582,12 @@ done: * But we had to alter page->flags anyway. */ static void -refill_inactive_zone(struct zone *zone, struct scan_control *sc) +refill_inactive_zone(struct zone *zone, const int nr_pages_in, + struct page_state *ps) { int pgmoved; int pgdeactivate = 0; - int pgscanned = 0; - int nr_pages = sc->nr_to_scan; + int nr_pages = nr_pages_in; LIST_HEAD(l_hold); /* The pages which were snipped off */ LIST_HEAD(l_inactive); /* Pages to go onto the inactive_list */ LIST_HEAD(l_active); /* Pages to go onto the active_list */ @@ -652,7 +601,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc) lru_add_drain(); pgmoved = 0; spin_lock_irq(&zone->lru_lock); - while (pgscanned < nr_pages && !list_empty(&zone->active_list)) { + while (nr_pages && !list_empty(&zone->active_list)) { page = lru_to_page(&zone->active_list); prefetchw_prev_lru_page(page, &zone->active_list, flags); if (!TestClearPageLRU(page)) @@ -672,7 +621,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc) list_add(&page->lru, &l_hold); pgmoved++; } - pgscanned++; + nr_pages--; } zone->nr_active -= pgmoved; spin_unlock_irq(&zone->lru_lock); @@ -688,7 +637,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc) * mapped memory instead of just pagecache. Work out how much memory * is mapped. */ - mapped_ratio = (sc->nr_mapped * 100) / total_memory; + mapped_ratio = (ps->nr_mapped * 100) / total_memory; /* * Now decide how much we really want to unmap some pages. The mapped @@ -787,7 +736,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc) spin_unlock_irq(&zone->lru_lock); pagevec_release(&pvec); - mod_page_state_zone(zone, pgrefill, pgscanned); + mod_page_state_zone(zone, pgrefill, nr_pages_in - nr_pages); mod_page_state(pgdeactivate, pgdeactivate); } @@ -795,14 +744,13 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc) * Scan `nr_pages' from this zone. Returns the number of reclaimed pages. * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. */ -static void -shrink_zone(struct zone *zone, struct scan_control *sc) +static int +shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, + int *total_scanned, struct page_state *ps, int do_writepage) { - unsigned long scan_active, scan_inactive; + unsigned long scan_active; int count; - scan_inactive = (zone->nr_active + zone->nr_inactive) >> sc->priority; - /* * Try to keep the active list 2/3 of the size of the cache. And * make sure that refill_inactive is given a decent number of pages. @@ -815,13 +763,13 @@ shrink_zone(struct zone *zone, struct scan_control *sc) */ if (zone->nr_active >= 4*(zone->nr_inactive*2 + 1)) { /* Don't scan more than 4 times the inactive list scan size */ - scan_active = 4*scan_inactive; + scan_active = 4*max_scan; } else { unsigned long long tmp; /* Cast to long long so the multiply doesn't overflow */ - tmp = (unsigned long long)scan_inactive * zone->nr_active; + tmp = (unsigned long long)max_scan * zone->nr_active; do_div(tmp, zone->nr_inactive*2 + 1); scan_active = (unsigned long)tmp; } @@ -830,17 +778,17 @@ shrink_zone(struct zone *zone, struct scan_control *sc) count = atomic_read(&zone->nr_scan_active); if (count >= SWAP_CLUSTER_MAX) { atomic_set(&zone->nr_scan_active, 0); - sc->nr_to_scan = count; - refill_inactive_zone(zone, sc); + refill_inactive_zone(zone, count, ps); } - atomic_add(scan_inactive, &zone->nr_scan_inactive); + atomic_add(max_scan, &zone->nr_scan_inactive); count = atomic_read(&zone->nr_scan_inactive); if (count >= SWAP_CLUSTER_MAX) { atomic_set(&zone->nr_scan_inactive, 0); - sc->nr_to_scan = count; - shrink_cache(zone, sc); + return shrink_cache(zone, gfp_mask, count, + total_scanned, do_writepage); } + return 0; } /* @@ -859,23 +807,28 @@ shrink_zone(struct zone *zone, struct scan_control *sc) * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ -static void -shrink_caches(struct zone **zones, struct scan_control *sc) +static int +shrink_caches(struct zone **zones, int priority, int *total_scanned, + int gfp_mask, struct page_state *ps, int do_writepage) { + int ret = 0; int i; for (i = 0; zones[i] != NULL; i++) { struct zone *zone = zones[i]; + int max_scan; - zone->temp_priority = sc->priority; - if (zone->prev_priority > sc->priority) - zone->prev_priority = sc->priority; + if (zone->free_pages < zone->pages_high) + zone->temp_priority = priority; - if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY) + if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; /* Let kswapd poll it */ - shrink_zone(zone, sc); + max_scan = (zone->nr_active + zone->nr_inactive) >> priority; + ret += shrink_zone(zone, max_scan, gfp_mask, + total_scanned, ps, do_writepage); } + return ret; } /* @@ -886,23 +839,25 @@ shrink_caches(struct zone **zones, struct scan_control *sc) * * If the caller is !__GFP_FS then the probability of a failure is reasonably * high - the zone may be full of dirty or under-writeback pages, which this - * caller can't do much about. We kick pdflush and take explicit naps in the - * hope that some of these pages can be written. But if the allocating task - * holds filesystem locks which prevent writeout this might not work, and the - * allocation attempt will fail. + * caller can't do much about. So for !__GFP_FS callers, we just perform a + * small LRU walk and if that didn't work out, fail the allocation back to the + * caller. GFP_NOFS allocators need to know how to deal with it. Kicking + * bdflush, waiting and retrying will work. + * + * This is a fairly lame algorithm - it can result in excessive CPU burning and + * excessive rotation of the inactive list, which is _supposed_ to be an LRU, + * yes? */ int try_to_free_pages(struct zone **zones, unsigned int gfp_mask, unsigned int order) { int priority; int ret = 0; - int total_scanned = 0, total_reclaimed = 0; + int nr_reclaimed = 0; struct reclaim_state *reclaim_state = current->reclaim_state; - struct scan_control sc; int i; - - sc.gfp_mask = gfp_mask; - sc.may_writepage = 0; + unsigned long total_scanned = 0; + int do_writepage = 0; inc_page_state(allocstall); @@ -910,23 +865,23 @@ int try_to_free_pages(struct zone **zones, zones[i]->temp_priority = DEF_PRIORITY; for (priority = DEF_PRIORITY; priority >= 0; priority--) { - sc.nr_mapped = read_page_state(nr_mapped); - sc.nr_scanned = 0; - sc.nr_reclaimed = 0; - sc.priority = priority; - shrink_caches(zones, &sc); - shrink_slab(sc.nr_scanned, gfp_mask); + int scanned = 0; + struct page_state ps; + + get_page_state(&ps); + nr_reclaimed += shrink_caches(zones, priority, &scanned, + gfp_mask, &ps, do_writepage); + shrink_slab(scanned, gfp_mask); if (reclaim_state) { - sc.nr_reclaimed += reclaim_state->reclaimed_slab; + nr_reclaimed += reclaim_state->reclaimed_slab; reclaim_state->reclaimed_slab = 0; } - if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX) { + if (nr_reclaimed >= SWAP_CLUSTER_MAX) { ret = 1; goto out; } - total_scanned += sc.nr_scanned; - total_reclaimed += sc.nr_reclaimed; - + if (!(gfp_mask & __GFP_FS)) + break; /* Let the caller handle it */ /* * Try to write back as many pages as we just scanned. This * tends to cause slow streaming writers to write data to the @@ -934,13 +889,14 @@ int try_to_free_pages(struct zone **zones, * that's undesirable in laptop mode, where we *want* lumpy * writeout. So in laptop mode, write out the whole world. */ + total_scanned += scanned; if (total_scanned > SWAP_CLUSTER_MAX + SWAP_CLUSTER_MAX/2) { wakeup_bdflush(laptop_mode ? 0 : total_scanned); - sc.may_writepage = 1; + do_writepage = 1; } /* Take a nap, wait for some writeback to complete */ - if (sc.nr_scanned && priority < DEF_PRIORITY - 2) + if (scanned && priority < DEF_PRIORITY - 2) blk_congestion_wait(WRITE, HZ/10); } if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) @@ -976,18 +932,15 @@ out: * the page allocator fallback scheme to ensure that aging of pages is balanced * across the zones. */ -static int balance_pgdat(pg_data_t *pgdat, int nr_pages) +static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps) { int to_free = nr_pages; int priority; int i; - int total_scanned = 0, total_reclaimed = 0; struct reclaim_state *reclaim_state = current->reclaim_state; - struct scan_control sc; - - sc.gfp_mask = GFP_KERNEL; - sc.may_writepage = 0; - sc.nr_mapped = read_page_state(nr_mapped); + unsigned long total_scanned = 0; + unsigned long total_reclaimed = 0; + int do_writepage = 0; inc_page_state(pageoutrun); @@ -997,7 +950,7 @@ static int balance_pgdat(pg_data_t *pgdat, int nr_pages) zone->temp_priority = DEF_PRIORITY; } - for (priority = DEF_PRIORITY; priority >= 0; priority--) { + for (priority = DEF_PRIORITY; priority; priority--) { int all_zones_ok = 1; int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */ @@ -1035,6 +988,9 @@ scan: */ for (i = 0; i <= end_zone; i++) { struct zone *zone = pgdat->node_zones + i; + int max_scan; + int reclaimed; + int scanned = 0; if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; @@ -1044,16 +1000,16 @@ scan: all_zones_ok = 0; } zone->temp_priority = priority; - if (zone->prev_priority > priority) - zone->prev_priority = priority; - sc.nr_scanned = 0; - sc.nr_reclaimed = 0; - sc.priority = priority; - shrink_zone(zone, &sc); + max_scan = (zone->nr_active + zone->nr_inactive) + >> priority; + reclaimed = shrink_zone(zone, max_scan, GFP_KERNEL, + &scanned, ps, do_writepage); + total_scanned += scanned; reclaim_state->reclaimed_slab = 0; - shrink_slab(sc.nr_scanned, GFP_KERNEL); - sc.nr_reclaimed += reclaim_state->reclaimed_slab; - total_reclaimed += sc.nr_reclaimed; + shrink_slab(scanned, GFP_KERNEL); + reclaimed += reclaim_state->reclaimed_slab; + total_reclaimed += reclaimed; + to_free -= reclaimed; if (zone->all_unreclaimable) continue; if (zone->pages_scanned > zone->present_pages * 2) @@ -1065,9 +1021,9 @@ scan: */ if (total_scanned > SWAP_CLUSTER_MAX * 2 && total_scanned > total_reclaimed+total_reclaimed/2) - sc.may_writepage = 1; + do_writepage = 1; } - if (nr_pages && to_free > total_reclaimed) + if (nr_pages && to_free > 0) continue; /* swsusp: need to do more work */ if (all_zones_ok) break; /* kswapd: all done */ @@ -1131,13 +1087,16 @@ int kswapd(void *p) tsk->flags |= PF_MEMALLOC|PF_KSWAPD; for ( ; ; ) { + struct page_state ps; + if (current->flags & PF_FREEZE) refrigerator(PF_FREEZE); prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); schedule(); finish_wait(&pgdat->kswapd_wait, &wait); - - balance_pgdat(pgdat, 0); + try_to_clip_inodes(); + get_page_state(&ps); + balance_pgdat(pgdat, 0, &ps); } } @@ -1170,7 +1129,10 @@ int shrink_all_memory(int nr_pages) current->reclaim_state = &reclaim_state; for_each_pgdat(pgdat) { int freed; - freed = balance_pgdat(pgdat, nr_to_free); + struct page_state ps; + + get_page_state(&ps); + freed = balance_pgdat(pgdat, nr_to_free, &ps); ret += freed; nr_to_free -= freed; if (nr_to_free <= 0) diff --git a/net/Kconfig b/net/Kconfig index 6b033215e..a77d893de 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -672,6 +672,8 @@ source "net/irda/Kconfig" source "net/bluetooth/Kconfig" +source "net/tux/Kconfig" + source "drivers/net/Kconfig" endmenu diff --git a/net/Makefile b/net/Makefile index 61740b47a..7e7a95752 100644 --- a/net/Makefile +++ b/net/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_UNIX) += unix/ ifneq ($(CONFIG_IPV6),) obj-y += ipv6/ endif +obj-$(CONFIG_TUX) += tux/ obj-$(CONFIG_PACKET) += packet/ obj-$(CONFIG_NET_KEY) += key/ obj-$(CONFIG_NET_SCHED) += sched/ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4170de1a0..265d17209 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -673,7 +673,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, /* ioctl calls. Shouldn't even need touching */ /* Device configuration ioctl calls */ -static int atif_ioctl(int cmd, void __user *arg) +static int atif_ioctl(int cmd, void *arg) { static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF }; struct ifreq atreq; @@ -892,7 +892,7 @@ static int atif_ioctl(int cmd, void __user *arg) } /* Routing ioctl() calls */ -static int atrtr_ioctl(unsigned int cmd, void __user *arg) +static int atrtr_ioctl(unsigned int cmd, void *arg) { struct rtentry rt; @@ -1567,7 +1567,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr struct atalk_route *rt; int err; - if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (flags & ~MSG_DONTWAIT) return -EINVAL; if (len > DDP_MAXSZ) @@ -1769,7 +1769,6 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { int rc = -EINVAL; struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; switch (cmd) { /* Protocol layer */ @@ -1779,7 +1778,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (amount < 0) amount = 0; - rc = put_user(amount, (int __user *)argp); + rc = put_user(amount, (int *)arg); break; } case TIOCINQ: { @@ -1792,18 +1791,18 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (skb) amount = skb->len - sizeof(struct ddpehdr); - rc = put_user(amount, (int __user *)argp); + rc = put_user(amount, (int *)arg); break; } case SIOCGSTAMP: - rc = sock_get_timestamp(sk, argp); + rc = sock_get_timestamp(sk, (struct timeval __user *)arg); break; /* Routing */ case SIOCADDRT: case SIOCDELRT: rc = -EPERM; if (capable(CAP_NET_ADMIN)) - rc = atrtr_ioctl(cmd, argp); + rc = atrtr_ioctl(cmd, (void *)arg); break; /* Interface */ case SIOCGIFADDR: @@ -1814,7 +1813,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSARP: /* proxy AARP */ case SIOCDARP: /* proxy AARP */ rtnl_lock(); - rc = atif_ioctl(cmd, argp); + rc = atif_ioctl(cmd, (void *)arg); rtnl_unlock(); break; /* Physical layer ioctl calls */ @@ -1830,7 +1829,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCGIFCOUNT: case SIOCGIFINDEX: case SIOCGIFNAME: - rc = dev_ioctl(cmd, argp); + rc = dev_ioctl(cmd, (void __user *)arg); break; } diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index b15e724f8..a2d9cd23d 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -49,7 +49,6 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct atm_vcc *vcc; int error; struct list_head * pos; - void __user *argp = (void __user *)arg; vcc = ATM_SD(sock); switch (cmd) { @@ -61,7 +60,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } error = put_user(vcc->sk->sk_sndbuf - atomic_read(&vcc->sk->sk_wmem_alloc), - (int __user *) argp) ? -EFAULT : 0; + (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: { @@ -73,11 +72,12 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } skb = skb_peek(&vcc->sk->sk_receive_queue); error = put_user(skb ? skb->len : 0, - (int __user *)argp) ? -EFAULT : 0; + (int *) arg) ? -EFAULT : 0; goto done; } case SIOCGSTAMP: /* borrowed from IP */ - error = sock_get_timestamp(vcc->sk, argp); + error = sock_get_timestamp(vcc->sk, + (struct timeval __user *) arg); goto done; case ATM_SETSC: printk(KERN_WARNING "ATM_SETSC is obsolete\n"); @@ -131,7 +131,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (error != -ENOIOCTLCMD) goto done; - error = atm_dev_ioctl(cmd, argp); + error = atm_dev_ioctl(cmd, arg); done: return error; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 47fbd98e0..563350a0a 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -336,7 +336,7 @@ void ax25_destroy_socket(ax25_cb *ax25) * includes a KILL command to abort any connection. * VERY useful for debugging ;-) */ -static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) +static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) { struct ax25_ctl_struct ax25_ctl; ax25_digi digi; @@ -1413,8 +1413,9 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, size_t size; int lv, err, addr_len = msg->msg_namelen; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) { return -EINVAL; + } lock_sock(sk); ax25 = ax25_sk(sk); @@ -1668,7 +1669,6 @@ static int ax25_shutdown(struct socket *sk, int how) static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; int res = 0; lock_sock(sk); @@ -1678,7 +1678,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - res = put_user(amount, (int __user *)argp); + res = put_user(amount, (int *)arg); break; } @@ -1688,13 +1688,13 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - res = put_user(amount, (int __user *)argp); + res = put_user(amount, (int *)arg); break; } case SIOCGSTAMP: if (sk != NULL) { - res = sock_get_timestamp(sk, argp); + res = sock_get_timestamp(sk, (struct timeval __user *)arg); break; } res = -EINVAL; @@ -1704,7 +1704,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ case SIOCAX25GETUID: { struct sockaddr_ax25 sax25; - if (copy_from_user(&sax25, argp, sizeof(sax25))) { + if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) { res = -EFAULT; break; } @@ -1718,7 +1718,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - if (get_user(amount, (long __user *)argp)) { + if (get_user(amount, (long *)arg)) { res = -EFAULT; break; } @@ -1738,7 +1738,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - res = ax25_rt_ioctl(cmd, argp); + res = ax25_rt_ioctl(cmd, (void *)arg); break; case SIOCAX25CTLCON: @@ -1746,7 +1746,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - res = ax25_ctl_ioctl(cmd, argp); + res = ax25_ctl_ioctl(cmd, (void *)arg); break; case SIOCAX25GETINFO: @@ -1783,12 +1783,12 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) warned=1; } - if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { + if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { res = -EFAULT; break; } } else { - if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) { + if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) { res = -EINVAL; break; } @@ -1804,7 +1804,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) { + if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) { res = -EFAULT; break; } @@ -1826,7 +1826,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; default: - res = dev_ioctl(cmd, argp); + res = dev_ioctl(cmd, (void __user *)arg); break; } release_sock(sk); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 51976db01..e279612f2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -353,7 +353,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev) } } -int hci_get_conn_list(void __user *arg) +int hci_get_conn_list(unsigned long arg) { struct hci_conn_list_req req, *cl; struct hci_conn_info *ci; @@ -361,7 +361,7 @@ int hci_get_conn_list(void __user *arg) struct list_head *p; int n = 0, size, err; - if (copy_from_user(&req, arg, sizeof(req))) + if (copy_from_user(&req, (void *) arg, sizeof(req))) return -EFAULT; if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci)) @@ -401,20 +401,20 @@ int hci_get_conn_list(void __user *arg) hci_dev_put(hdev); - err = copy_to_user(arg, cl, size); + err = copy_to_user((void *) arg, cl, size); kfree(cl); return err ? -EFAULT : 0; } -int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) +int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) { struct hci_conn_info_req req; struct hci_conn_info ci; struct hci_conn *conn; - char __user *ptr = arg + sizeof(req); + char *ptr = (void *) arg + sizeof(req); - if (copy_from_user(&req, arg, sizeof(req))) + if (copy_from_user(&req, (void *) arg, sizeof(req))) return -EFAULT; hci_dev_lock_bh(hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 69ab2e7b9..71ed4088c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -366,15 +366,15 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp); } -int hci_inquiry(void __user *arg) +int hci_inquiry(unsigned long arg) { - __u8 __user *ptr = arg; struct hci_inquiry_req ir; struct hci_dev *hdev; int err = 0, do_inquiry = 0, max_rsp; long timeo; - __u8 *buf; + __u8 *buf, *ptr; + ptr = (void *) arg; if (copy_from_user(&ir, ptr, sizeof(ir))) return -EFAULT; @@ -616,13 +616,13 @@ int hci_dev_reset_stat(__u16 dev) return ret; } -int hci_dev_cmd(unsigned int cmd, void __user *arg) +int hci_dev_cmd(unsigned int cmd, unsigned long arg) { struct hci_dev *hdev; struct hci_dev_req dr; int err = 0; - if (copy_from_user(&dr, arg, sizeof(dr))) + if (copy_from_user(&dr, (void *) arg, sizeof(dr))) return -EFAULT; if (!(hdev = hci_dev_get(dr.dev_id))) @@ -685,7 +685,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) return err; } -int hci_get_dev_list(void __user *arg) +int hci_get_dev_list(unsigned long arg) { struct hci_dev_list_req *dl; struct hci_dev_req *dr; @@ -693,7 +693,7 @@ int hci_get_dev_list(void __user *arg) int n = 0, size, err; __u16 dev_num; - if (get_user(dev_num, (__u16 __user *) arg)) + if (get_user(dev_num, (__u16 *) arg)) return -EFAULT; if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr)) @@ -720,19 +720,19 @@ int hci_get_dev_list(void __user *arg) dl->dev_num = n; size = sizeof(*dl) + n * sizeof(*dr); - err = copy_to_user(arg, dl, size); + err = copy_to_user((void *) arg, dl, size); kfree(dl); return err ? -EFAULT : 0; } -int hci_get_dev_info(void __user *arg) +int hci_get_dev_info(unsigned long arg) { struct hci_dev *hdev; struct hci_dev_info di; int err = 0; - if (copy_from_user(&di, arg, sizeof(di))) + if (copy_from_user(&di, (void *) arg, sizeof(di))) return -EFAULT; if (!(hdev = hci_dev_get(di.dev_id))) @@ -753,7 +753,7 @@ int hci_get_dev_info(void __user *arg) memcpy(&di.stat, &hdev->stat, sizeof(di.stat)); memcpy(&di.features, &hdev->features, sizeof(di.features)); - if (copy_to_user(arg, &di, sizeof(di))) + if (copy_to_user((void *) arg, &di, sizeof(di))) err = -EFAULT; hci_dev_put(hdev); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 348a82fb4..4d16b40ec 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -186,7 +186,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign return 0; case HCIGETCONNINFO: - return hci_get_conn_info(hdev, (void __user *)arg); + return hci_get_conn_info(hdev, arg); default: if (hdev->ioctl) @@ -198,20 +198,19 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; int err; BT_DBG("cmd %x arg %lx", cmd, arg); switch (cmd) { case HCIGETDEVLIST: - return hci_get_dev_list(argp); + return hci_get_dev_list(arg); case HCIGETDEVINFO: - return hci_get_dev_info(argp); + return hci_get_dev_info(arg); case HCIGETCONNLIST: - return hci_get_conn_list(argp); + return hci_get_conn_list(arg); case HCIDEVUP: if (!capable(CAP_NET_ADMIN)) @@ -243,10 +242,10 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a case HCISETSCOMTU: if (!capable(CAP_NET_ADMIN)) return -EACCES; - return hci_dev_cmd(cmd, argp); + return hci_dev_cmd(cmd, arg); case HCIINQUIRY: - return hci_inquiry(argp); + return hci_inquiry(arg); default: lock_sock(sk); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 298a25fb3..21a4556b9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -95,13 +95,17 @@ static void l2cap_sock_timeout(unsigned long arg) static void l2cap_sock_set_timer(struct sock *sk, long timeout) { BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); - sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); + + if (!mod_timer(&sk->sk_timer, jiffies + timeout)) + sock_hold(sk); } static void l2cap_sock_clear_timer(struct sock *sk) { BT_DBG("sock %p state %d", sk, sk->sk_state); - sk_stop_timer(sk, &sk->sk_timer); + + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) + __sock_put(sk); } static void l2cap_sock_init_timer(struct sock *sk) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 1aa1387cc..fbafeb2d5 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -707,7 +707,7 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon lock_sock(sk); #ifdef CONFIG_BT_RFCOMM_TTY - err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg); + err = rfcomm_dev_ioctl(sk, cmd, arg); #else err = -EOPNOTSUPP; #endif diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 55a266705..58af70084 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -91,13 +91,17 @@ static void sco_sock_timeout(unsigned long arg) static void sco_sock_set_timer(struct sock *sk, long timeout) { BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout); - sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); + + if (!mod_timer(&sk->sk_timer, jiffies + timeout)) + sock_hold(sk); } static void sco_sock_clear_timer(struct sock *sk) { BT_DBG("sock %p state %d", sk, sk->sk_state); - sk_stop_timer(sk, &sk->sk_timer); + + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) + __sock_put(sk); } static void sco_sock_init_timer(struct sock *sk) diff --git a/net/bluetooth/syms.c b/net/bluetooth/syms.c deleted file mode 100644 index 20d81017f..000000000 --- a/net/bluetooth/syms.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * Bluetooth symbols. - * - * $Id: syms.c,v 1.1 2002/03/08 21:06:59 maxk Exp $ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* HCI Core */ -EXPORT_SYMBOL(hci_alloc_dev); -EXPORT_SYMBOL(hci_free_dev); -EXPORT_SYMBOL(hci_register_dev); -EXPORT_SYMBOL(hci_unregister_dev); -EXPORT_SYMBOL(hci_suspend_dev); -EXPORT_SYMBOL(hci_resume_dev); - -EXPORT_SYMBOL(hci_register_proto); -EXPORT_SYMBOL(hci_unregister_proto); - -EXPORT_SYMBOL(hci_get_route); -EXPORT_SYMBOL(hci_connect); -EXPORT_SYMBOL(hci_dev_get); -EXPORT_SYMBOL(hci_conn_auth); -EXPORT_SYMBOL(hci_conn_encrypt); - -EXPORT_SYMBOL(hci_send_acl); -EXPORT_SYMBOL(hci_send_sco); -EXPORT_SYMBOL(hci_send_cmd); -EXPORT_SYMBOL(hci_si_event); - -/* Bluetooth lib */ -EXPORT_SYMBOL(bt_dump); -EXPORT_SYMBOL(baswap); -EXPORT_SYMBOL(batostr); -EXPORT_SYMBOL(bt_err); - -/* Bluetooth sockets */ -EXPORT_SYMBOL(bt_sock_register); -EXPORT_SYMBOL(bt_sock_unregister); -EXPORT_SYMBOL(bt_sock_alloc); -EXPORT_SYMBOL(bt_sock_link); -EXPORT_SYMBOL(bt_sock_unlink); -EXPORT_SYMBOL(bt_sock_recvmsg); -EXPORT_SYMBOL(bt_sock_poll); -EXPORT_SYMBOL(bt_accept_enqueue); -EXPORT_SYMBOL(bt_accept_dequeue); -EXPORT_SYMBOL(bt_sock_wait_state); - -EXPORT_SYMBOL(proc_bt); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index cceb01866..17c7ee3b3 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -143,7 +143,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) b.gc_timer_value = br_timer_value(&br->gc_timer); rcu_read_unlock(); - if (copy_to_user((void __user *)args[1], &b, sizeof(b))) + if (copy_to_user((void *)args[1], &b, sizeof(b))) return -EFAULT; return 0; @@ -168,7 +168,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) memset(indices, 0, num*sizeof(int)); get_port_ifindices(br, indices, num); - if (copy_to_user((void __user *)args[1], indices, num*sizeof(int))) + if (copy_to_user((void *)args[1], indices, num*sizeof(int))) num = -EFAULT; kfree(indices); return num; @@ -241,7 +241,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rcu_read_unlock(); - if (copy_to_user((void __user *)args[1], &p, sizeof(p))) + if (copy_to_user((void *)args[1], &p, sizeof(p))) return -EFAULT; return 0; @@ -308,11 +308,11 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } -static int old_deviceless(void __user *uarg) +static int old_deviceless(unsigned long uarg) { unsigned long args[3]; - if (copy_from_user(args, uarg, sizeof(args))) + if (copy_from_user(args, (void *)uarg, sizeof(args))) return -EFAULT; switch (args[0]) { @@ -331,7 +331,7 @@ static int old_deviceless(void __user *uarg) memset(indices, 0, args[2]*sizeof(int)); args[2] = get_bridge_ifindices(indices, args[2]); - ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int)) + ret = copy_to_user((void *)args[1], indices, args[2]*sizeof(int)) ? -EFAULT : args[2]; kfree(indices); @@ -346,7 +346,7 @@ static int old_deviceless(void __user *uarg) if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ)) + if (copy_from_user(buf, (void *)args[1], IFNAMSIZ)) return -EFAULT; buf[IFNAMSIZ-1] = 0; @@ -361,7 +361,7 @@ static int old_deviceless(void __user *uarg) return -EOPNOTSUPP; } -int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg) +int br_ioctl_deviceless_stub(unsigned int cmd, unsigned long uarg) { switch (cmd) { case SIOCGIFBR: @@ -376,7 +376,7 @@ int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg) if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(buf, uarg, IFNAMSIZ)) + if (copy_from_user(buf, (void __user *) uarg, IFNAMSIZ)) return -EFAULT; buf[IFNAMSIZ-1] = 0; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d3cd71517..048e76179 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -175,7 +175,7 @@ extern int br_handle_frame(struct sk_buff *skb); /* br_ioctl.c */ extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -extern int br_ioctl_deviceless_stub(unsigned int cmd, void __user *arg); +extern int br_ioctl_deviceless_stub(unsigned int cmd, unsigned long arg); /* br_netfilter.c */ extern int br_netfilter_init(void); diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 61f00fa3b..98cf53c81 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -300,25 +300,6 @@ static struct bin_attribute bridge_forward = { .read = brforward_read, }; - -/* - * This is a dummy kset so bridge objects don't cause - * hotplug events - */ -struct subsystem bridge_subsys = { - .kset = { .hotplug_ops = NULL }, -}; - -void br_sysfs_init(void) -{ - subsystem_register(&bridge_subsys); -} - -void br_sysfs_fini(void) -{ - subsystem_unregister(&bridge_subsys); -} - /* * Add entries in sysfs onto the existing network class device * for the bridge. @@ -353,7 +334,7 @@ int br_sysfs_addbr(struct net_device *dev) kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); br->ifobj.ktype = NULL; - br->ifobj.kset = &bridge_subsys.kset; + br->ifobj.kset = NULL; br->ifobj.parent = brobj; err = kobject_register(&br->ifobj); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 178822116..567249bf9 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -227,7 +227,7 @@ int br_sysfs_addif(struct net_bridge_port *p) kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); p->kobj.ktype = &brport_ktype; p->kobj.parent = &(p->dev->class_dev.kobj); - p->kobj.kset = &bridge_subsys.kset; + p->kobj.kset = NULL; err = kobject_add(&p->kobj); if(err) diff --git a/net/core/dev.c b/net/core/dev.c index fb20e1047..f0c0c9a95 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1180,46 +1180,28 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) rcu_read_unlock(); } -/* - * Invalidate hardware checksum when packet is to be mangled, and - * complete checksum manually on outgoing path. +/* Calculate csum in the case, when packet is misrouted. + * If it failed by some reason, ignore and send skb with wrong + * checksum. */ -int skb_checksum_help(struct sk_buff **pskb, int inward) +struct sk_buff *skb_checksum_help(struct sk_buff *skb) { unsigned int csum; - int ret = 0, offset = (*pskb)->h.raw - (*pskb)->data; - - if (inward) { - (*pskb)->ip_summed = CHECKSUM_NONE; - goto out; - } + int offset = skb->h.raw - skb->data; - if (skb_shared(*pskb) || skb_cloned(*pskb)) { - struct sk_buff *newskb = skb_copy(*pskb, GFP_ATOMIC); - if (!newskb) { - ret = -ENOMEM; - goto out; - } - if ((*pskb)->sk) - skb_set_owner_w(newskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = newskb; - } - - if (offset > (int)(*pskb)->len) + if (offset > (int)skb->len) BUG(); - csum = skb_checksum(*pskb, offset, (*pskb)->len-offset, 0); + csum = skb_checksum(skb, offset, skb->len-offset, 0); - offset = (*pskb)->tail - (*pskb)->h.raw; + offset = skb->tail - skb->h.raw; if (offset <= 0) BUG(); - if ((*pskb)->csum + 2 > offset) + if (skb->csum + 2 > offset) BUG(); - *(u16*)((*pskb)->h.raw + (*pskb)->csum) = csum_fold(csum); - (*pskb)->ip_summed = CHECKSUM_NONE; -out: - return ret; + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; + return skb; } #ifdef CONFIG_HIGHMEM @@ -1344,9 +1326,10 @@ int dev_queue_xmit(struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_HW && (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && (!(dev->features & NETIF_F_IP_CSUM) || - skb->protocol != htons(ETH_P_IP)))) - if (skb_checksum_help(&skb, 0)) - goto out_kfree_skb; + skb->protocol != htons(ETH_P_IP)))) { + if ((skb = skb_checksum_help(skb)) == NULL) + goto out; + } /* Grab device queue */ spin_lock_bh(&dev->queue_lock); @@ -1996,6 +1979,8 @@ static int dev_ifconf(char __user *arg) total = 0; for (dev = dev_base; dev; dev = dev->next) { + if (!dev_in_nx_info(dev, current->nx_info)) + continue; for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -2056,6 +2041,10 @@ void dev_seq_stop(struct seq_file *seq, void *v) static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) { + struct nx_info *nxi = current->nx_info; + + if (!dev_in_nx_info(dev, nxi)) + return; if (dev->get_stats) { struct net_device_stats *stats = dev->get_stats(dev); diff --git a/net/core/iovec.c b/net/core/iovec.c index 89de9355d..0f3c8b60b 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -157,7 +157,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, } while (len > 0) { - u8 __user *base = iov->iov_base + offset; + u8 *base = iov->iov_base + offset; int copy = min_t(unsigned int, len, iov->iov_len - offset); offset = 0; diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 58632d189..dd8b9a8ee 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -504,6 +504,14 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, unsigned int verdict; int ret = 0; + if (skb->ip_summed == CHECKSUM_HW) { + if (outdev == NULL) { + skb->ip_summed = CHECKSUM_NONE; + } else { + skb_checksum_help(skb); + } + } + /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 26e3577c0..f577cba67 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -224,6 +224,8 @@ int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; + if (!dev_in_nx_info(dev, current->nx_info)) + continue; if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 0) <= 0) break; } @@ -309,6 +311,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) struct sk_buff *skb; int size = NLMSG_GOODSIZE; + if (!dev_in_nx_info(dev, current->nx_info)) + return; skb = alloc_skb(size, GFP_KERNEL); if (!skb) return; diff --git a/net/core/sock.c b/net/core/sock.c index 289f5824e..78d318a96 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -323,7 +323,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname, break; case SO_PASSCRED: - sock->passcred = valbool; + if (valbool) + set_bit(SOCK_PASS_CRED, &sock->flags); + else + clear_bit(SOCK_PASS_CRED, &sock->flags); break; case SO_TIMESTAMP: @@ -546,7 +549,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_PASSCRED: - v.val = sock->passcred; + v.val = test_bit(SOCK_PASS_CRED, &sock->flags)?1:0; break; case SO_PEERCRED: @@ -621,6 +624,8 @@ struct sock *sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab) sock_lock_init(sk); } sk->sk_slab = slab; + sock_vx_init(sk); + sock_nx_init(sk); if (security_sk_alloc(sk, family, priority)) { kmem_cache_free(slab, sk); @@ -651,6 +656,10 @@ void sk_free(struct sock *sk) __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); security_sk_free(sk); + BUG_ON(sk->sk_vx_info); + BUG_ON(sk->sk_nx_info); +/* clr_vx_info(&sk->sk_vx_info); + clr_nx_info(&sk->sk_nx_info); */ kmem_cache_free(sk->sk_slab, sk); module_put(owner); } @@ -917,31 +926,6 @@ void __release_sock(struct sock *sk) } while((skb = sk->sk_backlog.head) != NULL); } -/** - * sk_wait_data - wait for data to arrive at sk_receive_queue - * sk - sock to wait on - * timeo - for how long - * - * Now socket state including sk->sk_err is changed only under lock, - * hence we may omit checks after joining wait queue. - * We check receive queue before schedule() only as optimization; - * it is very likely that release_sock() added new data. - */ -int sk_wait_data(struct sock *sk, long *timeo) -{ - int rc; - DEFINE_WAIT(wait); - - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue)); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - finish_wait(sk->sk_sleep, &wait); - return rc; -} - -EXPORT_SYMBOL(sk_wait_data); - /* * Set of default routines for initialising struct proto_ops when * the protocol does not support a particular function. In certain @@ -1124,23 +1108,6 @@ void sk_send_sigurg(struct sock *sk) sk_wake_async(sk, 3, POLL_PRI); } -void sk_reset_timer(struct sock *sk, struct timer_list* timer, - unsigned long expires) -{ - if (!mod_timer(timer, expires)) - sock_hold(sk); -} - -EXPORT_SYMBOL(sk_reset_timer); - -void sk_stop_timer(struct sock *sk, struct timer_list* timer) -{ - if (timer_pending(timer) && del_timer(timer)) - __sock_put(sk); -} - -EXPORT_SYMBOL(sk_stop_timer); - void sock_init_data(struct socket *sock, struct sock *sk) { skb_queue_head_init(&sk->sk_receive_queue); @@ -1184,6 +1151,11 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp.tv_sec = -1L; sk->sk_stamp.tv_usec = -1L; + sk->sk_vx_info = NULL; + sk->sk_xid = 0; + sk->sk_nx_info = NULL; + sk->sk_nid = 0; + atomic_set(&sk->sk_refcnt, 1); } diff --git a/net/core/stream.c b/net/core/stream.c new file mode 100644 index 000000000..24a6f72a0 --- /dev/null +++ b/net/core/stream.c @@ -0,0 +1,41 @@ +/* + * SUCS NET3: + * + * Generic stream handling routines. These are generic for most + * protocols. Even IP. Tonight 8-). + * This is used because TCP, LLC (others too) layer all have mostly + * identical sendmsg() and recvmsg() code. + * So we (will) share it here. + * + * Authors: Arnaldo Carvalho de Melo + * (from old tcp.c code) + * Alan Cox (Borrowed comments 8-)) + */ + +#include +#include +#include +#include +#include + +/** + * sk_stream_write_space - stream socket write_space callback. + * sk - socket + * + * FIXME: write proper description + */ +void sk_stream_write_space(struct sock *sk) +{ + struct socket *sock = sk->sk_socket; + + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) { + clear_bit(SOCK_NOSPACE, &sock->flags); + + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); + if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) + sock_wake_async(sock, 2, POLL_OUT); + } +} + +EXPORT_SYMBOL(sk_stream_write_space); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index c08a80fd3..632de2c26 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1212,7 +1212,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { case SIOCGIFADDR: case SIOCSIFADDR: - return dn_dev_ioctl(cmd, (void __user *)arg); + return dn_dev_ioctl(cmd, (void *)arg); case SIOCATMARK: lock_sock(sk); @@ -1226,7 +1226,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - err = put_user(amount, (int __user *)arg); + err = put_user(amount, (int *)arg); break; case TIOCINQ: @@ -1244,7 +1244,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } } release_sock(sk); - err = put_user(amount, (int __user *)arg); + err = put_user(amount, (int *)arg); break; default: @@ -1325,7 +1325,7 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use return err; } -static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags) +static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user __user *optval, int optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); @@ -1905,7 +1905,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, unsigned char fctype; long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) + if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE)) return -EOPNOTSUPP; if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 6b6e49a9e..6941da9f5 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -161,10 +161,10 @@ static int min_priority[1]; static int max_priority[] = { 127 }; /* From DECnet spec */ static int dn_forwarding_proc(ctl_table *, int, struct file *, - void __user *, size_t *); -static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, + void *, size_t *); +static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context); static struct dn_dev_sysctl_table { @@ -362,7 +362,7 @@ static void dn_dev_check_default(struct net_device *dev) static int dn_forwarding_proc(ctl_table *table, int write, struct file *filep, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { #ifdef CONFIG_DECNET_ROUTER struct net_device *dev = table->extra1; @@ -404,9 +404,9 @@ static int dn_forwarding_proc(ctl_table *table, int write, #endif } -static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen, +static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) { #ifdef CONFIG_DECNET_ROUTER @@ -423,7 +423,7 @@ static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen, if (newlen != sizeof(int)) return -EINVAL; - if (get_user(value, (int __user *)newval)) + if (get_user(value, (int *)newval)) return -EFAULT; if (value < 0) return -EINVAL; @@ -553,7 +553,7 @@ static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) } -int dn_dev_ioctl(unsigned int cmd, void __user *arg) +int dn_dev_ioctl(unsigned int cmd, void *arg) { char buffer[DN_IFREQ_SIZE]; struct ifreq *ifr = (struct ifreq *)buffer; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index ce383ad75..00ab04ef5 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -274,8 +274,8 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, * Check the flags. */ - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) - return -EINVAL; + if (msg->msg_flags&~MSG_DONTWAIT) + return(-EINVAL); /* * Get and verify the address. @@ -418,18 +418,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, /* tack our header on the front of the iovec */ size = sizeof(struct aunhdr); - /* - * XXX: that is b0rken. We can't mix userland and kernel pointers - * in iovec, since on a lot of platforms copy_from_user() will - * *not* work with the kernel and userland ones at the same time, - * regardless of what we do with set_fs(). And we are talking about - * econet-over-ethernet here, so "it's only ARM anyway" doesn't - * apply. Any suggestions on fixing that code? -- AV - */ iov[0].iov_base = (void *)&ah; iov[0].iov_len = size; for (i = 0; i < msg->msg_iovlen; i++) { - void __user *base = msg->msg_iov[i].iov_base; + void *base = msg->msg_iov[i].iov_base; size_t len = msg->msg_iov[i].iov_len; /* Check it now since we switch to KERNEL_DS later. */ if ((err = verify_area(VERIFY_READ, base, len)) < 0) @@ -597,7 +589,7 @@ out: * Handle Econet specific ioctls */ -static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg) +static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg) { struct ifreq ifr; struct ec_device *edev; @@ -670,19 +662,18 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg) static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; switch(cmd) { case SIOCGSTAMP: - return sock_get_timestamp(sk, argp); + return sock_get_timestamp(sk,(struct timeval __user *)arg); case SIOCSIFADDR: case SIOCGIFADDR: - return ec_dev_ioctl(sock, cmd, argp); + return ec_dev_ioctl(sock, cmd, (void *)arg); break; default: - return dev_ioctl(cmd, argp); + return dev_ioctl(cmd,(void __user *) arg); } /*NOTREACHED*/ return 0; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 0bb1b8808..d59797c7e 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -360,5 +360,28 @@ config INET_IPCOMP If unsure, say Y. +config ACCEPT_QUEUES + bool "IP: TCP Multiple accept queues support" + depends on INET && NETFILTER + ---help--- + Support multiple accept queues per listening socket. If you say Y + here, multiple accept queues will be configured per listening + socket. + + Each queue is mapped to a priority class. Incoming connection + requests can be classified (see iptables(8), MARK target), depending + on the packet's src/dest address or other parameters, into one of + the priority classes. The requests are then queued to the relevant + accept queue. + + Each of the queues can be assigned a weight. The accept()ance + of packets is then scheduled in accordance with the weight + assigned to the priority class. + + Be sure to enable "Network packet filtering" if you wish + to use this feature. + + If unsure, say N. + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8b14637aa..80d02436c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -158,6 +158,9 @@ void inet_sock_destruct(struct sock *sk) if (inet->opt) kfree(inet->opt); + + BUG_ON(sk->sk_nx_info); + BUG_ON(sk->sk_vx_info); dst_release(sk->sk_dst_cache); #ifdef INET_REFCNT_DEBUG atomic_dec(&inet_sock_nr); @@ -397,6 +400,11 @@ static int inet_create(struct socket *sock, int protocol) sk->sk_family = PF_INET; sk->sk_protocol = protocol; sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; + + set_vx_info(&sk->sk_vx_info, current->vx_info); + sk->sk_xid = vx_current_xid(); + set_nx_info(&sk->sk_nx_info, current->nx_info); + sk->sk_nid = nx_current_nid(); inet->uc_ttl = -1; inet->mc_loop = 1; @@ -421,8 +429,13 @@ static int inet_create(struct socket *sock, int protocol) if (sk->sk_prot->init) { err = sk->sk_prot->init(sk); - if (err) - inet_sock_release(sk); + if (err) { +/* sk->sk_vx_info = NULL; + put_vx_info(current->vx_info); + sk->sk_nx_info = NULL; + put_nx_info(current->nx_info); +*/ inet_sock_release(sk); + } } out: return err; @@ -460,6 +473,8 @@ int inet_release(struct socket *sock) !(current->flags & PF_EXITING)) timeout = sk->sk_lingertime; sock->sk = NULL; + clr_vx_info(&sk->sk_vx_info); + clr_nx_info(&sk->sk_nx_info); sk->sk_prot->close(sk, timeout); } return 0; @@ -476,6 +491,10 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) unsigned short snum; int chk_addr_ret; int err; + __u32 s_addr; /* Address used for validation */ + __u32 s_addr1; + __u32 s_addr2 = 0xffffffffl; /* Optional address of the socket */ + struct nx_info *nxi = sk->sk_nx_info; /* If the socket has its own bind function then use it. (RAW) */ if (sk->sk_prot->bind) { @@ -486,7 +505,36 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); + s_addr = s_addr1 = addr->sin_addr.s_addr; + nxdprintk("inet_bind(%p) %p,%p;%lx\n", + sk, nx_info, sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + if (nxi) { + __u32 v4_bcast = nxi->v4_bcast; + __u32 ipv4root = nxi->ipv4[0]; + int nbipv4 = nxi->nbipv4; + if (s_addr == 0) { + s_addr = ipv4root; + if (nbipv4 > 1) + s_addr1 = 0; + else { + s_addr1 = ipv4root; + } + s_addr2 = v4_bcast; + } else if (s_addr == 0x0100007f) { + s_addr = s_addr1 = ipv4root; + } else if (s_addr != v4_bcast) { + int i; + for (i=0; iipv4[i]) + break; + } + if (i == nbipv4) { + return -EADDRNOTAVAIL; + } + } + } + chk_addr_ret = inet_addr_type(s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -498,7 +546,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = -EADDRNOTAVAIL; if (!sysctl_ip_nonlocal_bind && !inet->freebind && - addr->sin_addr.s_addr != INADDR_ANY && + s_addr != INADDR_ANY && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) @@ -523,7 +571,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (sk->sk_state != TCP_CLOSE || inet->num) goto out_release_sock; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; + inet->rcv_saddr = inet->saddr = s_addr1; + inet->rcv_saddr2 = s_addr2; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->saddr = 0; /* Use device */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 6e16cc55b..37581ba5b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -488,6 +488,33 @@ static __inline__ int inet_abc_len(u32 addr) return rc; } +/* + Check that a device is not member of the ipv4root assigned to the process + Return true if this is the case + + If the process is not bound to specific IP, then it returns 0 (all + interface are fine). +*/ +static inline int devinet_notiproot (struct in_ifaddr *ifa) +{ + int ret = 0; + struct nx_info *nxi; + + if ((nxi = current->nx_info)) { + int i; + int nbip = nxi->nbipv4; + __u32 addr = ifa->ifa_local; + ret = 1; + for (i=0; iipv4[i] == addr) { + ret = 0; + break; + } + } + } + return ret; +} + int devinet_ioctl(unsigned int cmd, void __user *arg) { @@ -595,6 +622,8 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) ret = -EADDRNOTAVAIL; if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) goto done; + if (!ifa_in_nx_info(ifa, current->nx_info)) + goto done; switch(cmd) { case SIOCGIFADDR: /* Get interface address */ @@ -724,6 +753,8 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len) goto out; for (; ifa; ifa = ifa->ifa_next) { + if (!ifa_in_nx_info(ifa, current->nx_info)) + continue; if (!buf) { done += sizeof(ifr); continue; @@ -1059,6 +1090,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) read_lock(&in_dev->lock); for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; ifa = ifa->ifa_next, ip_idx++) { + if (!ifa_in_nx_info(ifa, current->nx_info)) + continue; if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 2316dfa91..3b4f8e35e 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -1010,6 +1010,8 @@ static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi return flags; } +extern int dev_in_nx_info(struct net_device *, struct nx_info *); + /* * This outputs /proc/net/route. * @@ -1039,7 +1041,7 @@ static int fib_seq_show(struct seq_file *seq, void *v) mask = FZ_MASK(iter->zone); flags = fib_flag_trans(f->fn_type, f->fn_state & FN_S_ZOMBIE, mask, fi); - if (fi) + if (fi && dev_in_nx_info(fi->fib_dev, current->nx_info)) snprintf(bf, sizeof(bf), "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", fi->fib_dev ? fi->fib_dev->name : "*", prefix, diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 60fc5091c..84a3df368 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -223,9 +223,8 @@ int ip_finish_output(struct sk_buff *skb) ip_finish_output2); } -int ip_mc_output(struct sk_buff **pskb) +int ip_mc_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct sock *sk = skb->sk; struct rtable *rt = (struct rtable*)skb->dst; struct net_device *dev = rt->u.dst.dev; @@ -256,7 +255,7 @@ int ip_mc_output(struct sk_buff **pskb) && ((rt->rt_flags&RTCF_LOCAL) || !(IPCB(skb)->flags&IPSKB_FORWARDED)) #endif ) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + struct sk_buff *newskb = skb_copy(skb, GFP_ATOMIC); if (newskb) NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL, newskb->dev, @@ -272,7 +271,7 @@ int ip_mc_output(struct sk_buff **pskb) } if (rt->rt_flags&RTCF_BROADCAST) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + struct sk_buff *newskb = skb_copy(skb, GFP_ATOMIC); if (newskb) NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL, newskb->dev, ip_dev_loopback_xmit); @@ -284,10 +283,8 @@ int ip_mc_output(struct sk_buff **pskb) return ip_finish_output(skb); } -int ip_output(struct sk_buff **pskb) +int ip_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - IP_INC_STATS(OutRequests); if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list) && diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index e20c7e43b..57d84fa77 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -143,10 +143,10 @@ static void ipcomp_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) skb->nh.raw = skb->data; } -static int ipcomp_output(struct sk_buff **pskb) +static int ipcomp_output(struct sk_buff *skb) { int err; - struct dst_entry *dst = (*pskb)->dst; + struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; struct iphdr *iph, *top_iph; struct ip_comp_hdr *ipch; @@ -157,26 +157,25 @@ static int ipcomp_output(struct sk_buff **pskb) } tmp_iph; int hdr_len = 0; - if ((*pskb)->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - if (err) - goto error_nolock; + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; } spin_lock_bh(&x->lock); - err = xfrm_check_output(x, *pskb, AF_INET); + err = xfrm_check_output(x, skb, AF_INET); if (err) goto error; /* Don't bother compressing */ if (!x->props.mode) { - iph = (*pskb)->nh.iph; + iph = skb->nh.iph; hdr_len = iph->ihl * 4; } - if (((*pskb)->len - hdr_len) < ipcd->threshold) { + if ((skb->len - hdr_len) < ipcd->threshold) { if (x->props.mode) { - ipcomp_tunnel_encap(x, *pskb); - iph = (*pskb)->nh.iph; + ipcomp_tunnel_encap(x, skb); + iph = skb->nh.iph; iph->protocol = IPPROTO_IPIP; ip_send_check(iph); } @@ -184,19 +183,19 @@ static int ipcomp_output(struct sk_buff **pskb) } if (x->props.mode) - ipcomp_tunnel_encap(x, *pskb); + ipcomp_tunnel_encap(x, skb); - if ((skb_is_nonlinear(*pskb) || skb_cloned(*pskb)) && - skb_linearize(*pskb, GFP_ATOMIC) != 0) { + if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && + skb_linearize(skb, GFP_ATOMIC) != 0) { err = -ENOMEM; goto error; } - err = ipcomp_compress(x, *pskb); + err = ipcomp_compress(x, skb); if (err) { if (err == -EMSGSIZE) { if (x->props.mode) { - iph = (*pskb)->nh.iph; + iph = skb->nh.iph; iph->protocol = IPPROTO_IPIP; ip_send_check(iph); } @@ -206,14 +205,14 @@ static int ipcomp_output(struct sk_buff **pskb) } /* Install ipcomp header, convert into ipcomp datagram. */ - iph = (*pskb)->nh.iph; + iph = skb->nh.iph; memcpy(&tmp_iph, iph, iph->ihl * 4); - top_iph = (struct iphdr *)skb_push(*pskb, sizeof(struct ip_comp_hdr)); + top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr)); memcpy(top_iph, &tmp_iph, iph->ihl * 4); iph = top_iph; if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN)) IP_ECN_clear(iph); - iph->tot_len = htons((*pskb)->len); + iph->tot_len = htons(skb->len); iph->protocol = IPPROTO_COMP; iph->check = 0; ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4); @@ -221,14 +220,14 @@ static int ipcomp_output(struct sk_buff **pskb) ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); ip_send_check(iph); - (*pskb)->nh.raw = (*pskb)->data; + skb->nh.raw = skb->data; out_ok: - x->curlft.bytes += (*pskb)->len; + x->curlft.bytes += skb->len; x->curlft.packets++; spin_unlock_bh(&x->lock); - if (((*pskb)->dst = dst_pop(dst)) == NULL) { + if ((skb->dst = dst_pop(dst)) == NULL) { err = -EHOSTUNREACH; goto error_nolock; } @@ -239,7 +238,7 @@ out_exit: error: spin_unlock_bh(&x->lock); error_nolock: - kfree_skb(*pskb); + kfree_skb(skb); goto out_exit; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a25e56077..64ccce525 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1008,7 +1008,7 @@ int ip_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __u * The IP multicast ioctl support routines. */ -int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) +int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) { struct sioc_sg_req sr; struct sioc_vif_req vr; @@ -1018,7 +1018,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) switch(cmd) { case SIOCGETVIFCNT: - if (copy_from_user(&vr,arg,sizeof(vr))) + if (copy_from_user(&vr,(void *)arg,sizeof(vr))) return -EFAULT; if(vr.vifi>=maxvif) return -EINVAL; @@ -1031,14 +1031,14 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) vr.obytes=vif->bytes_out; read_unlock(&mrt_lock); - if (copy_to_user(arg,&vr,sizeof(vr))) + if (copy_to_user((void *)arg,&vr,sizeof(vr))) return -EFAULT; return 0; } read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT: - if (copy_from_user(&sr,arg,sizeof(sr))) + if (copy_from_user(&sr,(void *)arg,sizeof(sr))) return -EFAULT; read_lock(&mrt_lock); @@ -1049,7 +1049,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) sr.wrong_if = c->mfc_un.res.wrong_if; read_unlock(&mrt_lock); - if (copy_to_user(arg,&sr,sizeof(sr))) + if (copy_to_user((void *)arg,&sr,sizeof(sr))) return -EFAULT; return 0; } diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 5df55ca9e..8f2d43fc5 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -1347,7 +1347,7 @@ static int ip_vs_zero_all(void) static int proc_do_defense_mode(ctl_table *table, int write, struct file * filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { int *valp = table->data; int val = *valp; @@ -1370,7 +1370,7 @@ proc_do_defense_mode(ctl_table *table, int write, struct file * filp, static int proc_do_sync_threshold(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp) + void *buffer, size_t *lenp) { int *valp = table->data; int val[2]; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 65230e5e1..19bc813bd 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -179,10 +179,11 @@ static inline int arp_packet_match(const struct arphdr *arphdr, return 0; } - /* Look for ifname matches. */ - for (i = 0, ret = 0; i < IFNAMSIZ; i++) { - ret |= (indev[i] ^ arpinfo->iniface[i]) - & arpinfo->iniface_mask[i]; + /* Look for ifname matches; this should unroll nicely. */ + for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { + ret |= (((const unsigned long *)indev)[i] + ^ ((const unsigned long *)arpinfo->iniface)[i]) + & ((const unsigned long *)arpinfo->iniface_mask)[i]; } if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { @@ -387,12 +388,12 @@ find_inlist_lock(struct list_head *head, } #endif -static inline struct arpt_table *arpt_find_table_lock(const char *name, int *error, struct semaphore *mutex) +static inline struct arpt_table *find_table_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); } -struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) +static inline struct arpt_target *find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); } @@ -542,7 +543,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i } t = arpt_get_target(e); - target = arpt_find_target_lock(t->u.user.name, &ret, &arpt_mutex); + target = find_target_lock(t->u.user.name, &ret, &arpt_mutex); if (!target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); goto out; @@ -842,7 +843,7 @@ static int get_entries(const struct arpt_get_entries *entries, int ret; struct arpt_table *t; - t = arpt_find_table_lock(entries->name, &ret, &arpt_mutex); + t = find_table_lock(entries->name, &ret, &arpt_mutex); if (t) { duprintf("t->private->number = %u\n", t->private->number); @@ -908,7 +909,7 @@ static int do_replace(void __user *user, unsigned int len) duprintf("arp_tables: Translated table\n"); - t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); + t = find_table_lock(tmp.name, &ret, &arpt_mutex); if (!t) goto free_newinfo_counters_untrans; @@ -1001,7 +1002,7 @@ static int do_add_counters(void __user *user, unsigned int len) goto free; } - t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); + t = find_table_lock(tmp.name, &ret, &arpt_mutex); if (!t) goto free; @@ -1074,7 +1075,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len break; } name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; - t = arpt_find_table_lock(name, &ret, &arpt_mutex); + t = find_table_lock(name, &ret, &arpt_mutex); if (t) { struct arpt_getinfo info; @@ -1322,7 +1323,6 @@ static void __exit fini(void) EXPORT_SYMBOL(arpt_register_table); EXPORT_SYMBOL(arpt_unregister_table); EXPORT_SYMBOL(arpt_do_table); -EXPORT_SYMBOL(arpt_find_target_lock); EXPORT_SYMBOL(arpt_register_target); EXPORT_SYMBOL(arpt_unregister_target); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 67c2fd2a5..50a467898 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -324,9 +324,8 @@ destroy_conntrack(struct nf_conntrack *nfct) ip_conntrack_destroyed(ct); WRITE_LOCK(&ip_conntrack_lock); - /* Make sure don't leave any orphaned expectations lying around */ - if (ct->expecting) - remove_expectations(ct, 1); + /* Delete us from our own list to prevent corruption later */ + list_del(&ct->sibling_list); /* Delete our master expectation */ if (ct->master) { @@ -1128,8 +1127,10 @@ int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, DUMP_TUPLE(newreply); conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; - if (!conntrack->master && list_empty(&conntrack->sibling_list)) - conntrack->helper = ip_ct_find_helper(newreply); + if (!conntrack->master) + conntrack->helper = LIST_FIND(&helpers, helper_cmp, + struct ip_conntrack_helper *, + newreply); WRITE_UNLOCK(&ip_conntrack_lock); return 1; diff --git a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c index f7146f31b..0b26447c7 100644 --- a/net/ipv4/netfilter/ip_fw_compat.c +++ b/net/ipv4/netfilter/ip_fw_compat.c @@ -69,8 +69,7 @@ fw_in(unsigned int hooknum, /* Assume worse case: any hook could change packet */ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; if ((*pskb)->ip_summed == CHECKSUM_HW) - if (skb_checksum_help(pskb, (out == NULL))) - return NF_DROP; + (*pskb)->ip_summed = CHECKSUM_NONE; switch (hooknum) { case NF_IP_PRE_ROUTING: diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2d433b69d..66316da7f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -61,6 +61,9 @@ do { \ #endif #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) +/* Mutex protects lists (only traversed in user context). */ +static DECLARE_MUTEX(ipt_mutex); + /* Must have mutex */ #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) @@ -415,7 +418,7 @@ find_inlist_lock_noload(struct list_head *head, { void *ret; -#if 0 +#if 0 duprintf("find_inlist: searching for `%s' in %s.\n", name, head == &ipt_target ? "ipt_target" : head == &ipt_match ? "ipt_match" @@ -458,7 +461,7 @@ find_inlist_lock(struct list_head *head, #endif static inline struct ipt_table * -ipt_find_table_lock(const char *name, int *error, struct semaphore *mutex) +find_table_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ipt_tables, name, "iptable_", error, mutex); } @@ -469,8 +472,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex); } -struct ipt_target * -ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex) +static inline struct ipt_target * +find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); } @@ -685,7 +688,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, goto cleanup_matches; t = ipt_get_target(e); - target = ipt_find_target_lock(t->u.user.name, &ret, &ipt_mutex); + target = find_target_lock(t->u.user.name, &ret, &ipt_mutex); if (!target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); goto cleanup_matches; @@ -1022,7 +1025,7 @@ get_entries(const struct ipt_get_entries *entries, int ret; struct ipt_table *t; - t = ipt_find_table_lock(entries->name, &ret, &ipt_mutex); + t = find_table_lock(entries->name, &ret, &ipt_mutex); if (t) { duprintf("t->private->number = %u\n", t->private->number); @@ -1089,7 +1092,7 @@ do_replace(void __user *user, unsigned int len) duprintf("ip_tables: Translated table\n"); - t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex); + t = find_table_lock(tmp.name, &ret, &ipt_mutex); if (!t) goto free_newinfo_counters_untrans; @@ -1192,7 +1195,7 @@ do_add_counters(void __user *user, unsigned int len) goto free; } - t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex); + t = find_table_lock(tmp.name, &ret, &ipt_mutex); if (!t) goto free; @@ -1267,7 +1270,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) break; } name[IPT_TABLE_MAXNAMELEN-1] = '\0'; - t = ipt_find_table_lock(name, &ret, &ipt_mutex); + t = find_table_lock(name, &ret, &ipt_mutex); if (t) { struct ipt_getinfo info; @@ -1852,7 +1855,6 @@ EXPORT_SYMBOL(ipt_unregister_match); EXPORT_SYMBOL(ipt_do_table); EXPORT_SYMBOL(ipt_register_target); EXPORT_SYMBOL(ipt_unregister_target); -EXPORT_SYMBOL(ipt_find_target_lock); module_init(init); module_exit(fini); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index b941c00dd..a2384c2e2 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -102,6 +102,38 @@ static void raw_v4_unhash(struct sock *sk) write_unlock_bh(&raw_v4_lock); } + +/* + Check if an address is in the list +*/ +static inline int raw_addr_in_list ( + u32 rcv_saddr1, + u32 rcv_saddr2, + u32 loc_addr, + struct nx_info *nx_info) +{ + int ret = 0; + if (loc_addr != 0 && + (rcv_saddr1 == loc_addr || rcv_saddr2 == loc_addr)) + ret = 1; + else if (rcv_saddr1 == 0) { + /* Accept any address or only the one in the list */ + if (nx_info == NULL) + ret = 1; + else { + int n = nx_info->nbipv4; + int i; + for (i=0; iipv4[i] == loc_addr) { + ret = 1; + break; + } + } + } + } + return ret; +} + struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, unsigned long raddr, unsigned long laddr, int dif) @@ -113,7 +145,8 @@ struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, if (inet->num == num && !(inet->daddr && inet->daddr != raddr) && - !(inet->rcv_saddr && inet->rcv_saddr != laddr) && + raw_addr_in_list(inet->rcv_saddr, inet->rcv_saddr2, + laddr, sk->sk_nx_info) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) goto found; /* gotcha */ } @@ -647,7 +680,7 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) default: #ifdef CONFIG_IP_MROUTE - return ipmr_ioctl(sk, cmd, (void __user *)arg); + return ipmr_ioctl(sk, cmd, arg); #else return -ENOIOCTLCMD; #endif @@ -687,7 +720,8 @@ static struct sock *raw_get_first(struct seq_file *seq) struct hlist_node *node; sk_for_each(sk, node, &raw_v4_htable[state->bucket]) - if (sk->sk_family == PF_INET) + if (sk->sk_family == PF_INET && + vx_check(sk->sk_xid, VX_WATCH|VX_IDENT)) goto found; } sk = NULL; @@ -703,7 +737,8 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_family != PF_INET); + } while (sk && (sk->sk_family != PF_INET || + !vx_check(sk->sk_xid, VX_WATCH|VX_IDENT))); if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) { sk = sk_head(&raw_v4_htable[state->bucket]); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a570e709f..6e7cbd378 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -138,7 +138,6 @@ static struct timer_list rt_secret_timer; static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); static void ipv4_dst_destroy(struct dst_entry *dst); -static void ipv4_dst_ifdown(struct dst_entry *dst, int how); static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -151,7 +150,6 @@ static struct dst_ops ipv4_dst_ops = { .gc = rt_garbage_collect, .check = ipv4_dst_check, .destroy = ipv4_dst_destroy, - .ifdown = ipv4_dst_ifdown, .negative_advice = ipv4_negative_advice, .link_failure = ipv4_link_failure, .update_pmtu = ip_rt_update_pmtu, @@ -1338,16 +1336,6 @@ static void ipv4_dst_destroy(struct dst_entry *dst) } } -static void ipv4_dst_ifdown(struct dst_entry *dst, int how) -{ - struct rtable *rt = (struct rtable *) dst; - struct in_device *idev = rt->idev; - if (idev) { - rt->idev = NULL; - in_dev_put(idev); - } -} - static void ipv4_link_failure(struct sk_buff *skb) { struct rtable *rt; @@ -1359,10 +1347,8 @@ static void ipv4_link_failure(struct sk_buff *skb) dst_set_expires(&rt->u.dst, 0); } -static int ip_rt_bug(struct sk_buff **pskb) +static int ip_rt_bug(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - printk(KERN_DEBUG "ip_rt_bug: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->dev ? skb->dev->name : "?"); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 260cb4032..ba59e7fa4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -256,6 +256,7 @@ #include #include #include +#include #include #include @@ -536,13 +537,34 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) int tcp_listen_start(struct sock *sk) { +#ifdef CONFIG_ACCEPT_QUEUES + int i = 0; +#endif struct inet_opt *inet = inet_sk(sk); struct tcp_opt *tp = tcp_sk(sk); struct tcp_listen_opt *lopt; sk->sk_max_ack_backlog = 0; sk->sk_ack_backlog = 0; - tp->accept_queue = tp->accept_queue_tail = NULL; + tp->accept_queue = NULL; +#ifdef CONFIG_ACCEPT_QUEUES + tp->class_index = 0; + for (i=0; i < NUM_ACCEPT_QUEUES; i++) { + tp->acceptq[i].aq_tail = NULL; + tp->acceptq[i].aq_head = NULL; + tp->acceptq[i].aq_wait_time = 0; + tp->acceptq[i].aq_qcount = 0; + tp->acceptq[i].aq_count = 0; + if (i == 0) { + tp->acceptq[i].aq_valid = 1; + tp->acceptq[i].aq_ratio = 1; + } + else { + tp->acceptq[i].aq_valid = 0; + tp->acceptq[i].aq_ratio = 0; + } + } +#endif tp->syn_wait_lock = RW_LOCK_UNLOCKED; tcp_delack_init(tp); @@ -572,6 +594,10 @@ int tcp_listen_start(struct sock *sk) sk_dst_reset(sk); sk->sk_prot->hash(sk); +#ifdef CONFIG_CKRM + ckrm_cb_listen_start(sk); +#endif + return 0; } @@ -602,7 +628,18 @@ static void tcp_listen_stop (struct sock *sk) write_lock_bh(&tp->syn_wait_lock); tp->listen_opt = NULL; write_unlock_bh(&tp->syn_wait_lock); - tp->accept_queue = tp->accept_queue_tail = NULL; + +#ifdef CONFIG_CKRM + ckrm_cb_listen_stop(sk); +#endif + +#ifdef CONFIG_ACCEPT_QUEUES + for (i = 0; i < NUM_ACCEPT_QUEUES; i++) + tp->acceptq[i].aq_head = tp->acceptq[i].aq_tail = NULL; +#else + tp->accept_queue_tail = NULL; +#endif + tp->accept_queue = NULL; if (lopt->qlen) { for (i = 0; i < TCP_SYNQ_HSIZE; i++) { @@ -648,7 +685,11 @@ static void tcp_listen_stop (struct sock *sk) local_bh_enable(); sock_put(child); - sk_acceptq_removed(sk); +#ifdef CONFIG_ACCEPT_QUEUES + tcp_acceptq_removed(sk, req->acceptq_class); +#else + tcp_acceptq_removed(sk); +#endif tcp_openreq_fastfree(req); } BUG_TRAP(!sk->sk_ack_backlog); @@ -1296,13 +1337,25 @@ static int tcp_recv_urg(struct sock *sk, long timeo, return -EAGAIN; } +/* + * Release a skb if it is no longer needed. This routine + * must be called with interrupts disabled or with the + * socket locked so that the sk_buff queue operation is ok. + */ + +static inline void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) +{ + __skb_unlink(skb, &sk->sk_receive_queue); + __kfree_skb(skb); +} + /* Clean up the receive buffer for full frames taken by the user, * then send an ACK if necessary. COPIED is the number of bytes * tcp_recvmsg has given to the user so far, it speeds up the * calculation of whether or not we must ACK for the sake of * a window update. */ -static void cleanup_rbuf(struct sock *sk, int copied) +void cleanup_rbuf(struct sock *sk, int copied) { struct tcp_opt *tp = tcp_sk(sk); int time_to_ack = 0; @@ -1356,6 +1409,31 @@ static void cleanup_rbuf(struct sock *sk, int copied) tcp_send_ack(sk); } +/* Now socket state including sk->sk_err is changed only under lock, + * hence we may omit checks after joining wait queue. + * We check receive queue before schedule() only as optimization; + * it is very likely that release_sock() added new data. + */ + +static long tcp_data_wait(struct sock *sk, long timeo) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + release_sock(sk); + + if (skb_queue_empty(&sk->sk_receive_queue)) + timeo = schedule_timeout(timeo); + + lock_sock(sk); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + + finish_wait(sk->sk_sleep, &wait); + return timeo; +} + static void tcp_prequeue_process(struct sock *sk) { struct sk_buff *skb; @@ -1436,11 +1514,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, break; } if (skb->h.th->fin) { - sk_eat_skb(sk, skb); + tcp_eat_skb(sk, skb); ++seq; break; } - sk_eat_skb(sk, skb); + tcp_eat_skb(sk, skb); if (!desc->count) break; } @@ -1635,8 +1713,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Do not sleep, just process backlog. */ release_sock(sk); lock_sock(sk); - } else - sk_wait_data(sk, &timeo); + } else { + timeo = tcp_data_wait(sk, timeo); + } if (user_recv) { int chunk; @@ -1720,14 +1799,14 @@ skip_copy: if (skb->h.th->fin) goto found_fin_ok; if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); + tcp_eat_skb(sk, skb); continue; found_fin_ok: /* Process the FIN. */ ++*seq; if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); + tcp_eat_skb(sk, skb); break; } while (len > 0); @@ -2196,6 +2275,10 @@ struct sock *tcp_accept(struct sock *sk, int flags, int *err) struct open_request *req; struct sock *newsk; int error; +#ifdef CONFIG_ACCEPT_QUEUES + int prev_class = 0; + int first; +#endif lock_sock(sk); @@ -2209,7 +2292,6 @@ struct sock *tcp_accept(struct sock *sk, int flags, int *err) /* Find already established connection */ if (!tp->accept_queue) { long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); - /* If this is a non blocking socket don't sleep */ error = -EAGAIN; if (!timeo) @@ -2220,12 +2302,46 @@ struct sock *tcp_accept(struct sock *sk, int flags, int *err) goto out; } +#ifndef CONFIG_ACCEPT_QUEUES req = tp->accept_queue; if ((tp->accept_queue = req->dl_next) == NULL) tp->accept_queue_tail = NULL; + tcp_acceptq_removed(sk); +#else + first = tp->class_index; + /* We should always have request queued here. The accept_queue + * is already checked for NULL above. + */ + while(!tp->acceptq[first].aq_head) { + tp->acceptq[first].aq_cnt = 0; + first = (first+1) & ~NUM_ACCEPT_QUEUES; + } + req = tp->acceptq[first].aq_head; + tp->acceptq[first].aq_qcount--; + tp->acceptq[first].aq_count++; + tp->acceptq[first].aq_wait_time+=(jiffies - req->acceptq_time_stamp); + + for (prev_class= first-1 ; prev_class >=0; prev_class--) + if (tp->acceptq[prev_class].aq_tail) + break; + if (prev_class>=0) + tp->acceptq[prev_class].aq_tail->dl_next = req->dl_next; + else + tp->accept_queue = req->dl_next; + + if (req == tp->acceptq[first].aq_tail) + tp->acceptq[first].aq_head = tp->acceptq[first].aq_tail = NULL; + else + tp->acceptq[first].aq_head = req->dl_next; + + if((++(tp->acceptq[first].aq_cnt)) >= tp->acceptq[first].aq_ratio){ + tp->acceptq[first].aq_cnt = 0; + tp->class_index = ++first & ~NUM_ACCEPT_QUEUES; + } + tcp_acceptq_removed(sk, req->acceptq_class); +#endif newsk = req->sk; - sk_acceptq_removed(sk); tcp_openreq_fastfree(req); BUG_TRAP(newsk->sk_state != TCP_SYN_RECV); release_sock(sk); @@ -2395,6 +2511,49 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, } } break; + +#ifdef CONFIG_ACCEPT_QUEUES + case TCP_ACCEPTQ_SHARE: + { + char share_wt[NUM_ACCEPT_QUEUES]; + int i,j; + + if (sk->sk_state != TCP_LISTEN) + return -EOPNOTSUPP; + + if (copy_from_user(share_wt,optval, optlen)) { + err = -EFAULT; + break; + } + j = 0; + for (i = 0; i < NUM_ACCEPT_QUEUES; i++) { + if (share_wt[i]) { + if (!j) + j = share_wt[i]; + else if (share_wt[i] < j) { + j = share_wt[i]; + } + tp->acceptq[i].aq_valid = 1; + } + else + tp->acceptq[i].aq_valid = 0; + + } + if (j == 0) { + /* Class 0 is always valid. If nothing is + * specified set class 0 as 1. + */ + share_wt[0] = 1; + tp->acceptq[0].aq_valid = 1; + j = 1; + } + for (i=0; i < NUM_ACCEPT_QUEUES; i++) { + tp->acceptq[i].aq_ratio = share_wt[i]/j; + tp->acceptq[i].aq_cnt = 0; + } + } + break; +#endif default: err = -ENOPROTOOPT; @@ -2460,11 +2619,56 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, break; case TCP_INFO: { struct tcp_info info; + u32 now = tcp_time_stamp; if (get_user(len, optlen)) return -EFAULT; - - tcp_get_info(sk, &info); + info.tcpi_state = sk->sk_state; + info.tcpi_ca_state = tp->ca_state; + info.tcpi_retransmits = tp->retransmits; + info.tcpi_probes = tp->probes_out; + info.tcpi_backoff = tp->backoff; + info.tcpi_options = 0; + if (tp->tstamp_ok) + info.tcpi_options |= TCPI_OPT_TIMESTAMPS; + if (tp->sack_ok) + info.tcpi_options |= TCPI_OPT_SACK; + if (tp->wscale_ok) { + info.tcpi_options |= TCPI_OPT_WSCALE; + info.tcpi_snd_wscale = tp->snd_wscale; + info.tcpi_rcv_wscale = tp->rcv_wscale; + } else { + info.tcpi_snd_wscale = 0; + info.tcpi_rcv_wscale = 0; + } + if (tp->ecn_flags & TCP_ECN_OK) + info.tcpi_options |= TCPI_OPT_ECN; + + info.tcpi_rto = (1000000 * tp->rto) / HZ; + info.tcpi_ato = (1000000 * tp->ack.ato) / HZ; + info.tcpi_snd_mss = tp->mss_cache_std; + info.tcpi_rcv_mss = tp->ack.rcv_mss; + + info.tcpi_unacked = tp->packets_out; + info.tcpi_sacked = tp->sacked_out; + info.tcpi_lost = tp->lost_out; + info.tcpi_retrans = tp->retrans_out; + info.tcpi_fackets = tp->fackets_out; + + info.tcpi_last_data_sent = ((now - tp->lsndtime) * 1000) / HZ; + info.tcpi_last_ack_sent = 0; + info.tcpi_last_data_recv = ((now - + tp->ack.lrcvtime) * 1000) / HZ; + info.tcpi_last_ack_recv = ((now - tp->rcv_tstamp) * 1000) / HZ; + + info.tcpi_pmtu = tp->pmtu_cookie; + info.tcpi_rcv_ssthresh = tp->rcv_ssthresh; + info.tcpi_rtt = ((1000000 * tp->srtt) / HZ) >> 3; + info.tcpi_rttvar = ((1000000 * tp->mdev) / HZ) >> 2; + info.tcpi_snd_ssthresh = tp->snd_ssthresh; + info.tcpi_snd_cwnd = tp->snd_cwnd; + info.tcpi_advmss = tp->advmss; + info.tcpi_reordering = tp->reordering; len = min_t(unsigned int, len, sizeof(info)); if (put_user(len, optlen)) @@ -2476,6 +2680,41 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, case TCP_QUICKACK: val = !tp->ack.pingpong; break; + +#ifdef CONFIG_ACCEPT_QUEUES + case TCP_ACCEPTQ_SHARE: { + struct tcp_acceptq_info tinfo[NUM_ACCEPT_QUEUES]; + int i; + + if (sk->sk_state != TCP_LISTEN) + return -EOPNOTSUPP; + + if (get_user(len, optlen)) + return -EFAULT; + + memset(tinfo, 0, sizeof(tinfo)); + + for(i=0; i < NUM_ACCEPT_QUEUES; i++) { + tinfo[i].acceptq_wait_time = + tp->acceptq[i].aq_wait_time/(HZ/USER_HZ); + tinfo[i].acceptq_qcount = tp->acceptq[i].aq_qcount; + tinfo[i].acceptq_count = tp->acceptq[i].aq_count; + if (tp->acceptq[i].aq_valid) + tinfo[i].acceptq_shares=tp->acceptq[i].aq_ratio; + else + tinfo[i].acceptq_shares = 0; + } + + len = min_t(unsigned int, len, sizeof(tinfo)); + if (put_user(len, optlen)) + return -EFAULT; + + if (copy_to_user(optval, (char *)tinfo, len)) + return -EFAULT; + + return 0; + } +#endif default: return -ENOPROTOOPT; }; @@ -2636,3 +2875,4 @@ EXPORT_SYMBOL(tcp_sockets_allocated); EXPORT_SYMBOL(tcp_statistics); EXPORT_SYMBOL(tcp_timewait_cachep); EXPORT_SYMBOL(tcp_write_space); +EXPORT_SYMBOL_GPL(cleanup_rbuf); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c0a0b65f5..708005f0d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -463,8 +463,6 @@ void tcp_rcv_space_adjust(struct sock *sk) tp->rcvq_space.space = space; if (sysctl_tcp_moderate_rcvbuf) { - int new_clamp = space; - /* Receive space grows, normalize in order to * take into account packet headers and sk_buff * structure overhead. @@ -474,16 +472,10 @@ void tcp_rcv_space_adjust(struct sock *sk) space = 1; rcvmem = (tp->advmss + MAX_TCP_HEADER + 16 + sizeof(struct sk_buff)); - while (tcp_win_from_space(rcvmem) < tp->advmss) - rcvmem += 128; space *= rcvmem; space = min(space, sysctl_tcp_rmem[2]); - if (space > sk->sk_rcvbuf) { + if (space > sk->sk_rcvbuf) sk->sk_rcvbuf = space; - - /* Make the window clamp follow along. */ - tp->window_clamp = new_clamp; - } } } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e5d1364dd..4a2a11b76 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -179,9 +179,63 @@ void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, tcp_sk(sk)->bind_hash = tb; } +/* + Return 1 if addr match the socket IP list + or the socket is INADDR_ANY +*/ +static inline int tcp_in_list(struct sock *sk, u32 addr) +{ + struct nx_info *nxi = sk->sk_nx_info; + + vxdprintk("tcp_in_list(%p) %p,%p;%lx\n", + sk, nxi, sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + + if (nxi) { + int n = nxi->nbipv4; + int i; + + for (i=0; iipv4[i] == addr) + return 1; + } + else if (!tcp_v4_rcv_saddr(sk) || tcp_v4_rcv_saddr(sk) == addr) + return 1; + return 0; +} + +/* + Check if the addresses in sk1 conflict with those in sk2 +*/ +int tcp_ipv4_addr_conflict(struct sock *sk1, struct sock *sk2) +{ + if (sk1 && sk2) + nxdprintk("inet_bind(%p,%p) %p,%p;%lx %p,%p;%lx\n", + sk1, sk2, + sk1->sk_nx_info, sk1->sk_socket, + (sk1->sk_socket?sk1->sk_socket->flags:0), + sk2->sk_nx_info, sk2->sk_socket, + (sk2->sk_socket?sk2->sk_socket->flags:0)); + + if (tcp_v4_rcv_saddr(sk1)) { + /* Bind to one address only */ + return tcp_in_list (sk2, tcp_v4_rcv_saddr(sk1)); + } else if (sk1->sk_nx_info) { + /* A restricted bind(any) */ + struct nx_info *nxi = sk1->sk_nx_info; + int n = nxi->nbipv4; + int i; + + for (i=0; iipv4[i])) + return 1; + } else /* A bind(any) do not allow other bind on the same port */ + return 1; + return 0; +} + static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) { - const u32 sk_rcv_saddr = tcp_v4_rcv_saddr(sk); struct sock *sk2; struct hlist_node *node; int reuse = sk->sk_reuse; @@ -194,9 +248,7 @@ static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { if (!reuse || !sk2->sk_reuse || sk2->sk_state == TCP_LISTEN) { - const u32 sk2_rcv_saddr = tcp_v4_rcv_saddr(sk2); - if (!sk2_rcv_saddr || !sk_rcv_saddr || - sk2_rcv_saddr == sk_rcv_saddr) + if (tcp_ipv4_addr_conflict(sk, sk2)) break; } } @@ -405,6 +457,34 @@ void tcp_unhash(struct sock *sk) wake_up(&tcp_lhash_wait); } +/* + Check if an address is in the list +*/ +static inline int tcp_addr_in_list( + u32 rcv_saddr, + u32 daddr, + struct nx_info *nx_info) +{ + if (rcv_saddr == daddr) + return 1; + else if (rcv_saddr == 0) { + /* Accept any address or check the list */ + if (!nx_info) + return 1; + else { + int n = nx_info->nbipv4; + int i; + + for (i=0; iipv4[i] == daddr) + return 1; + } + } + return 0; +} + + + /* Don't inline this cruft. Here are some nice properties to * exploit here. The BSD API does not allow a listening TCP * to specify the remote port nor the remote address for the @@ -426,11 +506,10 @@ static struct sock *__tcp_v4_lookup_listener(struct hlist_head *head, u32 daddr, __u32 rcv_saddr = inet->rcv_saddr; score = (sk->sk_family == PF_INET ? 1 : 0); - if (rcv_saddr) { - if (rcv_saddr != daddr) - continue; + if (tcp_addr_in_list(rcv_saddr, daddr, sk->sk_nx_info)) score+=2; - } + else + continue; if (sk->sk_bound_dev_if) { if (sk->sk_bound_dev_if != dif) continue; @@ -458,10 +537,9 @@ inline struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, head = &tcp_listening_hash[tcp_lhashfn(hnum)]; if (!hlist_empty(head)) { struct inet_opt *inet = inet_sk((sk = __sk_head(head))); - if (inet->num == hnum && !sk->sk_node.next && - (!inet->rcv_saddr || inet->rcv_saddr == daddr) && (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && + tcp_addr_in_list(inet->rcv_saddr, daddr, sk->sk_nx_info) && !sk->sk_bound_dev_if) goto sherry_cache; sk = __tcp_v4_lookup_listener(head, daddr, hnum, dif); @@ -916,7 +994,11 @@ static void tcp_v4_synq_add(struct sock *sk, struct open_request *req) lopt->syn_table[h] = req; write_unlock(&tp->syn_wait_lock); +#ifdef CONFIG_ACCEPT_QUEUES + tcp_synq_added(sk, req); +#else tcp_synq_added(sk); +#endif } @@ -1413,6 +1495,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) __u32 daddr = skb->nh.iph->daddr; __u32 isn = TCP_SKB_CB(skb)->when; struct dst_entry *dst = NULL; +#ifdef CONFIG_ACCEPT_QUEUES + int class = 0; +#endif #ifdef CONFIG_SYN_COOKIES int want_cookie = 0; #else @@ -1437,12 +1522,31 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop; } +#ifdef CONFIG_ACCEPT_QUEUES + class = (skb->nfmark <= 0) ? 0 : + ((skb->nfmark >= NUM_ACCEPT_QUEUES) ? 0: skb->nfmark); + /* + * Accept only if the class has shares set or if the default class + * i.e. class 0 has shares + */ + if (!(tcp_sk(sk)->acceptq[class].aq_valid)) { + if (tcp_sk(sk)->acceptq[0].aq_valid) + class = 0; + else + goto drop; + } +#endif + /* Accept backlog is full. If we have already queued enough * of warm entries in syn queue, drop request. It is better than * clogging syn queue with openreqs with exponentially increasing * timeout. */ - if (sk_acceptq_is_full(sk) && tcp_synq_young(sk) > 1) +#ifdef CONFIG_ACCEPT_QUEUES + if (tcp_acceptq_is_full(sk, class) && tcp_synq_young(sk, class) > 1) +#else + if (tcp_acceptq_is_full(sk) && tcp_synq_young(sk) > 1) +#endif goto drop; req = tcp_openreq_alloc(); @@ -1472,7 +1576,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tp.tstamp_ok = tp.saw_tstamp; tcp_openreq_init(req, &tp, skb); - +#ifdef CONFIG_ACCEPT_QUEUES + req->acceptq_class = class; + req->acceptq_time_stamp = jiffies; +#endif req->af.v4_req.loc_addr = daddr; req->af.v4_req.rmt_addr = saddr; req->af.v4_req.opt = tcp_v4_save_options(sk, skb); @@ -1567,7 +1674,11 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct tcp_opt *newtp; struct sock *newsk; - if (sk_acceptq_is_full(sk)) +#ifdef CONFIG_ACCEPT_QUEUES + if (tcp_acceptq_is_full(sk, req->acceptq_class)) +#else + if (tcp_acceptq_is_full(sk)) +#endif goto exit_overflow; if (!dst && (dst = tcp_v4_route_req(sk, req)) == NULL) @@ -2159,6 +2270,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur) req = req->dl_next; while (1) { while (req) { + if (!vx_check(req->sk->sk_xid, VX_IDENT|VX_WATCH)) + continue; if (req->class->family == st->family) { cur = req; goto out; @@ -2177,6 +2290,8 @@ get_req: sk = sk_next(sk); get_sk: sk_for_each_from(sk, node) { + if (!vx_check(sk->sk_xid, VX_IDENT|VX_WATCH)) + continue; if (sk->sk_family == st->family) { cur = sk; goto out; @@ -2224,18 +2339,20 @@ static void *established_get_first(struct seq_file *seq) read_lock(&tcp_ehash[st->bucket].lock); sk_for_each(sk, node, &tcp_ehash[st->bucket].chain) { - if (sk->sk_family != st->family) { + if (!vx_check(sk->sk_xid, VX_IDENT|VX_WATCH)) + continue; + if (sk->sk_family != st->family) continue; - } rc = sk; goto out; } st->state = TCP_SEQ_STATE_TIME_WAIT; tw_for_each(tw, node, &tcp_ehash[st->bucket + tcp_ehash_size].chain) { - if (tw->tw_family != st->family) { + if (!vx_check(tw->tw_xid, VX_IDENT|VX_WATCH)) + continue; + if (tw->tw_family != st->family) continue; - } rc = tw; goto out; } @@ -2259,7 +2376,8 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && tw->tw_family != st->family) { + while (tw && tw->tw_family != st->family && + !vx_check(tw->tw_xid, VX_IDENT|VX_WATCH)) { tw = tw_next(tw); } if (tw) { @@ -2279,6 +2397,8 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { + if (!vx_check(sk->sk_xid, VX_IDENT|VX_WATCH)) + continue; if (sk->sk_family == st->family) goto found; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index d4c0d84d1..a6a7828bd 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -362,6 +362,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_ts_recent_stamp = tp->ts_recent_stamp; tw_dead_node_init(tw); + tw->tw_xid = sk->sk_xid; + tw->tw_vx_info = NULL; + tw->tw_nid = sk->sk_nid; + tw->tw_nx_info = NULL; + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (tw->tw_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); @@ -697,6 +702,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newsk->sk_state = TCP_SYN_RECV; /* SANITY */ + sock_vx_init(newsk); + sock_nx_init(newsk); sk_node_init(&newsk->sk_node); tcp_sk(newsk)->bind_hash = NULL; @@ -725,6 +732,9 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, if ((filter = newsk->sk_filter) != NULL) sk_filter_charge(newsk, filter); + if (sk->sk_create_child) + sk->sk_create_child(sk, newsk); + if (unlikely(xfrm_sk_clone_policy(newsk))) { /* It is still raw copy of parent, so invalidate * destructor and make plain sk_free() */ @@ -790,7 +800,14 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->num_sacks = 0; newtp->urg_data = 0; newtp->listen_opt = NULL; +#ifdef CONFIG_ACCEPT_QUEUES + newtp->accept_queue = NULL; + memset(newtp->acceptq, 0,sizeof(newtp->acceptq)); + newtp->class_index = 0; + +#else newtp->accept_queue = newtp->accept_queue_tail = NULL; +#endif /* Deinitialize syn_wait_lock to trap illegal accesses. */ memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock)); @@ -798,6 +815,10 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newsk->sk_err = 0; newsk->sk_priority = 0; atomic_set(&newsk->sk_refcnt, 2); + + /* hmm, maybe from socket? */ + set_vx_info(&newsk->sk_vx_info, current->vx_info); + set_nx_info(&newsk->sk_nx_info, current->nx_info); #ifdef INET_REFCNT_DEBUG atomic_inc(&inet_sock_nr); #endif diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index cab2678b1..695f8befa 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -68,13 +68,18 @@ void tcp_clear_xmit_timers(struct sock *sk) struct tcp_opt *tp = tcp_sk(sk); tp->pending = 0; - sk_stop_timer(sk, &tp->retransmit_timer); + if (timer_pending(&tp->retransmit_timer) && + del_timer(&tp->retransmit_timer)) + __sock_put(sk); tp->ack.pending = 0; tp->ack.blocked = 0; - sk_stop_timer(sk, &tp->delack_timer); + if (timer_pending(&tp->delack_timer) && + del_timer(&tp->delack_timer)) + __sock_put(sk); - sk_stop_timer(sk, &sk->sk_timer); + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) + __sock_put(sk); } static void tcp_write_err(struct sock *sk) @@ -213,7 +218,8 @@ static void tcp_delack_timer(unsigned long data) /* Try again later. */ tp->ack.blocked = 1; NET_INC_STATS_BH(DelayedACKLocked); - sk_reset_timer(sk, &tp->delack_timer, jiffies + TCP_DELACK_MIN); + if (!mod_timer(&tp->delack_timer, jiffies + TCP_DELACK_MIN)) + sock_hold(sk); goto out_unlock; } @@ -223,7 +229,8 @@ static void tcp_delack_timer(unsigned long data) goto out; if (time_after(tp->ack.timeout, jiffies)) { - sk_reset_timer(sk, &tp->delack_timer, tp->ack.timeout); + if (!mod_timer(&tp->delack_timer, tp->ack.timeout)) + sock_hold(sk); goto out; } tp->ack.pending &= ~TCP_ACK_TIMER; @@ -422,7 +429,8 @@ static void tcp_write_timer(unsigned long data) bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* Try again later */ - sk_reset_timer(sk, &tp->retransmit_timer, jiffies + (HZ / 20)); + if (!mod_timer(&tp->retransmit_timer, jiffies + (HZ/20))) + sock_hold(sk); goto out_unlock; } @@ -430,7 +438,8 @@ static void tcp_write_timer(unsigned long data) goto out; if (time_after(tp->timeout, jiffies)) { - sk_reset_timer(sk, &tp->retransmit_timer, tp->timeout); + if (!mod_timer(&tp->retransmit_timer, tp->timeout)) + sock_hold(sk); goto out; } @@ -489,7 +498,16 @@ static void tcp_synack_timer(struct sock *sk) * ones are about to clog our table. */ if (lopt->qlen>>(lopt->max_qlen_log-1)) { +#ifdef CONFIG_ACCEPT_QUEUES + int young = 0; + + for(i=0; i < NUM_ACCEPT_QUEUES; i++) + young += lopt->qlen_young[i]; + + young <<= 1; +#else int young = (lopt->qlen_young<<1); +#endif while (thresh > 2) { if (lopt->qlen < young) @@ -515,9 +533,12 @@ static void tcp_synack_timer(struct sock *sk) unsigned long timeo; if (req->retrans++ == 0) - lopt->qlen_young--; - timeo = min((TCP_TIMEOUT_INIT << req->retrans), - TCP_RTO_MAX); +#ifdef CONFIG_ACCEPT_QUEUES + lopt->qlen_young[req->acceptq_class]--; +#else + lopt->qlen_young--; +#endif + timeo = min((TCP_TIMEOUT_INIT << req->retrans), TCP_RTO_MAX); req->expires = now + timeo; reqp = &req->dl_next; continue; @@ -529,7 +550,11 @@ static void tcp_synack_timer(struct sock *sk) write_unlock(&tp->syn_wait_lock); lopt->qlen--; if (req->retrans == 0) - lopt->qlen_young--; +#ifdef CONFIG_ACCEPT_QUEUES + lopt->qlen_young[req->acceptq_class]--; +#else + lopt->qlen_young--; +#endif tcp_openreq_free(req); continue; } @@ -548,12 +573,14 @@ static void tcp_synack_timer(struct sock *sk) void tcp_delete_keepalive_timer (struct sock *sk) { - sk_stop_timer(sk, &sk->sk_timer); + if (timer_pending(&sk->sk_timer) && del_timer (&sk->sk_timer)) + __sock_put(sk); } void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len) { - sk_reset_timer(sk, &sk->sk_timer, jiffies + len); + if (!mod_timer(&sk->sk_timer, jiffies + len)) + sock_hold(sk); } void tcp_set_keepalive(struct sock *sk, int val) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a58375168..dec547c4b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -120,6 +120,8 @@ rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; /* Shared by v4/v6 udp. */ int udp_port_rover; +int tcp_ipv4_addr_conflict(struct sock *sk1, struct sock *sk2); + static int udp_v4_get_port(struct sock *sk, unsigned short snum) { struct hlist_node *node; @@ -179,9 +181,7 @@ gotit: (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (!inet2->rcv_saddr || - !inet->rcv_saddr || - inet2->rcv_saddr == inet->rcv_saddr) && + tcp_ipv4_addr_conflict(sk2, sk) && (!sk2->sk_reuse || !sk->sk_reuse)) goto fail; } @@ -216,6 +216,17 @@ static void udp_v4_unhash(struct sock *sk) write_unlock_bh(&udp_hash_lock); } +static inline int udp_in_list(struct nx_info *nx_info, u32 addr) +{ + int n = nx_info->nbipv4; + int i; + + for (i=0; iipv4[i] == addr) + return 1; + return 0; +} + /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ @@ -235,6 +246,11 @@ struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, i if (inet->rcv_saddr != daddr) continue; score+=2; + } else if (sk->sk_nx_info) { + if (udp_in_list(sk->sk_nx_info, daddr)) + score+=2; + else + continue; } if (inet->daddr) { if (inet->daddr != saddr) @@ -290,11 +306,12 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk, if (inet->num != hnum || (inet->daddr && inet->daddr != rmt_addr) || (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + (inet->rcv_saddr && inet->rcv_saddr != loc_addr && + inet->rcv_saddr2 && inet->rcv_saddr2 != loc_addr) || ipv6_only_sock(s) || (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; - if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) + if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif)) continue; goto found; } @@ -599,6 +616,15 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; + struct nx_info *nxi = sk->sk_nx_info; + + if (nxi) { + err = ip_find_src(nxi, &rt, &fl); + if (err) + goto out; + if (daddr == IPI_LOOPBACK && !vx_check(0, VX_ADMIN)) + daddr = fl.fl4_dst = nxi->ipv4[0]; + } err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); if (err) goto out; @@ -1374,8 +1400,10 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; + sk_for_each(sk, node, &udp_hash[state->bucket]) { - if (sk->sk_family == state->family) + if (sk->sk_family == state->family && + vx_check(sk->sk_xid, VX_WATCH|VX_IDENT)) goto found; } } @@ -1392,7 +1420,8 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_family != state->family); + } while (sk && (sk->sk_family != state->family || + !vx_check(sk->sk_xid, VX_WATCH|VX_IDENT))); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(&udp_hash[state->bucket]); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 185092c0d..81c5d9766 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -144,11 +144,11 @@ static int ipv6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int d return nexthdr; } -int ah6_output(struct sk_buff **pskb) +int ah6_output(struct sk_buff *skb) { int err; int hdr_len = sizeof(struct ipv6hdr); - struct dst_entry *dst = (*pskb)->dst; + struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; struct ipv6hdr *iph = NULL; struct ip_auth_hdr *ah; @@ -156,55 +156,54 @@ int ah6_output(struct sk_buff **pskb) u16 nh_offset = 0; u8 nexthdr; - if ((*pskb)->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - if (err) - goto error_nolock; + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; } spin_lock_bh(&x->lock); - err = xfrm_check_output(x, *pskb, AF_INET6); + err = xfrm_check_output(x, skb, AF_INET6); if (err) goto error; if (x->props.mode) { - iph = (*pskb)->nh.ipv6h; - (*pskb)->nh.ipv6h = (struct ipv6hdr*)skb_push(*pskb, x->props.header_len); - (*pskb)->nh.ipv6h->version = 6; - (*pskb)->nh.ipv6h->payload_len = htons((*pskb)->len - sizeof(struct ipv6hdr)); - (*pskb)->nh.ipv6h->nexthdr = IPPROTO_AH; - ipv6_addr_copy(&(*pskb)->nh.ipv6h->saddr, + iph = skb->nh.ipv6h; + skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, x->props.header_len); + skb->nh.ipv6h->version = 6; + skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + skb->nh.ipv6h->nexthdr = IPPROTO_AH; + ipv6_addr_copy(&skb->nh.ipv6h->saddr, (struct in6_addr *) &x->props.saddr); - ipv6_addr_copy(&(*pskb)->nh.ipv6h->daddr, + ipv6_addr_copy(&skb->nh.ipv6h->daddr, (struct in6_addr *) &x->id.daddr); - ah = (struct ip_auth_hdr*)((*pskb)->nh.ipv6h+1); + ah = (struct ip_auth_hdr*)(skb->nh.ipv6h+1); ah->nexthdr = IPPROTO_IPV6; } else { - hdr_len = (*pskb)->h.raw - (*pskb)->nh.raw; + hdr_len = skb->h.raw - skb->nh.raw; iph = kmalloc(hdr_len, GFP_ATOMIC); if (!iph) { err = -ENOMEM; goto error; } - memcpy(iph, (*pskb)->data, hdr_len); - (*pskb)->nh.ipv6h = (struct ipv6hdr*)skb_push(*pskb, x->props.header_len); - memcpy((*pskb)->nh.ipv6h, iph, hdr_len); - nexthdr = ipv6_clear_mutable_options(*pskb, &nh_offset, XFRM_POLICY_OUT); + memcpy(iph, skb->data, hdr_len); + skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, x->props.header_len); + memcpy(skb->nh.ipv6h, iph, hdr_len); + nexthdr = ipv6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_OUT); if (nexthdr == 0) goto error_free_iph; - (*pskb)->nh.raw[nh_offset] = IPPROTO_AH; - (*pskb)->nh.ipv6h->payload_len = htons((*pskb)->len - sizeof(struct ipv6hdr)); - ah = (struct ip_auth_hdr*)((*pskb)->nh.raw+hdr_len); - (*pskb)->h.raw = (unsigned char*) ah; + skb->nh.raw[nh_offset] = IPPROTO_AH; + skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + ah = (struct ip_auth_hdr*)(skb->nh.raw+hdr_len); + skb->h.raw = (unsigned char*) ah; ah->nexthdr = nexthdr; } - (*pskb)->nh.ipv6h->priority = 0; - (*pskb)->nh.ipv6h->flow_lbl[0] = 0; - (*pskb)->nh.ipv6h->flow_lbl[1] = 0; - (*pskb)->nh.ipv6h->flow_lbl[2] = 0; - (*pskb)->nh.ipv6h->hop_limit = 0; + skb->nh.ipv6h->priority = 0; + skb->nh.ipv6h->flow_lbl[0] = 0; + skb->nh.ipv6h->flow_lbl[1] = 0; + skb->nh.ipv6h->flow_lbl[2] = 0; + skb->nh.ipv6h->hop_limit = 0; ahp = x->data; ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + @@ -213,29 +212,29 @@ int ah6_output(struct sk_buff **pskb) ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(++x->replay.oseq); - ahp->icv(ahp, *pskb, ah->auth_data); + ahp->icv(ahp, skb, ah->auth_data); if (x->props.mode) { - (*pskb)->nh.ipv6h->hop_limit = iph->hop_limit; - (*pskb)->nh.ipv6h->priority = iph->priority; - (*pskb)->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0]; - (*pskb)->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1]; - (*pskb)->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2]; + skb->nh.ipv6h->hop_limit = iph->hop_limit; + skb->nh.ipv6h->priority = iph->priority; + skb->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0]; + skb->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1]; + skb->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2]; if (x->props.flags & XFRM_STATE_NOECN) - IP6_ECN_clear((*pskb)->nh.ipv6h); + IP6_ECN_clear(skb->nh.ipv6h); } else { - memcpy((*pskb)->nh.ipv6h, iph, hdr_len); - (*pskb)->nh.raw[nh_offset] = IPPROTO_AH; - (*pskb)->nh.ipv6h->payload_len = htons((*pskb)->len - sizeof(struct ipv6hdr)); + memcpy(skb->nh.ipv6h, iph, hdr_len); + skb->nh.raw[nh_offset] = IPPROTO_AH; + skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); kfree (iph); } - (*pskb)->nh.raw = (*pskb)->data; + skb->nh.raw = skb->data; - x->curlft.bytes += (*pskb)->len; + x->curlft.bytes += skb->len; x->curlft.packets++; spin_unlock_bh(&x->lock); - if (((*pskb)->dst = dst_pop(dst)) == NULL) { + if ((skb->dst = dst_pop(dst)) == NULL) { err = -EHOSTUNREACH; goto error_nolock; } @@ -245,7 +244,7 @@ error_free_iph: error: spin_unlock_bh(&x->lock); error_nolock: - kfree_skb(*pskb); + kfree_skb(skb); return err; } @@ -363,7 +362,7 @@ void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset); struct xfrm_state *x; - if (type != ICMPV6_DEST_UNREACH && + if (type != ICMPV6_DEST_UNREACH || type != ICMPV6_PKT_TOOBIG) return; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index ff12dcf3e..a5fd7d644 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -155,7 +155,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = { static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { struct sk_buff *skb = *skbp; - struct inet6_skb_parm *opt = IP6CB(skb); + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { @@ -217,7 +217,7 @@ void __init ipv6_nodata_init(void) static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { struct sk_buff *skb = *skbp; - struct inet6_skb_parm *opt = IP6CB(skb); + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; struct in6_addr *addr; struct in6_addr daddr; int n, i; @@ -288,7 +288,7 @@ looped_back: return -1; } *skbp = skb = skb2; - opt = IP6CB(skb2); + opt = (struct inet6_skb_parm *)skb2->cb; hdr = (struct ipv6_rt_hdr *) skb2->h.raw; } @@ -418,7 +418,7 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr) static int ipv6_hop_ra(struct sk_buff *skb, int optoff) { if (skb->nh.raw[optoff+1] == 2) { - IP6CB(skb)->ra = optoff; + ((struct inet6_skb_parm*)skb->cb)->ra = optoff; return 1; } LIMIT_NETDEBUG( @@ -482,7 +482,7 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) { - IP6CB(skb)->hop = sizeof(struct ipv6hdr); + ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr); if (ip6_parse_tlv(tlvprochopopt_lst, skb)) return sizeof(struct ipv6hdr); return -1; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 0be5945d3..61695f33b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -74,7 +74,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt /* Store incoming device index. When the packet will be queued, we cannot refer to skb->dev anymore. */ - IP6CB(skb)->iif = dev->ifindex; + ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex; if (skb->len < sizeof(struct ipv6hdr)) goto err; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0057672a3..4f48168ab 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -55,7 +55,7 @@ #include #include -static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)); +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)); static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr) { @@ -107,9 +107,8 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) } -static int ip6_output2(struct sk_buff **pskb) +int ip6_output2(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; struct dst_entry *dst = skb->dst; struct net_device *dev = dst->dev; @@ -122,7 +121,7 @@ static int ip6_output2(struct sk_buff **pskb) if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr)) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); + struct sk_buff *newskb = skb_copy(skb, GFP_ATOMIC); /* Do not check for IFF_ALLMULTI; multicast routing is not supported in any case. @@ -145,14 +144,12 @@ static int ip6_output2(struct sk_buff **pskb) return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); } -int ip6_output(struct sk_buff **pskb) +int ip6_output(struct sk_buff *skb) { - struct sk_buff *skb = *pskb; - if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list)) - return ip6_fragment(pskb, ip6_output2); + return ip6_fragment(skb, ip6_output2); else - return ip6_output2(pskb); + return ip6_output2(skb); } #ifdef CONFIG_NETFILTER @@ -349,7 +346,7 @@ int ip6_forward(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = skb->nh.ipv6h; - struct inet6_skb_parm *opt = IP6CB(skb); + struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb; if (ipv6_devconf.forwarding == 0) goto error; @@ -516,11 +513,11 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } -static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)) +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct net_device *dev; - struct sk_buff *frag, *skb = *pskb; struct rt6_info *rt = (struct rt6_info*)skb->dst; + struct sk_buff *frag; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; @@ -607,13 +604,11 @@ static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**)) frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); ip6_copy_metadata(frag, skb); } - err = output(pskb); - if (err || !frag) { - if (unlikely(skb != *pskb)) - skb = *pskb; + err = output(skb); + + if (err || !frag) break; - } - + skb = frag; frag = skb->next; skb->next = NULL; @@ -726,7 +721,7 @@ slow_path: IP6_INC_STATS(FragCreates); - err = output(&frag); + err = output(frag); if (err) goto fail; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 245dac731..aa6b74d9b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -395,7 +395,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); - dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); + dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2); if (!dst) return; @@ -486,7 +486,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); - dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); + dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2); if (!dst) return; @@ -562,7 +562,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); - dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); + dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output2); if (!dst) return; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 223212888..c84fd8eb4 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -66,6 +66,8 @@ do { \ #endif #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) +/* Mutex protects lists (only traversed in user context). */ +static DECLARE_MUTEX(ip6t_mutex); /* Must have mutex */ #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) @@ -542,7 +544,7 @@ find_inlist_lock(struct list_head *head, #endif static inline struct ip6t_table * -ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex) +find_table_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex); } @@ -553,8 +555,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex) return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); } -struct ip6t_target * -ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) +static inline struct ip6t_target * +find_target_lock(const char *name, int *error, struct semaphore *mutex) { return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); } @@ -769,7 +771,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, goto cleanup_matches; t = ip6t_get_target(e); - target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex); + target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex); if (!target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); goto cleanup_matches; @@ -1026,7 +1028,7 @@ get_counters(const struct ip6t_table_info *t, static int copy_entries_to_user(unsigned int total_size, struct ip6t_table *table, - void __user *userptr) + void *userptr) { unsigned int off, num, countersize; struct ip6t_entry *e; @@ -1109,7 +1111,7 @@ get_entries(const struct ip6t_get_entries *entries, int ret; struct ip6t_table *t; - t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex); + t = find_table_lock(entries->name, &ret, &ip6t_mutex); if (t) { duprintf("t->private->number = %u\n", t->private->number); @@ -1172,7 +1174,7 @@ do_replace(void __user *user, unsigned int len) duprintf("ip_tables: Translated table\n"); - t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); + t = find_table_lock(tmp.name, &ret, &ip6t_mutex); if (!t) goto free_newinfo_counters_untrans; @@ -1274,7 +1276,7 @@ do_add_counters(void __user *user, unsigned int len) goto free; } - t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); + t = find_table_lock(tmp.name, &ret, &ip6t_mutex); if (!t) goto free; @@ -1349,7 +1351,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) break; } name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; - t = ip6t_find_table_lock(name, &ret, &ip6t_mutex); + t = find_table_lock(name, &ret, &ip6t_mutex); if (t) { struct ip6t_getinfo info; @@ -1962,7 +1964,6 @@ static void __exit fini(void) EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); -EXPORT_SYMBOL(ip6t_find_target_lock); EXPORT_SYMBOL(ip6t_register_match); EXPORT_SYMBOL(ip6t_unregister_match); EXPORT_SYMBOL(ip6t_register_target); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 0e1b275ad..3d2961c48 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -409,8 +409,10 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = IP6CB(skb)->iif; + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { + struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb; + sin6->sin6_scope_id = opt->iif; + } } sock_recv_timestamp(msg, sk, skb); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 541f2434b..18057ed15 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -84,11 +84,9 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); static struct dst_entry *ip6_negative_advice(struct dst_entry *); static void ip6_dst_destroy(struct dst_entry *); -static void ip6_dst_ifdown(struct dst_entry *, int how); static int ip6_dst_gc(void); static int ip6_pkt_discard(struct sk_buff *skb); -static int ip6_pkt_discard_out(struct sk_buff **pskb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -99,7 +97,6 @@ static struct dst_ops ip6_dst_ops = { .gc_thresh = 1024, .check = ip6_dst_check, .destroy = ip6_dst_destroy, - .ifdown = ip6_dst_ifdown, .negative_advice = ip6_negative_advice, .link_failure = ip6_link_failure, .update_pmtu = ip6_rt_update_pmtu, @@ -116,7 +113,7 @@ struct rt6_info ip6_null_entry = { .error = -ENETUNREACH, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .input = ip6_pkt_discard, - .output = ip6_pkt_discard_out, + .output = ip6_pkt_discard, .ops = &ip6_dst_ops, .path = (struct dst_entry*)&ip6_null_entry, } @@ -145,17 +142,9 @@ static __inline__ struct rt6_info *ip6_dst_alloc(void) static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; - struct inet6_dev *idev = rt->rt6i_idev; - - if (idev != NULL) { - rt->rt6i_idev = NULL; - in6_dev_put(idev); - } -} - -static void ip6_dst_ifdown(struct dst_entry *dst, int how) -{ - ip6_dst_destroy(dst); + if (rt->rt6i_idev != NULL) + in6_dev_put(rt->rt6i_idev); + } /* @@ -583,13 +572,11 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) /* Protected by rt6_lock. */ static struct dst_entry *ndisc_dst_gc_list; -static int ipv6_get_mtu(struct net_device *dev); -static inline unsigned int ipv6_advmss(unsigned int mtu); struct dst_entry *ndisc_dst_alloc(struct net_device *dev, struct neighbour *neigh, struct in6_addr *addr, - int (*output)(struct sk_buff **)) + int (*output)(struct sk_buff *)) { struct rt6_info *rt = ip6_dst_alloc(); @@ -610,8 +597,6 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, rt->rt6i_metric = 0; atomic_set(&rt->u.dst.__refcnt, 1); rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; - rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); - rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst)); rt->u.dst.output = output; write_lock_bh(&rt6_lock); @@ -793,7 +778,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) dev_put(dev); dev = &loopback_dev; dev_hold(dev); - rt->u.dst.output = ip6_pkt_discard_out; + rt->u.dst.output = ip6_pkt_discard; rt->u.dst.input = ip6_pkt_discard; rt->u.dst.error = -ENETUNREACH; rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; @@ -1293,11 +1278,6 @@ int ip6_pkt_discard(struct sk_buff *skb) return 0; } -int ip6_pkt_discard_out(struct sk_buff **pskb) -{ - return ip6_pkt_discard(*pskb); -} - /* * Add address */ diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2668fc87c..7a42f2e4e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -536,7 +536,8 @@ static int tcp_v6_hash_connect(struct sock *sk) static __inline__ int tcp_v6_iif(struct sk_buff *skb) { - return IP6CB(skb)->iif; + struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb; + return opt->iif; } static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, @@ -878,7 +879,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, np->rxopt.bits.srcrt == 2 && req->af.v6_req.pktopts) { struct sk_buff *pktopts = req->af.v6_req.pktopts; - struct inet6_skb_parm *rxopt = IP6CB(pktopts); + struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)pktopts->cb; if (rxopt->srcrt) opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt)); } @@ -931,7 +932,7 @@ static struct or_calltable or_ipv6 = { static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) { struct ipv6_pinfo *np = inet6_sk(sk); - struct inet6_skb_parm *opt = IP6CB(skb); + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; if (np->rxopt.all) { if ((opt->hop && np->rxopt.bits.hopopts) || @@ -1153,7 +1154,11 @@ static void tcp_v6_synq_add(struct sock *sk, struct open_request *req) lopt->syn_table[h] = req; write_unlock(&tp->syn_wait_lock); +#ifdef CONFIG_ACCEPT_QUEUES + tcp_synq_added(sk, req); +#else tcp_synq_added(sk); +#endif } @@ -1166,6 +1171,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct tcp_opt tmptp, *tp = tcp_sk(sk); struct open_request *req = NULL; __u32 isn = TCP_SKB_CB(skb)->when; +#ifdef CONFIG_ACCEPT_QUEUES + int class = 0; +#endif if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_conn_request(sk, skb); @@ -1173,6 +1181,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (!ipv6_unicast_destination(skb)) goto drop; + /* * There are no SYN attacks on IPv6, yet... */ @@ -1182,9 +1191,34 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop; } - if (sk_acceptq_is_full(sk) && tcp_synq_young(sk) > 1) +#ifdef CONFIG_ACCEPT_QUEUES + class = (skb->nfmark <= 0) ? 0 : + ((skb->nfmark >= NUM_ACCEPT_QUEUES) ? 0: skb->nfmark); + /* + * Accept only if the class has shares set or if the default class + * i.e. class 0 has shares + */ + if (!(tcp_sk(sk)->acceptq[class].aq_valid)) { + if (tcp_sk(sk)->acceptq[0].aq_valid) + class = 0; + else + goto drop; + } +#endif + + /* Accept backlog is full. If we have already queued enough + * of warm entries in syn queue, drop request. It is better than + * clogging syn queue with openreqs with exponentially increasing + * timeout. + */ +#ifdef CONFIG_ACCEPT_QUEUES + if (tcp_acceptq_is_full(sk, class) && tcp_synq_young(sk, class) > 1) +#else + if (tcp_acceptq_is_full(sk) && tcp_synq_young(sk) > 1) +#endif goto drop; + req = tcp_openreq_alloc(); if (req == NULL) goto drop; @@ -1197,7 +1231,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tmptp.tstamp_ok = tmptp.saw_tstamp; tcp_openreq_init(req, &tmptp, skb); - +#ifdef CONFIG_ACCEPT_QUEUES + req->acceptq_class = class; + req->acceptq_time_stamp = jiffies; +#endif req->class = &or_ipv6; ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr); ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr); @@ -1299,12 +1336,16 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, opt = np->opt; - if (sk_acceptq_is_full(sk)) +#ifdef CONFIG_ACCEPT_QUEUES + if (tcp_acceptq_is_full(sk, req->acceptq_class)) +#else + if (tcp_acceptq_is_full(sk)) +#endif goto out_overflow; if (np->rxopt.bits.srcrt == 2 && opt == NULL && req->af.v6_req.pktopts) { - struct inet6_skb_parm *rxopt = IP6CB(req->af.v6_req.pktopts); + struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)req->af.v6_req.pktopts->cb; if (rxopt->srcrt) opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(req->af.v6_req.pktopts->nh.raw+rxopt->srcrt)); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 0dc7f0ec1..63ef59317 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -432,8 +432,10 @@ try_again: if (np->rxopt.all) datagram_recv_ctl(sk, msg, skb); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = IP6CB(skb)->iif; + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { + struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb; + sin6->sin6_scope_id = opt->iif; + } } } err = copied; @@ -572,26 +574,34 @@ static void udpv6_mcast_deliver(struct udphdr *uh, struct sk_buff *skb) { struct sock *sk, *sk2; + struct sk_buff *buff; int dif; read_lock(&udp_hash_lock); sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = skb->dev->ifindex; sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (!sk) { - kfree_skb(skb); - goto out; - } + if (!sk) + goto free_skb; + buff = NULL; sk2 = sk; while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, uh->source, saddr, dif))) { - struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) - udpv6_queue_rcv_skb(sk2, buff); + if (!buff) { + buff = skb_clone(skb, GFP_ATOMIC); + if (!buff) + continue; + } + if (udpv6_queue_rcv_skb(sk2, buff) >= 0) + buff = NULL; + } + if (buff) + kfree_skb(buff); + if (udpv6_queue_rcv_skb(sk, skb) < 0) { +free_skb: + kfree_skb(skb); } - udpv6_queue_rcv_skb(sk, skb); -out: read_unlock(&udp_hash_lock); } diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 163223daf..1c3e4f5f0 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -90,7 +90,7 @@ extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len, int noblock); extern int ipxrtr_route_skb(struct sk_buff *skb); extern struct ipx_route *ipxrtr_lookup(__u32 net); -extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg); +extern int ipxrtr_ioctl(unsigned int cmd, void *arg); #undef IPX_REFCNT_DEBUG #ifdef IPX_REFCNT_DEBUG @@ -114,7 +114,7 @@ static void ipxcfg_set_auto_select(char val) ipx_primary_net = ipx_interfaces_head(); } -static int ipxcfg_get_config_data(struct ipx_config_data __user *arg) +static int ipxcfg_get_config_data(struct ipx_config_data *arg) { struct ipx_config_data vals; @@ -1141,7 +1141,7 @@ out: return intrfc; } -static int ipxitf_ioctl(unsigned int cmd, void __user *arg) +static int ipxitf_ioctl(unsigned int cmd, void *arg) { int rc = -EINVAL; struct ifreq ifr; @@ -1204,14 +1204,14 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) } case SIOCAIPXITFCRT: rc = -EFAULT; - if (get_user(val, (unsigned char __user *) arg)) + if (get_user(val, (unsigned char *) arg)) break; rc = 0; ipxcfg_auto_create_interfaces = val; break; case SIOCAIPXPRISLT: rc = -EFAULT; - if (get_user(val, (unsigned char __user *) arg)) + if (get_user(val, (unsigned char *) arg)) break; rc = 0; ipxcfg_set_auto_select(val); @@ -1695,7 +1695,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, /* Socket gets bound below anyway */ /* if (sk->sk_zapped) return -EIO; */ /* Socket not bound */ - if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (flags & ~MSG_DONTWAIT) goto out; /* Max possible packet size limited by 16 bit pktsize in header */ @@ -1823,14 +1823,13 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) int rc = 0; long amount = 0; struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; switch (cmd) { case TIOCOUTQ: amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - rc = put_user(amount, (int __user *)argp); + rc = put_user(amount, (int *)arg); break; case TIOCINQ: { struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); @@ -1838,14 +1837,14 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) * user tasks fiddle here */ if (skb) amount = skb->len - sizeof(struct ipxhdr); - rc = put_user(amount, (int __user *)argp); + rc = put_user(amount, (int *)arg); break; } case SIOCADDRT: case SIOCDELRT: rc = -EPERM; if (capable(CAP_NET_ADMIN)) - rc = ipxrtr_ioctl(cmd, argp); + rc = ipxrtr_ioctl(cmd, (void *)arg); break; case SIOCSIFADDR: case SIOCAIPXITFCRT: @@ -1854,10 +1853,10 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (!capable(CAP_NET_ADMIN)) break; case SIOCGIFADDR: - rc = ipxitf_ioctl(cmd, argp); + rc = ipxitf_ioctl(cmd, (void *)arg); break; case SIOCIPXCFGDATA: - rc = ipxcfg_get_config_data(argp); + rc = ipxcfg_get_config_data((void *)arg); break; case SIOCIPXNCPCONN: /* @@ -1868,12 +1867,12 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (!capable(CAP_NET_ADMIN)) break; rc = get_user(ipx_sk(sk)->ipx_ncp_conn, - (const unsigned short __user *)argp); + (const unsigned short *)(arg)); break; case SIOCGSTAMP: rc = -EINVAL; if (sk) - rc = sock_get_timestamp(sk, argp); + rc = sock_get_timestamp(sk, (struct timeval __user *)arg); break; case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: @@ -1884,7 +1883,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -EINVAL; break; default: - rc = dev_ioctl(cmd, argp); + rc = dev_ioctl(cmd,(void __user *) arg); break; } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index c90c505ed..6d6c65a53 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1269,7 +1269,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR)) return -EINVAL; if (sk->sk_shutdown & SEND_SHUTDOWN) { @@ -1521,7 +1521,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~MSG_DONTWAIT) return -EINVAL; if (sk->sk_shutdown & SEND_SHUTDOWN) { @@ -1593,7 +1593,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~MSG_DONTWAIT) return -EINVAL; if (sk->sk_shutdown & SEND_SHUTDOWN) { @@ -1779,7 +1779,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - if (put_user(amount, (unsigned int __user *)arg)) + if (put_user(amount, (unsigned int *)arg)) return -EFAULT; return 0; } @@ -1790,7 +1790,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (unsigned int __user *)arg)) + if (put_user(amount, (unsigned int *)arg)) return -EFAULT; return 0; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 645b42564..419f67381 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2726,7 +2726,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb, int copied, err; err = -EINVAL; - if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) + if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC)) goto out; msg->msg_namelen = 0; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index fbb97bf37..1e3fe7237 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1021,7 +1021,7 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, unsigned char *asmptr; int size; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; lock_sock(sk); @@ -1176,7 +1176,6 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - void __user *argp = (void __user *)arg; int ret; lock_sock(sk); @@ -1187,7 +1186,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (amount < 0) amount = 0; release_sock(sk); - return put_user(amount, (int __user *)argp); + return put_user(amount, (int *)arg); } case TIOCINQ: { @@ -1197,13 +1196,13 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; release_sock(sk); - return put_user(amount, (int __user *)argp); + return put_user(amount, (int *)arg); } case SIOCGSTAMP: ret = -EINVAL; if (sk != NULL) - ret = sock_get_timestamp(sk, argp); + ret = sock_get_timestamp(sk, (struct timeval __user *)arg); release_sock(sk); return ret; @@ -1225,11 +1224,11 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCNRDECOBS: release_sock(sk); if (!capable(CAP_NET_ADMIN)) return -EPERM; - return nr_rt_ioctl(cmd, argp); + return nr_rt_ioctl(cmd, (void *)arg); default: release_sock(sk); - return dev_ioctl(cmd, argp); + return dev_ioctl(cmd, (void __user *)arg); } release_sock(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 93ac3b310..91e57eb8a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1037,7 +1037,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, int copied, err; err = -EINVAL; - if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) + if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC)) goto out; #if 0 diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index a5555c328..315e4a97a 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1021,7 +1021,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, unsigned char *asmptr; int n, size, qbit = 0; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; if (sk->sk_zapped) @@ -1249,7 +1249,6 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; rose_cb *rose = rose_sk(sk); - void __user *argp = (void __user *)arg; switch (cmd) { case TIOCOUTQ: { @@ -1257,7 +1256,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - return put_user(amount, (unsigned int __user *)argp); + return put_user(amount, (unsigned int *)arg); } case TIOCINQ: { @@ -1266,12 +1265,12 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - return put_user(amount, (unsigned int __user *)argp); + return put_user(amount, (unsigned int *)arg); } case SIOCGSTAMP: if (sk != NULL) - return sock_get_timestamp(sk, (struct timeval __user *)argp); + return sock_get_timestamp(sk, (struct timeval __user *)arg); return -EINVAL; case SIOCGIFADDR: @@ -1291,18 +1290,18 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCRSCLRRT: if (!capable(CAP_NET_ADMIN)) return -EPERM; - return rose_rt_ioctl(cmd, argp); + return rose_rt_ioctl(cmd, (void *)arg); case SIOCRSGCAUSE: { struct rose_cause_struct rose_cause; rose_cause.cause = rose->cause; rose_cause.diagnostic = rose->diagnostic; - return copy_to_user(argp, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; } case SIOCRSSCAUSE: { struct rose_cause_struct rose_cause; - if (copy_from_user(&rose_cause, argp, sizeof(struct rose_cause_struct))) + if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct))) return -EFAULT; rose->cause = rose_cause.cause; rose->diagnostic = rose_cause.diagnostic; @@ -1313,14 +1312,14 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (!capable(CAP_NET_ADMIN)) return -EPERM; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_release(&rose_callsign, NULL); - if (copy_from_user(&rose_callsign, argp, sizeof(ax25_address))) + if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) return -EFAULT; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_register(&rose_callsign, NULL); return 0; case SIOCRSGL2CALL: - return copy_to_user(argp, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; case SIOCRSACCEPT: if (rose->state == ROSE_STATE_5) { @@ -1336,7 +1335,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return 0; default: - return dev_ioctl(cmd, argp); + return dev_ioctl(cmd, (void __user *)arg); } return 0; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 491b510b0..a3c0350c9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1164,11 +1164,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, if (!asoc) { SCTP_DEBUG_PRINTK("There is no association yet.\n"); - if (sinfo_flags & (MSG_EOF | MSG_ABORT)) { - err = -EINVAL; - goto out_unlock; - } - /* Check for invalid stream against the stream counts, * either the default or the user specified stream counts. */ @@ -2804,7 +2799,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, if (len != sizeof(struct sctp_paddrparams)) return -EINVAL; - if (copy_from_user(¶ms, optval, len)) + if (copy_from_user(¶ms, optval, *optlen)) /* XXXXXX */ return -EFAULT; trans = sctp_addr_id2transport(sk, ¶ms.spp_address, @@ -2974,7 +2969,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, int cnt = 0; struct sctp_getaddrs getaddrs; struct sctp_sockaddr_entry *from; - void __user *to; + void *to; union sctp_addr temp; struct sctp_opt *sp = sctp_sk(sk); int addrlen; @@ -3001,7 +2996,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, bp = &asoc->base.bind_addr; } - to = getaddrs.addrs; + to = (void *)getaddrs.addrs; list_for_each(pos, &bp->address_list) { from = list_entry(pos, struct sctp_sockaddr_entry, @@ -4393,11 +4388,7 @@ out: return err; do_error: - if (asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1 >= - asoc->max_init_attempts) - err = -ETIMEDOUT; - else - err = -ECONNREFUSED; + err = -ECONNREFUSED; goto out; do_interrupted: diff --git a/net/socket.c b/net/socket.c index 1aa2ce2a3..e0cae444d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -120,7 +121,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, * in the operation structures but are done directly via the socketcall() multiplexor. */ -static struct file_operations socket_file_ops = { +struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, @@ -287,7 +288,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb) ei->socket.ops = NULL; ei->socket.sk = NULL; ei->socket.file = NULL; - ei->socket.passcred = 0; + ei->socket.flags = 0; return &ei->vfs_inode; } @@ -362,52 +363,63 @@ static struct dentry_operations sockfs_dentry_operations = { * but we take care of internal coherence yet. */ -int sock_map_fd(struct socket *sock) +struct file * sock_map_file(struct socket *sock) { - int fd; + struct file *file; struct qstr this; char name[32]; - /* - * Find a file descriptor suitable for return to the user. - */ - - fd = get_unused_fd(); - if (fd >= 0) { - struct file *file = get_empty_filp(); + file = get_empty_filp(); - if (!file) { - put_unused_fd(fd); - fd = -ENFILE; - goto out; - } + if (!file) + return ERR_PTR(-ENFILE); - sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); - this.name = name; - this.len = strlen(name); - this.hash = SOCK_INODE(sock)->i_ino; - - file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); - if (!file->f_dentry) { - put_filp(file); - put_unused_fd(fd); - fd = -ENOMEM; - goto out; - } - file->f_dentry->d_op = &sockfs_dentry_operations; - d_add(file->f_dentry, SOCK_INODE(sock)); - file->f_vfsmnt = mntget(sock_mnt); - file->f_mapping = file->f_dentry->d_inode->i_mapping; + sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = SOCK_INODE(sock)->i_ino; - sock->file = file; - file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; - file->f_mode = 3; - file->f_flags = O_RDWR; - file->f_pos = 0; - fd_install(fd, file); + file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); + if (!file->f_dentry) { + put_filp(file); + return ERR_PTR(-ENOMEM); } + file->f_dentry->d_op = &sockfs_dentry_operations; + d_add(file->f_dentry, SOCK_INODE(sock)); + file->f_vfsmnt = mntget(sock_mnt); +file->f_mapping = file->f_dentry->d_inode->i_mapping; + + if (sock->file) + BUG(); + sock->file = file; + file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; + file->f_mode = 3; + file->f_flags = O_RDWR; + file->f_pos = 0; + + return file; +} -out: +int sock_map_fd(struct socket *sock) +{ + int fd; + struct file *file; + + /* + * Find a file descriptor suitable for return to the user. + */ + + fd = get_unused_fd(); + if (fd < 0) + return fd; + + file = sock_map_file(sock); + if (IS_ERR(file)) { + put_unused_fd(fd); + return PTR_ERR(file); + } + fd_install(fd, file); + return fd; } @@ -531,7 +543,7 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock_iocb *si = kiocb_to_siocb(iocb); - int err; + int err, len; si->sock = sock; si->scm = NULL; @@ -542,7 +554,20 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (err) return err; - return sock->ops->sendmsg(iocb, sock, msg, size); + len = sock->ops->sendmsg(iocb, sock, msg, size); + if (sock->sk) { + if (len == size) + vx_sock_send(sock->sk, size); + else + vx_sock_fail(sock->sk, size); + } + vxdprintk("__sock_sendmsg: %p[%p,%p,%p;%d]:%d/%d\n", + sock, sock->sk, + (sock->sk)?sock->sk->sk_nx_info:0, + (sock->sk)?sock->sk->sk_vx_info:0, + (sock->sk)?sock->sk->sk_xid:0, + size, len); + return len; } int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) @@ -561,7 +586,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { - int err; + int err, len; struct sock_iocb *si = kiocb_to_siocb(iocb); si->sock = sock; @@ -574,7 +599,16 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (err) return err; - return sock->ops->recvmsg(iocb, sock, msg, size, flags); + len = sock->ops->recvmsg(iocb, sock, msg, size, flags); + if ((len >= 0) && sock->sk) + vx_sock_recv(sock->sk, len); + vxdprintk("__sock_recvmsg: %p[%p,%p,%p;%d]:%d/%d\n", + sock, sock->sk, + (sock->sk)?sock->sk->sk_nx_info:0, + (sock->sk)?sock->sk->sk_vx_info:0, + (sock->sk)?sock->sk->sk_xid:0, + size, len); + return len; } int sock_recvmsg(struct socket *sock, struct msghdr *msg, @@ -729,9 +763,9 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector, */ static DECLARE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; +static int (*br_ioctl_hook)(unsigned int cmd, unsigned long arg) = NULL; -void brioctl_set(int (*hook)(unsigned int, void __user *)) +void brioctl_set(int (*hook)(unsigned int, unsigned long)) { down(&br_ioctl_mutex); br_ioctl_hook = hook; @@ -740,9 +774,9 @@ void brioctl_set(int (*hook)(unsigned int, void __user *)) EXPORT_SYMBOL(brioctl_set); static DECLARE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook)(void __user *arg); +static int (*vlan_ioctl_hook)(unsigned long arg); -void vlan_ioctl_set(int (*hook)(void __user *)) +void vlan_ioctl_set(int (*hook)(unsigned long)) { down(&vlan_ioctl_mutex); vlan_ioctl_hook = hook; @@ -751,9 +785,9 @@ void vlan_ioctl_set(int (*hook)(void __user *)) EXPORT_SYMBOL(vlan_ioctl_set); static DECLARE_MUTEX(dlci_ioctl_mutex); -static int (*dlci_ioctl_hook)(unsigned int, void __user *); +static int (*dlci_ioctl_hook)(unsigned int, void *); -void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) +void dlci_ioctl_set(int (*hook)(unsigned int, void *)) { down(&dlci_ioctl_mutex); dlci_ioctl_hook = hook; @@ -770,30 +804,29 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct socket *sock; - void __user *argp = (void __user *)arg; int pid, err; unlock_kernel(); sock = SOCKET_I(inode); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(cmd, (void __user *)arg); } else #ifdef WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(cmd, (void __user *)arg); } else #endif /* WIRELESS_EXT */ switch (cmd) { case FIOSETOWN: case SIOCSPGRP: err = -EFAULT; - if (get_user(pid, (int __user *)argp)) + if (get_user(pid, (int __user *)arg)) break; err = f_setown(sock->file, pid, 1); break; case FIOGETOWN: case SIOCGPGRP: - err = put_user(sock->file->f_owner.pid, (int __user *)argp); + err = put_user(sock->file->f_owner.pid, (int __user *)arg); break; case SIOCGIFBR: case SIOCSIFBR: @@ -805,7 +838,7 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, down(&br_ioctl_mutex); if (br_ioctl_hook) - err = br_ioctl_hook(cmd, argp); + err = br_ioctl_hook(cmd, arg); up(&br_ioctl_mutex); break; case SIOCGIFVLAN: @@ -816,13 +849,13 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, down(&vlan_ioctl_mutex); if (vlan_ioctl_hook) - err = vlan_ioctl_hook(argp); + err = vlan_ioctl_hook(arg); up(&vlan_ioctl_mutex); break; case SIOCGIFDIVERT: case SIOCSIFDIVERT: /* Convert this to call through a hook */ - err = divert_ioctl(cmd, argp); + err = divert_ioctl(cmd, (struct divert_cf *)arg); break; case SIOCADDDLCI: case SIOCDELDLCI: @@ -832,7 +865,7 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (dlci_ioctl_hook) { down(&dlci_ioctl_mutex); - err = dlci_ioctl_hook(cmd, argp); + err = dlci_ioctl_hook(cmd, (void *)arg); up(&dlci_ioctl_mutex); } break; @@ -978,6 +1011,8 @@ static int sock_fasync(int fd, struct file *filp, int on) } out: + if (sock->sk != sk) + BUG(); release_sock(sock->sk); return 0; } @@ -1023,6 +1058,10 @@ static int __sock_create(int family, int type, int protocol, struct socket **res if (type < 0 || type >= SOCK_MAX) return -EINVAL; + /* disable IPv6 inside vservers for now */ + if (family == PF_INET6 && !vx_check(0, VX_ADMIN)) + return -EAFNOSUPPORT; + /* Compatibility. This uglymoron is moved from INET layer to here to avoid @@ -1131,6 +1170,7 @@ asmlinkage long sys_socket(int family, int type, int protocol) if (retval < 0) goto out; + set_bit(SOCK_USER_SOCKET, &sock->flags); retval = sock_map_fd(sock); if (retval < 0) goto out_release; @@ -1161,10 +1201,12 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u err = sock_create(family, type, protocol, &sock1); if (err < 0) goto out; + set_bit(SOCK_USER_SOCKET, &sock1->flags); err = sock_create(family, type, protocol, &sock2); if (err < 0) goto out_release_1; + set_bit(SOCK_USER_SOCKET, &sock2->flags); err = sock1->ops->socketpair(sock1, sock2); if (err < 0) @@ -2007,6 +2049,51 @@ void __init sock_init(void) #endif } +int tux_Dprintk; +int tux_TDprintk; + +#ifdef CONFIG_TUX_MODULE + +asmlinkage long (*sys_tux_ptr) (unsigned int action, user_req_t *u_info) = NULL; + +struct module *tux_module = NULL; +spinlock_t tux_module_lock = SPIN_LOCK_UNLOCKED; + +asmlinkage long sys_tux (unsigned int action, user_req_t *u_info) +{ + int ret; + + if (current->tux_info) + return sys_tux_ptr(action, u_info); + + ret = -ENOSYS; + spin_lock(&tux_module_lock); + if (!tux_module) + goto out_unlock; + if (!try_module_get(tux_module)) + goto out_unlock; + spin_unlock(&tux_module_lock); + + if (!sys_tux_ptr) + TUX_BUG(); + ret = sys_tux_ptr(action, u_info); + + spin_lock(&tux_module_lock); + module_put(tux_module); +out_unlock: + spin_unlock(&tux_module_lock); + + return ret; +} + +EXPORT_SYMBOL_GPL(tux_module); +EXPORT_SYMBOL_GPL(tux_module_lock); +EXPORT_SYMBOL_GPL(sys_tux_ptr); + +EXPORT_SYMBOL_GPL(tux_Dprintk); +EXPORT_SYMBOL_GPL(tux_TDprintk); + +#endif #ifdef CONFIG_PROC_FS void socket_seq_show(struct seq_file *seq) { diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 60bca99bf..06aa0a389 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -493,7 +493,7 @@ gss_pipe_downcall(struct file *filp, const char *src, size_t mlen) spin_unlock(&gss_auth->lock); rpc_release_client(clnt); kfree(obj.data); - dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); + dprintk("RPC: gss_pipe_downcall returning length %u\n", mlen); return mlen; err: if (ctx) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 55b2fd104..03bd7bd8c 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -333,7 +333,6 @@ rsc_init(struct rsc *new, struct rsc *tmp) new->handle.data = tmp->handle.data; tmp->handle.data = NULL; new->mechctx = NULL; - new->cred.cr_group_info = NULL; } static inline void @@ -454,11 +453,8 @@ gss_svc_searchbyctx(struct xdr_netobj *handle) struct rsc rsci; struct rsc *found; - memset(&rsci, 0, sizeof(rsci)); - if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) - return NULL; + rsci.handle = *handle; found = rsc_lookup(&rsci, 0); - rsc_free(&rsci); if (!found) return NULL; if (cache_check(&rsc_cache, &found->h, NULL)) @@ -1049,7 +1045,6 @@ svcauth_gss_domain_release(struct auth_domain *dom) struct auth_ops svcauthops_gss = { .name = "rpcsec_gss", - .owner = THIS_MODULE, .flavour = RPC_AUTH_GSS, .accept = svcauth_gss_accept, .release = svcauth_gss_release, @@ -1059,12 +1054,10 @@ struct auth_ops svcauthops_gss = { int gss_svc_init(void) { - int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); - if (rv == 0) { - cache_register(&rsc_cache); - cache_register(&rsi_cache); - } - return rv; + cache_register(&rsc_cache); + cache_register(&rsi_cache); + svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); + return 0; } void @@ -1072,5 +1065,4 @@ gss_svc_shutdown(void) { cache_unregister(&rsc_cache); cache_unregister(&rsi_cache); - svc_auth_unregister(RPC_AUTH_GSS); } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e06577901..441c5de1b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -214,17 +214,24 @@ out_no_clnt: int rpc_shutdown_client(struct rpc_clnt *clnt) { + wait_queue_t __wait; + init_waitqueue_entry(&__wait, current); dprintk("RPC: shutting down %s client for %s, tasks=%d\n", clnt->cl_protname, clnt->cl_server, atomic_read(&clnt->cl_users)); + add_wait_queue(&destroy_wait, &__wait); + set_current_state(TASK_UNINTERRUPTIBLE); while (atomic_read(&clnt->cl_users) > 0) { /* Don't let rpc_release_client destroy us */ clnt->cl_oneshot = 0; clnt->cl_dead = 0; rpc_killall_tasks(clnt); - sleep_on_timeout(&destroy_wait, 1*HZ); + schedule_timeout(1*HZ); + set_current_state(TASK_UNINTERRUPTIBLE); } + current->state = TASK_RUNNING; + remove_wait_queue(&destroy_wait, &__wait); if (atomic_read(&clnt->cl_users) < 0) { printk(KERN_ERR "RPC: rpc_shutdown_client clnt %p tasks=%d\n", diff --git a/net/tux/Kconfig b/net/tux/Kconfig new file mode 100644 index 000000000..8b6d62420 --- /dev/null +++ b/net/tux/Kconfig @@ -0,0 +1,25 @@ + +config TUX + tristate "TUX: Threaded linUX application protocol accelerator layer" + default y if INET=y + select ZLIB_DEFLATE + help + This is the TUX content-accelerator/server + +menu "TUX options" + depends on TUX + +config TUX_EXTCGI + bool "External CGI module" + default y + +config TUX_EXTENDED_LOG + bool "extended TUX logging format" + default n + +config TUX_DEBUG + bool "debug TUX" + default n + +endmenu + diff --git a/net/tux/Makefile b/net/tux/Makefile new file mode 100644 index 000000000..fc0bbd0a5 --- /dev/null +++ b/net/tux/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for TUX +# + +obj-$(CONFIG_TUX) += tux.o + +tux-y := accept.o input.o userspace.o cachemiss.o output.o \ + redirect.o postpone.o logger.o proto_http.o proto_ftp.o \ + proc.o main.o mod.o abuf.o times.o directory.o gzip.o + +tux-$(subst m,y,$(CONFIG_TUX_EXTCGI)) += cgi.o extcgi.o + diff --git a/net/tux/abuf.c b/net/tux/abuf.c new file mode 100644 index 000000000..7447e698c --- /dev/null +++ b/net/tux/abuf.c @@ -0,0 +1,186 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * abuf.c: async buffer-sending + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +char * get_abuf (tux_req_t *req, unsigned int max_size) +{ + threadinfo_t *ti = req->ti; + struct page *page; + char *buf; + unsigned int offset; + unsigned int left; + + if (req->abuf.page || req->abuf.buf || req->abuf.size) + TUX_BUG(); + + if (max_size > PAGE_SIZE) + BUG(); + offset = ti->header_offset; + if (offset > PAGE_SIZE) + TUX_BUG(); + left = PAGE_SIZE - offset; + if (!max_size) + BUG(); + page = ti->header_cache; + if ((left < max_size) || !page) { + while (!(page = alloc_pages(GFP_KERNEL, 0))) { + if (net_ratelimit()) + printk(KERN_WARNING "tux: OOM in get_abuf()!\n"); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + + if (ti->header_cache) + __free_page(ti->header_cache); + ti->header_cache = page; + ti->header_offset = 0; + offset = 0; + } + buf = page_address(page) + offset; + + if (!page) + BUG(); + req->abuf.page = page; + req->abuf.buf = buf; + req->abuf.size = 0; + req->abuf.offset = offset; + req->abuf.flags = 0; + get_page(req->abuf.page); + + return buf; +} + +static void do_send_abuf (tux_req_t *req, int cachemiss); + +void send_abuf (tux_req_t *req, unsigned int size, unsigned long flags) +{ + threadinfo_t *ti = req->ti; + + Dprintk("send_abuf(req: %p, sock: %p): %p(%p), size:%d, off:%d, flags:%08lx\n", req, req->sock, req->abuf.page, req->abuf.buf, size, req->abuf.offset, flags); + + ti->header_offset += size; + if (ti->header_offset > PAGE_SIZE) + TUX_BUG(); + if (req->abuf.offset + req->abuf.size > PAGE_SIZE) + TUX_BUG(); + + req->abuf.flags = flags | MSG_NOSIGNAL; + req->abuf.size = size; + + add_tux_atom(req, do_send_abuf); +} + +static void do_send_abuf (tux_req_t *req, int cachemiss) +{ + int ret; + + if (req->magic != TUX_MAGIC) + TUX_BUG(); + if (!req->sock) + TUX_BUG(); + tcp_sk(req->sock->sk)->nonagle = 2; + +repeat: + Dprintk("do_send_abuf(%p,%d): %p(%p), size:%d, off:%d, flags:%08lx\n", + req, cachemiss, + req->abuf.page, req->abuf.buf, req->abuf.size, + req->abuf.offset, req->abuf.flags); + + if (tux_zerocopy_header) + ret = tcp_sendpage(req->sock, req->abuf.page, + req->abuf.offset, req->abuf.size, req->abuf.flags); + else { + mm_segment_t oldmm; + oldmm = get_fs(); set_fs(KERNEL_DS); + ret = send_sync_buf(req, req->sock, req->abuf.buf, + req->abuf.size, req->abuf.flags); + set_fs(oldmm); + } + + + Dprintk("do_send_abuf: ret: %d\n", ret); + if (!ret) + TUX_BUG(); + + if (ret < 0) { + if (ret != -EAGAIN) { + TDprintk("ret: %d, req->error = TUX_ERROR_CONN_CLOSE.\n", ret); + req->error = TUX_ERROR_CONN_CLOSE; + req->atom_idx = 0; + req->in_file.f_pos = 0; + __free_page(req->abuf.page); + memset(&req->abuf, 0, sizeof(req->abuf)); + zap_request(req, cachemiss); + return; + } + add_tux_atom(req, do_send_abuf); + if (add_output_space_event(req, req->sock)) { + del_tux_atom(req); + goto repeat; + } + return; + } + + req->abuf.buf += ret; + req->abuf.offset += ret; + req->abuf.size -= ret; + + if ((int)req->abuf.size < 0) + TUX_BUG(); + if (req->abuf.size > 0) + goto repeat; + + Dprintk("DONE do_send_abuf: %p(%p), size:%d, off:%d, flags:%08lx\n", + req->abuf.page, req->abuf.buf, req->abuf.size, + req->abuf.offset, req->abuf.flags); + + __free_page(req->abuf.page); + + memset(&req->abuf, 0, sizeof(req->abuf)); + + add_req_to_workqueue(req); +} + +void __send_async_message (tux_req_t *req, const char *message, + int status, unsigned int size, int push) +{ + unsigned int flags; + char *buf; + + Dprintk("TUX: sending %d reply (%d bytes)!\n", status, size); + Dprintk("request %p, reply: %s\n", req, message); + if (!size) + TUX_BUG(); + buf = get_abuf(req, size); + memcpy(buf, message, size); + + req->status = status; + flags = MSG_DONTWAIT; + if (!push) + flags |= MSG_MORE; + send_abuf(req, size, flags); + add_req_to_workqueue(req); +} diff --git a/net/tux/accept.c b/net/tux/accept.c new file mode 100644 index 000000000..16f611cf1 --- /dev/null +++ b/net/tux/accept.c @@ -0,0 +1,859 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * accept.c: accept new connections, allocate requests + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +unsigned int tux_ack_pingpong = 1; +unsigned int tux_push_all = 0; +unsigned int tux_zerocopy_parse = 1; + +static int __idle_event (tux_req_t *req); +static int __output_space_event (tux_req_t *req); + +struct socket * start_listening(tux_socket_t *listen, int nr) +{ + struct sockaddr_in sin; + struct socket *sock = NULL; + struct sock *sk; + struct tcp_opt *tp; + int err; + u16 port = listen->port; + u32 addr = listen->ip; + tux_proto_t *proto = listen->proto; + + /* Create a listening socket: */ + + err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (err) { + printk(KERN_ERR "TUX: error %d creating socket.\n", err); + goto error; + } + + /* Bind the socket: */ + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(addr); + sin.sin_port = htons(port); + + sk = sock->sk; + sk->sk_reuse = 1; + sock_set_flag(sk, SOCK_URGINLINE); + + err = sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin)); + if (err) { + printk(KERN_ERR "TUX: error %d binding socket. This means that probably some other process is (or was a short time ago) using addr %s://%d.%d.%d.%d:%d.\n", + err, proto->name, HIPQUAD(addr), port); + goto error; + } + + tp = tcp_sk(sk); + Dprintk("listen sk accept_queue: %p/%p.\n", + tp->accept_queue, tp->accept_queue_tail); + tp->ack.pingpong = tux_ack_pingpong; + + sock_reset_flag(sk, SOCK_LINGER); + sk->sk_lingertime = 0; + tp->linger2 = tux_keepalive_timeout * HZ; + + if (proto->defer_accept && !tux_keepalive_timeout && tux_defer_accept) + tp->defer_accept = 1; + + /* Now, start listening on the socket */ + + err = sock->ops->listen(sock, tux_max_backlog); + if (err) { + printk(KERN_ERR "TUX: error %d listening on socket.\n", err); + goto error; + } + + printk(KERN_NOTICE "TUX: thread %d listens on %s://%d.%d.%d.%d:%d.\n", + nr, proto->name, HIPQUAD(addr), port); + return sock; + +error: + if (sock) + sock_release(sock); + return NULL; +} + +static inline void __kfree_req (tux_req_t *req, threadinfo_t * ti) +{ + list_del(&req->all); + DEBUG_DEL_LIST(&req->all); + ti->nr_requests--; + kfree(req); +} + +int flush_freequeue (threadinfo_t * ti) +{ + struct list_head *tmp; + unsigned long flags; + tux_req_t *req; + int count = 0; + + spin_lock_irqsave(&ti->free_requests_lock,flags); + while (ti->nr_free_requests) { + ti->nr_free_requests--; + tmp = ti->free_requests.next; + req = list_entry(tmp, tux_req_t, free); + list_del(tmp); + DEBUG_DEL_LIST(tmp); + DEC_STAT(nr_free_pending); + __kfree_req(req, ti); + count++; + } + spin_unlock_irqrestore(&ti->free_requests_lock,flags); + + return count; +} + +static tux_req_t * kmalloc_req (threadinfo_t * ti) +{ + struct list_head *tmp; + unsigned long flags; + tux_req_t *req; + + spin_lock_irqsave(&ti->free_requests_lock, flags); + if (ti->nr_free_requests) { + ti->nr_free_requests--; + tmp = ti->free_requests.next; + req = list_entry(tmp, tux_req_t, free); + list_del(tmp); + DEBUG_DEL_LIST(tmp); + DEC_STAT(nr_free_pending); + req->magic = TUX_MAGIC; + spin_unlock_irqrestore(&ti->free_requests_lock, flags); + } else { + spin_unlock_irqrestore(&ti->free_requests_lock, flags); + req = tux_kmalloc(sizeof(*req)); + ti->nr_requests++; + memset (req, 0, sizeof(*req)); + list_add(&req->all, &ti->all_requests); + } + req->magic = TUX_MAGIC; + INC_STAT(nr_allocated); + init_waitqueue_entry(&req->sleep, current); + init_waitqueue_entry(&req->ftp_sleep, current); + INIT_LIST_HEAD(&req->work); + INIT_LIST_HEAD(&req->free); + INIT_LIST_HEAD(&req->lru); + req->ti = ti; + req->total_bytes = 0; + SET_TIMESTAMP(req->accept_timestamp); + req->first_timestamp = jiffies; + req->fd = -1; + init_timer(&req->keepalive_timer); + init_timer(&req->output_timer); + + Dprintk("allocated NEW req %p.\n", req); + return req; +} + +void kfree_req (tux_req_t *req) +{ + threadinfo_t * ti = req->ti; + unsigned long flags; + + Dprintk("freeing req %p.\n", req); + + if (req->magic != TUX_MAGIC) + TUX_BUG(); + spin_lock_irqsave(&ti->free_requests_lock,flags); + req->magic = 0; + DEC_STAT(nr_allocated); + if (req->sock || req->dentry || req->private) + TUX_BUG(); + if (ti->nr_free_requests > tux_max_free_requests) + __kfree_req(req, ti); + else { + req->error = 0; + ti->nr_free_requests++; + + // the free requests queue is LIFO + list_add(&req->free, &ti->free_requests); + INC_STAT(nr_free_pending); + } + spin_unlock_irqrestore(&ti->free_requests_lock,flags); +} + +static void __add_req_to_workqueue (tux_req_t *req) +{ + threadinfo_t *ti = req->ti; + + if (!list_empty(&req->work)) + TUX_BUG(); + Dprintk("work-queueing request %p at %p/%p.\n", req, __builtin_return_address(0), __builtin_return_address(1)); + if (connection_too_fast(req)) + list_add_tail(&req->work, &ti->work_pending); + else + list_add(&req->work, &ti->work_pending); + INC_STAT(nr_work_pending); + wake_up_process(ti->thread); + return; +} + +void add_req_to_workqueue (tux_req_t *req) +{ + unsigned long flags; + threadinfo_t *ti = req->ti; + + spin_lock_irqsave(&ti->work_lock, flags); + __add_req_to_workqueue(req); + spin_unlock_irqrestore(&ti->work_lock, flags); +} + +void del_output_timer (tux_req_t *req) +{ +#if CONFIG_SMP + if (!spin_is_locked(&req->ti->work_lock)) + TUX_BUG(); +#endif + if (!list_empty(&req->lru)) { + list_del(&req->lru); + DEBUG_DEL_LIST(&req->lru); + req->ti->nr_lru--; + } + Dprintk("del output timeout for req %p.\n", req); + del_timer(&req->output_timer); +} + +static void output_timeout_fn (unsigned long data); + +#define OUTPUT_TIMEOUT HZ + +static void add_output_timer (tux_req_t *req) +{ + struct timer_list *timer = &req->output_timer; + + timer->data = (unsigned long) req; + timer->function = &output_timeout_fn; + mod_timer(timer, jiffies + OUTPUT_TIMEOUT); +} + +static void output_timeout_fn (unsigned long data) +{ + tux_req_t *req = (tux_req_t *)data; + + if (connection_too_fast(req)) { + add_output_timer(req); +// mod_timer(&req->output_timer, jiffies + OUTPUT_TIMEOUT); + return; + } + output_space_event(req); +} + +void output_timeout (tux_req_t *req) +{ + Dprintk("output timeout for req %p.\n", req); + if (test_and_set_bit(0, &req->wait_output_space)) + TUX_BUG(); + INC_STAT(nr_output_space_pending); + add_output_timer(req); +} + +void __del_keepalive_timer (tux_req_t *req) +{ +#if CONFIG_SMP + if (!spin_is_locked(&req->ti->work_lock)) + TUX_BUG(); +#endif + if (!list_empty(&req->lru)) { + list_del(&req->lru); + DEBUG_DEL_LIST(&req->lru); + req->ti->nr_lru--; + } + Dprintk("del keepalive timeout for req %p.\n", req); + del_timer(&req->keepalive_timer); +} + +static void keepalive_timeout_fn (unsigned long data) +{ + tux_req_t *req = (tux_req_t *)data; + +#if CONFIG_TUX_DEBUG + Dprintk("req %p timed out after %d sec!\n", req, tux_keepalive_timeout); + if (tux_Dprintk) + print_req(req); +#endif + Dprintk("req->error = TUX_ERROR_CONN_TIMEOUT!\n"); + req->error = TUX_ERROR_CONN_TIMEOUT; + if (!idle_event(req)) + output_space_event(req); +} + +void __add_keepalive_timer (tux_req_t *req) +{ + struct timer_list *timer = &req->keepalive_timer; + + if (!tux_keepalive_timeout) + TUX_BUG(); +#if CONFIG_SMP + if (!spin_is_locked(&req->ti->work_lock)) + TUX_BUG(); +#endif + + if (!list_empty(&req->lru)) + TUX_BUG(); + if (req->ti->nr_lru > tux_max_keepalives) { + struct list_head *head, *last; + tux_req_t *last_req; + + head = &req->ti->lru; + last = head->prev; + if (last == head) + TUX_BUG(); + last_req = list_entry(last, tux_req_t, lru); + list_del(last); + DEBUG_DEL_LIST(last); + req->ti->nr_lru--; + + Dprintk("LRU-aging req %p!\n", last_req); + last_req->error = TUX_ERROR_CONN_TIMEOUT; + if (!__idle_event(last_req)) + __output_space_event(last_req); + } + list_add(&req->lru, &req->ti->lru); + req->ti->nr_lru++; + + timer->expires = jiffies + tux_keepalive_timeout * HZ; + timer->data = (unsigned long) req; + timer->function = &keepalive_timeout_fn; + add_timer(timer); +} + +static int __output_space_event (tux_req_t *req) +{ + if (!req || (req->magic != TUX_MAGIC)) + TUX_BUG(); + + if (!test_and_clear_bit(0, &req->wait_output_space)) { + Dprintk("output space ready event at <%p>, on non-idle %p.\n", __builtin_return_address(0), req); + return 0; + } + + Dprintk("output space ready event at <%p>, %p was waiting!\n", __builtin_return_address(0), req); + DEC_STAT(nr_output_space_pending); + + del_keepalive_timer(req); + del_output_timer(req); + + __add_req_to_workqueue(req); + return 1; +} + +int output_space_event (tux_req_t *req) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&req->ti->work_lock, flags); + ret = __output_space_event(req); + spin_unlock_irqrestore(&req->ti->work_lock, flags); + + return ret; +} + +static int __idle_event (tux_req_t *req) +{ + struct tcp_opt *tp; + threadinfo_t *ti; + + if (!req || (req->magic != TUX_MAGIC)) + TUX_BUG(); + ti = req->ti; + + if (!test_and_clear_bit(0, &req->idle_input)) { + Dprintk("data ready event at <%p>, on non-idle %p.\n", __builtin_return_address(0), req); + return 0; + } + + Dprintk("data ready event at <%p>, %p was idle!\n", __builtin_return_address(0), req); + del_keepalive_timer(req); + del_output_timer(req); + DEC_STAT(nr_idle_input_pending); + + tp = tcp_sk(req->sock->sk); + + tp->ack.pingpong = tux_ack_pingpong; + SET_TIMESTAMP(req->accept_timestamp); + + __add_req_to_workqueue(req); + + return 1; +} + +int idle_event (tux_req_t *req) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&req->ti->work_lock, flags); + ret = __idle_event(req); + spin_unlock_irqrestore(&req->ti->work_lock, flags); + + return ret; +} + +#define HANDLE_CALLBACK_1(callback, tux_name, real_name, param...) \ + tux_req_t *req; \ + \ + read_lock(&sk->sk_callback_lock); \ + req = sk->sk_user_data; \ + \ + Dprintk("callback "#callback"(%p) req %p.\n", \ + sk->sk_##callback, req); \ + \ + if (!req) { \ + if (sk->sk_##callback == tux_name) { \ + printk("BUG: "#callback" "#tux_name" "#real_name" no req!"); \ + TUX_BUG(); \ + } \ + read_unlock(&sk->sk_callback_lock); \ + if (sk->sk_##callback) \ + sk->sk_##callback(param); \ + return; \ + } \ + +#define HANDLE_CALLBACK_2(callback, tux_name, real_name, param...) \ + Dprintk(#tux_name"() on %p.\n", req); \ + if (req->magic != TUX_MAGIC) \ + TUX_BUG(); \ + if (req->real_name) \ + req->real_name(param); + +#define HANDLE_CALLBACK(callback, tux_name, real_name, param...) \ + HANDLE_CALLBACK_1(callback,tux_name,real_name,param) \ + HANDLE_CALLBACK_2(callback,tux_name,real_name,param) + +static void tux_data_ready (struct sock *sk, int len) +{ + HANDLE_CALLBACK_1(data_ready, tux_data_ready, real_data_ready, sk, len); + + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_write_space (struct sock *sk) +{ + HANDLE_CALLBACK(write_space, tux_write_space, real_write_space, sk); + + Dprintk("sk->sk_wmem_queued: %d, sk->sk_sndbuf: %d.\n", + sk->sk_wmem_queued, sk->sk_sndbuf); + + if (tcp_wspace(sk) >= tcp_min_write_space(sk)) { + clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + if (!idle_event(req)) + output_space_event(req); + } + read_unlock(&sk->sk_callback_lock); +} + +static void tux_error_report (struct sock *sk) +{ + HANDLE_CALLBACK(error_report, tux_error_report, real_error_report, sk); + + req->error = TUX_ERROR_CONN_CLOSE; + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_state_change (struct sock *sk) +{ + HANDLE_CALLBACK(state_change, tux_state_change, real_state_change, sk); + + if (req->sock && req->sock->sk && + (req->sock->sk->sk_state > TCP_ESTABLISHED)) { + Dprintk("req %p changed to TCP non-established!\n", req); + Dprintk("req->sock: %p\n", req->sock); + if (req->sock) + Dprintk("req->sock->sk: %p\n", req->sock->sk); + if (req->sock && req->sock->sk) + Dprintk("TCP state: %d\n", req->sock->sk->sk_state); + Dprintk("req->error = TUX_ERROR_CONN_CLOSE!\n"); + req->error = TUX_ERROR_CONN_CLOSE; + } + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_destruct (struct sock *sk) +{ + BUG(); +} + +static void tux_ftp_data_ready (struct sock *sk, int len) +{ + HANDLE_CALLBACK_1(data_ready, tux_ftp_data_ready, + ftp_real_data_ready, sk, len); + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_ftp_write_space (struct sock *sk) +{ + HANDLE_CALLBACK_1(write_space, tux_ftp_write_space, + ftp_real_write_space, sk); + + Dprintk("sk->sk_wmem_queued: %d, sk->sk_sndbuf: %d.\n", + sk->sk_wmem_queued, sk->sk_sndbuf); + + if (tcp_wspace(sk) >= sk->sk_sndbuf/10*8) { + clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + if (!idle_event(req)) + output_space_event(req); + } + read_unlock(&sk->sk_callback_lock); +} + +static void tux_ftp_error_report (struct sock *sk) +{ + HANDLE_CALLBACK(error_report, tux_ftp_error_report, + ftp_real_error_report, sk); + + TDprintk("req %p sock %p got TCP errors on FTP data connection!\n", req, sk); + TDprintk("req->error = TUX_ERROR_CONN_CLOSE!\n"); + req->error = TUX_ERROR_CONN_CLOSE; + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_ftp_state_change (struct sock *sk) +{ + HANDLE_CALLBACK(state_change, tux_ftp_state_change, + ftp_real_state_change, sk); + + if (req->sock && req->sock->sk && + (req->sock->sk->sk_state > TCP_ESTABLISHED)) { + Dprintk("req %p FTP control sock changed to TCP non-established!\n", req); + Dprintk("req->sock: %p\n", req->sock); + TDprintk("req->error = TUX_ERROR_CONN_CLOSE!\n"); + + req->error = TUX_ERROR_CONN_CLOSE; + } + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_ftp_create_child (struct sock *sk, struct sock *newsk) +{ + HANDLE_CALLBACK(create_child, tux_ftp_create_child, + ftp_real_create_child, sk, newsk); + + newsk->sk_user_data = NULL; + newsk->sk_data_ready = req->ftp_real_data_ready; + newsk->sk_state_change = req->ftp_real_state_change; + newsk->sk_write_space = req->ftp_real_write_space; + newsk->sk_error_report = req->ftp_real_error_report; + newsk->sk_create_child = req->ftp_real_create_child; + newsk->sk_destruct = req->ftp_real_destruct; + + if (!idle_event(req)) + output_space_event(req); + read_unlock(&sk->sk_callback_lock); +} + +static void tux_ftp_destruct (struct sock *sk) +{ + BUG(); +} + +static void link_tux_socket (tux_req_t *req, struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (req->sock) + TUX_BUG(); + if (sk->sk_destruct == tux_destruct) + TUX_BUG(); + /* + * (No need to lock the socket, we just want to + * make sure that events from now on go through + * tux_data_ready()) + */ + write_lock_irq(&sk->sk_callback_lock); + + req->sock = sock; + sk->sk_user_data = req; + + req->real_data_ready = sk->sk_data_ready; + req->real_state_change = sk->sk_state_change; + req->real_write_space = sk->sk_write_space; + req->real_error_report = sk->sk_error_report; + req->real_destruct = sk->sk_destruct; + + sk->sk_data_ready = tux_data_ready; + sk->sk_state_change = tux_state_change; + sk->sk_write_space = tux_write_space; + sk->sk_error_report = tux_error_report; + sk->sk_destruct = tux_destruct; + + write_unlock_irq(&sk->sk_callback_lock); + + if (req->real_destruct == tux_destruct) + TUX_BUG(); + req->client_addr = inet_sk(sk)->daddr; + req->client_port = inet_sk(sk)->dport; + + add_wait_queue(sk->sk_sleep, &req->sleep); +} + +void __link_data_socket (tux_req_t *req, struct socket *sock, + struct sock *sk) +{ + /* + * (No need to lock the socket, we just want to + * make sure that events from now on go through + * tux_data_ready()) + */ + write_lock_irq(&sk->sk_callback_lock); + + req->data_sock = sock; + sk->sk_user_data = req; + + req->ftp_real_data_ready = sk->sk_data_ready; + req->ftp_real_state_change = sk->sk_state_change; + req->ftp_real_write_space = sk->sk_write_space; + req->ftp_real_error_report = sk->sk_error_report; + req->ftp_real_create_child = sk->sk_create_child; + req->ftp_real_destruct = sk->sk_destruct; + + sk->sk_data_ready = tux_ftp_data_ready; + sk->sk_state_change = tux_ftp_state_change; + sk->sk_write_space = tux_ftp_write_space; + sk->sk_error_report = tux_ftp_error_report; + sk->sk_create_child = tux_ftp_create_child; + sk->sk_destruct = tux_ftp_destruct; + + if (req->ftp_real_destruct == tux_ftp_destruct) + TUX_BUG(); + + write_unlock_irq(&sk->sk_callback_lock); + + add_wait_queue(sk->sk_sleep, &req->ftp_sleep); +} + +void link_tux_data_socket (tux_req_t *req, struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (req->data_sock) + TUX_BUG(); + if (sk->sk_destruct == tux_ftp_destruct) + TUX_BUG(); + __link_data_socket(req, sock, sk); +} + +void unlink_tux_socket (tux_req_t *req) +{ + struct sock *sk; + + if (!req->sock || !req->sock->sk) + return; + sk = req->sock->sk; + + write_lock_irq(&sk->sk_callback_lock); + if (!sk->sk_user_data) + TUX_BUG(); + if (req->real_destruct == tux_destruct) + TUX_BUG(); + + sk->sk_user_data = NULL; + + sk->sk_data_ready = req->real_data_ready; + sk->sk_state_change = req->real_state_change; + sk->sk_write_space = req->real_write_space; + sk->sk_error_report = req->real_error_report; + sk->sk_destruct = req->real_destruct; + + if (sk->sk_destruct == tux_destruct) + TUX_BUG(); + + req->real_data_ready = NULL; + req->real_state_change = NULL; + req->real_write_space = NULL; + req->real_error_report = NULL; + req->real_destruct = NULL; + + write_unlock_irq(&sk->sk_callback_lock); + + remove_wait_queue(sk->sk_sleep, &req->sleep); +} + +void unlink_tux_data_socket (tux_req_t *req) +{ + struct sock *sk; + + if (!req->data_sock || !req->data_sock->sk) + return; + sk = req->data_sock->sk; + + write_lock_irq(&sk->sk_callback_lock); + + if (req->real_destruct == tux_ftp_destruct) + TUX_BUG(); + + sk->sk_user_data = NULL; + sk->sk_data_ready = req->ftp_real_data_ready; + sk->sk_state_change = req->ftp_real_state_change; + sk->sk_write_space = req->ftp_real_write_space; + sk->sk_error_report = req->ftp_real_error_report; + sk->sk_create_child = req->ftp_real_create_child; + sk->sk_destruct = req->ftp_real_destruct; + + req->ftp_real_data_ready = NULL; + req->ftp_real_state_change = NULL; + req->ftp_real_write_space = NULL; + req->ftp_real_error_report = NULL; + req->ftp_real_create_child = NULL; + req->ftp_real_destruct = NULL; + + write_unlock_irq(&sk->sk_callback_lock); + + if (sk->sk_destruct == tux_ftp_destruct) + TUX_BUG(); + + remove_wait_queue(sk->sk_sleep, &req->ftp_sleep); +} + +void add_tux_atom (tux_req_t *req, atom_func_t *atom) +{ + Dprintk("adding TUX atom %p to req %p, atom_idx: %d, at %p/%p.\n", + atom, req, req->atom_idx, __builtin_return_address(0), __builtin_return_address(1)); + if (req->atom_idx == MAX_TUX_ATOMS) + TUX_BUG(); + req->atoms[req->atom_idx] = atom; + req->atom_idx++; +} + +void del_tux_atom (tux_req_t *req) +{ + if (!req->atom_idx) + TUX_BUG(); + req->atom_idx--; + Dprintk("removing TUX atom %p to req %p, atom_idx: %d, at %p.\n", + req->atoms[req->atom_idx], req, req->atom_idx, __builtin_return_address(0)); +} + +void tux_schedule_atom (tux_req_t *req, int cachemiss) +{ + if (!list_empty(&req->work)) + TUX_BUG(); + if (!req->atom_idx) + TUX_BUG(); + req->atom_idx--; + Dprintk("DOING TUX atom %p, req %p, atom_idx: %d, at %p.\n", + req->atoms[req->atom_idx], req, req->atom_idx, __builtin_return_address(0)); + might_sleep(); + req->atoms[req->atom_idx](req, cachemiss); + might_sleep(); + Dprintk("DONE TUX atom %p, req %p, atom_idx: %d, at %p.\n", + req->atoms[req->atom_idx], req, req->atom_idx, __builtin_return_address(0)); +} + +/* + * Puts newly accepted connections into the inputqueue. This is the + * first step in the life of a TUX request. + */ +int accept_requests (threadinfo_t *ti) +{ + int count = 0, last_count = 0, error, socknr = 0; + struct socket *sock, *new_sock; + struct tcp_opt *tp1, *tp2; + tux_req_t *req; + + if (ti->nr_requests > tux_max_connect) + goto out; + +repeat: + for (socknr = 0; socknr < CONFIG_TUX_NUMSOCKETS; socknr++) { + tux_listen_t *tux_listen; + + tux_listen = ti->listen + socknr; + sock = tux_listen->sock; + if (!sock) + break; + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) + break; + + tp1 = tcp_sk(sock->sk); + /* + * Quick test to see if there are connections on the queue. + * This is cheaper than accept() itself because this saves us + * the allocation of a new socket. (Which doesn't seem to be + * used anyway) + */ + if (tp1->accept_queue) { + tux_proto_t *proto; + + if (!count++) + __set_task_state(current, TASK_RUNNING); + + new_sock = sock_alloc(); + if (!new_sock) + goto out; + + new_sock->type = sock->type; + new_sock->ops = sock->ops; + + error = sock->ops->accept(sock, new_sock, O_NONBLOCK); + if (error < 0) + goto err; + if (new_sock->sk->sk_state != TCP_ESTABLISHED) + goto err; + + tp2 = tcp_sk(new_sock->sk); + tp2->nonagle = 2; + tp2->ack.pingpong = tux_ack_pingpong; + new_sock->sk->sk_reuse = 1; + sock_set_flag(new_sock->sk, SOCK_URGINLINE); + + /* Allocate a request-entry for the connection */ + req = kmalloc_req(ti); + if (!req) + BUG(); + link_tux_socket(req, new_sock); + + proto = req->proto = tux_listen->proto; + + proto->got_request(req); + } + } + if (count != last_count) { + last_count = count; + goto repeat; + } +out: + return count; +err: + sock_release(new_sock); + goto out; +} + diff --git a/net/tux/cachemiss.c b/net/tux/cachemiss.c new file mode 100644 index 000000000..f840583bb --- /dev/null +++ b/net/tux/cachemiss.c @@ -0,0 +1,264 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * cachemiss.c: handle the 'slow IO path' by queueing not-yet-cached + * requests to the IO-thread pool. Dynamic load balancing is done + * between IO threads, based on the number of requests they have pending. + */ + +#include +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +void queue_cachemiss (tux_req_t *req) +{ + iothread_t *iot = req->ti->iot; + + Dprintk("queueing_cachemiss(req:%p) (req->cwd_dentry: %p) at %p:%p.\n", + req, req->cwd_dentry, __builtin_return_address(0), __builtin_return_address(1)); + if (req->idle_input || req->wait_output_space) + TUX_BUG(); + req->had_cachemiss = 1; + if (!list_empty(&req->work)) + TUX_BUG(); + spin_lock(&iot->async_lock); + if (connection_too_fast(req)) + list_add_tail(&req->work, &iot->async_queue); + else + list_add(&req->work, &iot->async_queue); + iot->nr_async_pending++; + INC_STAT(nr_cachemiss_pending); + spin_unlock(&iot->async_lock); + + wake_up(&iot->async_sleep); +} + +static tux_req_t * get_cachemiss (iothread_t *iot) +{ + struct list_head *tmp; + tux_req_t *req = NULL; + + spin_lock(&iot->async_lock); + if (!list_empty(&iot->async_queue)) { + + tmp = iot->async_queue.next; + req = list_entry(tmp, tux_req_t, work); + + Dprintk("get_cachemiss(%p): got req %p.\n", iot, req); + list_del(tmp); + DEBUG_DEL_LIST(tmp); + iot->nr_async_pending--; + DEC_STAT(nr_cachemiss_pending); + + if (req->ti->iot != iot) + TUX_BUG(); + } + spin_unlock(&iot->async_lock); + return req; +} + +struct file * tux_open_file (char *filename, int mode) +{ + struct file *filp; + + if (!filename) + TUX_BUG(); + + /* Rule no. 3 -- Does the file exist ? */ + + filp = filp_open(filename, mode, 0600); + + if (IS_ERR(filp) || !filp || !filp->f_dentry) + goto err; + +out: + return filp; +err: + Dprintk("filp_open() error: %d.\n", (int)filp); + filp = NULL; + goto out; +} + +static int cachemiss_thread (void *data) +{ + tux_req_t *req; + struct k_sigaction *ka; + DECLARE_WAITQUEUE(wait, current); + iothread_t *iot = data; + int nr = iot->ti->cpu, wake_up; + + Dprintk("iot %p/%p got started.\n", iot, current); + drop_permissions(); + + spin_lock(&iot->async_lock); + iot->threads++; + sprintf(current->comm, "async IO %d/%d", nr, iot->threads); + + + spin_lock_irq(¤t->sighand->siglock); + ka = current->sighand->action + SIGCHLD-1; + ka->sa.sa_handler = SIG_IGN; + siginitsetinv(¤t->blocked, sigmask(SIGCHLD)); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + spin_unlock(&iot->async_lock); +#if CONFIG_SMP + { + cpumask_t mask; + + if (cpu_isset(nr, cpu_online_map)) { + cpus_clear(mask); + cpu_set(nr, mask); + set_cpus_allowed(current, mask); + } + + } +#endif + + add_wait_queue_exclusive(&iot->async_sleep, &wait); + + for (;;) { + while (!list_empty(&iot->async_queue) && + (req = get_cachemiss(iot))) { + + if (!req->atom_idx) { + add_tux_atom(req, flush_request); + add_req_to_workqueue(req); + continue; + } + tux_schedule_atom(req, 1); + if (signal_pending(current)) + flush_all_signals(); + } + if (signal_pending(current)) + flush_all_signals(); + if (!list_empty(&iot->async_queue)) + continue; + if (iot->shutdown) { + Dprintk("iot %p/%p got shutdown!\n", iot, current); + break; + } + __set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&iot->async_queue)) { + Dprintk("iot %p/%p going to sleep.\n", iot, current); + schedule(); + Dprintk("iot %p/%p got woken up.\n", iot, current); + } + __set_current_state(TASK_RUNNING); + } + + remove_wait_queue(&iot->async_sleep, &wait); + + wake_up = 0; + spin_lock(&iot->async_lock); + if (!--iot->threads) + wake_up = 1; + spin_unlock(&iot->async_lock); + Dprintk("iot %p/%p has finished shutdown!\n", iot, current); + if (wake_up) { + Dprintk("iot %p/%p waking up master.\n", iot, current); + wake_up(&iot->wait_shutdown); + } + + return 0; +} + +static void __stop_cachemiss_threads (iothread_t *iot) +{ + DECLARE_WAITQUEUE(wait, current); + + Dprintk("stopping async IO threads %p.\n", iot); + add_wait_queue(&iot->wait_shutdown, &wait); + + spin_lock(&iot->async_lock); + if (iot->shutdown) + TUX_BUG(); + if (!iot->threads) + TUX_BUG(); + iot->shutdown = 1; + wake_up_all(&iot->async_sleep); + spin_unlock(&iot->async_lock); + + __set_current_state(TASK_UNINTERRUPTIBLE); + Dprintk("waiting for async IO threads %p to exit.\n", iot); + schedule(); + remove_wait_queue(&iot->wait_shutdown, &wait); + + if (iot->threads) + TUX_BUG(); + if (iot->nr_async_pending) + TUX_BUG(); + Dprintk("stopped async IO threads %p.\n", iot); +} + +void stop_cachemiss_threads (threadinfo_t *ti) +{ + iothread_t *iot = ti->iot; + + if (!iot) + TUX_BUG(); + if (iot->nr_async_pending) + TUX_BUG(); + __stop_cachemiss_threads(iot); + ti->iot = NULL; + kfree(iot); +} + +int start_cachemiss_threads (threadinfo_t *ti) +{ + int i, pid; + + iothread_t *iot; + + iot = kmalloc(sizeof(*iot), GFP_KERNEL); + if (!iot) + return -ENOMEM; + memset(iot, 0, sizeof(*iot)); + + iot->ti = ti; + iot->async_lock = SPIN_LOCK_UNLOCKED; + iot->nr_async_pending = 0; + INIT_LIST_HEAD(&iot->async_queue); + init_waitqueue_head(&iot->async_sleep); + init_waitqueue_head(&iot->wait_shutdown); + + for (i = 0; i < NR_IO_THREADS; i++) { + pid = kernel_thread(cachemiss_thread, (void *)iot, 0); + if (pid < 0) { + printk(KERN_ERR "TUX: error %d creating IO thread!\n", + pid); + __stop_cachemiss_threads(iot); + kfree(iot); + return pid; + } + } + ti->iot = iot; + /* + * Wait for all cachemiss threads to start up: + */ + while (iot->threads != NR_IO_THREADS) { + __set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + } + return 0; +} + diff --git a/net/tux/cgi.c b/net/tux/cgi.c new file mode 100644 index 000000000..fda4d3825 --- /dev/null +++ b/net/tux/cgi.c @@ -0,0 +1,173 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * cgi.c: user-space CGI (and other) code execution. + */ + +#define __KERNEL_SYSCALLS__ +#define __KERNEL_SYSCALLS_NO_ERRNO__ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +static int exec_usermode(char *program_path, char *argv[], char *envp[]) +{ + int i, err; + + err = tux_chroot(tux_cgiroot); + if (err) { + printk(KERN_ERR "TUX: CGI chroot returned %d, /proc/sys/net/tux/cgiroot is probably set up incorrectly! Aborting CGI execution.\n", err); + return err; + } + + /* Allow execve args to be in kernel space. */ + set_fs(KERNEL_DS); + + flush_signals(current); + spin_lock_irq(¤t->sighand->siglock); + flush_signal_handlers(current, 1); + spin_unlock_irq(¤t->sighand->siglock); + + for (i = 3; i < current->files->max_fds; i++ ) + if (current->files->fd[i]) + tux_close(i); + + err = execve(program_path, argv, envp); + if (err < 0) + return err; + return 0; +} + +static inline long tux_dup(unsigned int fildes) +{ + int ret = -EBADF; + struct file * file = fget(fildes); + + if (file) + ret = dupfd(file, 0); + return ret; +} + +static int exec_helper (void * data) +{ + exec_param_t *param = data; + char **tmp; + int ret; + + sprintf(current->comm,"doexec - %d", current->pid); +#if CONFIG_SMP + if (!tux_cgi_inherit_cpu) { + + cpumask_t cgi_mask, map; + + mask_to_cpumask(tux_cgi_cpu_mask, &cgi_mask); + cpus_and(map, cpu_online_map, cgi_mask); + + if (!(cpus_empty(map))) + set_cpus_allowed(current, cgi_mask); + else + set_cpus_allowed(current, cpu_online_map); + } +#endif + + if (!param) + TUX_BUG(); + Dprintk("doing exec(%s).\n", param->command); + + Dprintk("argv: "); + tmp = param->argv; + while (*tmp) { + Dprintk("{%s} ", *tmp); + tmp++; + } + Dprintk("\n"); + Dprintk("envp: "); + tmp = param->envp; + while (*tmp) { + Dprintk("{%s} ", *tmp); + tmp++; + } + Dprintk("\n"); + /* + * Set up stdin, stdout and stderr of the external + * CGI application. + */ + if (param->pipe_fds) { + tux_close(1); + tux_close(2); + tux_close(4); + if (tux_dup(3) != 1) + TUX_BUG(); + if (tux_dup(5) != 2) + TUX_BUG(); + tux_close(3); + tux_close(5); + // do not close on exec. +#if 0 + sys_fcntl(0, F_SETFD, 0); + sys_fcntl(1, F_SETFD, 0); + sys_fcntl(2, F_SETFD, 0); +#else + spin_lock(¤t->files->file_lock); + FD_CLR(0, current->files->close_on_exec); + FD_CLR(1, current->files->close_on_exec); + FD_CLR(2, current->files->close_on_exec); + spin_unlock(¤t->files->file_lock); +#endif + } + ret = exec_usermode(param->command, param->argv, param->envp); + if (ret < 0) + Dprintk("bug: exec() returned %d.\n", ret); + else + Dprintk("exec()-ed successfully!\n"); + return 0; +} + +pid_t tux_exec_process (char *command, char **argv, + char **envp, int pipe_fds, + exec_param_t *param, int wait) +{ + exec_param_t param_local; + pid_t pid; + struct k_sigaction *ka; + + ka = current->sighand->action + SIGCHLD-1; + ka->sa.sa_handler = SIG_IGN; + + if (!param && wait) + param = ¶m_local; + + param->command = command; + param->argv = argv; + param->envp = envp; + param->pipe_fds = pipe_fds; + +repeat_fork: + pid = kernel_thread(exec_helper, (void*) param, CLONE_SIGHAND|SIGCHLD); + Dprintk("kernel thread created PID %d.\n", pid); + if (pid < 0) { + printk(KERN_ERR "TUX: could not create new CGI kernel thread due to %d... retrying.\n", pid); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + goto repeat_fork; + } + return pid; +} diff --git a/net/tux/directory.c b/net/tux/directory.c new file mode 100644 index 000000000..714800e7b --- /dev/null +++ b/net/tux/directory.c @@ -0,0 +1,297 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * directory.c: directory listing support + */ + +#define __KERNEL_SYSCALLS__ +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +char * tux_print_path (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt, char *buf, unsigned int max_len) +{ + char *res; + struct dentry *cwd, *root; + struct vfsmount *cwd_mnt, *rootmnt; + + cwd = dget(dentry); + cwd_mnt = mntget(mnt); + root = dget(req->docroot_dentry); + rootmnt = mntget(req->docroot_mnt); + + spin_lock(&dcache_lock); + res = __d_path(cwd, cwd_mnt, root, rootmnt, buf, max_len); + spin_unlock(&dcache_lock); + + dput(cwd); + mntput(cwd_mnt); + dput(root); + mntput(rootmnt); + + return res; +} + +/* + * There are filesystems that do not fill in ->d_type correctly. + * Determine file-type. + */ +static int get_d_type (struct dentry *dentry) +{ + unsigned int mode = dentry->d_inode->i_mode; + + if (S_ISREG(mode)) + return DT_REG; + if (S_ISDIR(mode)) + return DT_DIR; + if (S_ISLNK(mode)) + return DT_LNK; + if (S_ISFIFO(mode)) + return DT_FIFO; + if (S_ISSOCK(mode)) + return DT_SOCK; + if (S_ISCHR(mode)) + return DT_CHR; + if (S_ISBLK(mode)) + return DT_BLK; + return 0; +} + +static void do_dir_line (tux_req_t *req, int cachemiss) +{ + struct linux_dirent64 *dirp, *dirp0; + char string0[MAX_OBJECTNAME_LEN+200], *tmp; + int len, curroff, total, str_len = 0; + int err, flag = cachemiss ? 0 : LOOKUP_ATOMIC; + struct nameidata base; + struct dentry *dentry = NULL; + struct inode *inode = NULL; + struct vfsmount *mnt = NULL; + + if (req->proto->check_req_err(req, cachemiss)) + return; + + tmp = NULL; + dirp0 = req->dirp0; + curroff = req->curroff; + total = req->total; + + dirp = (struct linux_dirent64 *)((char *)dirp0 + curroff); + if (!dirp->d_name || !dirp->d_name[0]) + goto next_dir; + /* + * Hide .xxxxx files: + */ + if (dirp->d_name[0] == '.') + goto next_dir; + Dprintk("<%s T:%d (off:%Ld) (len:%d)>\n", dirp->d_name, dirp->d_type, dirp->d_off, dirp->d_reclen); + if (tux_hide_unreadable) { + switch (dirp->d_type) { + default: + goto next_dir; + case DT_UNKNOWN: + case DT_REG: + case DT_DIR: + case DT_LNK: + /* valid entries - fall through. */ + ; + } + } + len = strlen(dirp->d_name); + if (len >= MAX_OBJECTNAME_LEN) { + dirp->d_name[MAX_OBJECTNAME_LEN] = 0; + len = MAX_OBJECTNAME_LEN-1; + } + + if (!req->dentry) + TUX_BUG(); + + base.flags = flag; + base.last_type = LAST_ROOT; + base.dentry = dget(req->dentry); + base.mnt = mntget(req->cwd_mnt); + + switch_docroot(req); + err = path_walk(dirp->d_name, &base); + + Dprintk("path_walk() returned %d.\n", err); + + if (err) { + if (err == -EWOULDBLOCKIO) { + add_tux_atom(req, do_dir_line); + queue_cachemiss(req); + return; + } + goto next_dir; + } + + dentry = base.dentry; + mnt = base.mnt; + if (!dentry) + TUX_BUG(); + if (IS_ERR(dentry)) + TUX_BUG(); + inode = dentry->d_inode; + if (!inode) + TUX_BUG(); + if (!dirp->d_type) + dirp->d_type = get_d_type(dentry); + if (tux_hide_unreadable) { + umode_t mode; + + mode = inode->i_mode; + if (mode & tux_mode_forbidden) + goto out_dput; + if (!(mode & tux_mode_allowed)) + goto out_dput; + + err = permission(inode, MAY_READ, NULL); + if (err) + goto out_dput; + if (dirp->d_type == DT_DIR) { + err = permission(inode, MAY_EXEC, NULL); + if (err) + goto out_dput; + } + } + + tmp = req->proto->print_dir_line(req, string0, dirp->d_name, len, dirp->d_type, dentry, inode); + if (tmp) + str_len = tmp-string0; +out_dput: + dput(dentry); + mntput(mnt); +next_dir: + curroff += dirp->d_reclen; + + if (tmp && (tmp != string0)) + Dprintk("writing line (len: %d): <%s>\n", strlen(string0), string0); + + if (curroff < total) { + req->dirp0 = dirp0; + req->curroff = curroff; + add_tux_atom(req, do_dir_line); + } else { + kfree(dirp0); + req->dirp0 = NULL; + req->curroff = 0; + // falls back to the list_directory atom + } + if (tmp && (tmp != string0)) + __send_async_message(req, string0, 200, str_len, 0); + else + add_req_to_workqueue(req); +} + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) +#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) + +static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned int d_type) +{ + struct linux_dirent64 * dirent, d; + struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; + int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) { + d.d_off = offset; + copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off)); + } + dirent = buf->current_dir; + buf->previous = dirent; + memset(&d, 0, NAME_OFFSET(&d)); + d.d_ino = ino; + d.d_reclen = reclen; + d.d_type = d_type; + copy_to_user(dirent, &d, NAME_OFFSET(&d)); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + dirent = (void *)dirent + reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +} +#define DIRENT_SIZE 3000 + +void list_directory (tux_req_t *req, int cachemiss) +{ + struct getdents_callback64 buf; + struct linux_dirent64 *dirp0; + mm_segment_t oldmm; + int total; + + Dprintk("list_directory(%p, %d), dentry: %p.\n", req, cachemiss, req->dentry); + if (!req->cwd_dentry) + TUX_BUG(); + + if (!cachemiss) { + add_tux_atom(req, list_directory); + queue_cachemiss(req); + return; + } + + dirp0 = tux_kmalloc(DIRENT_SIZE); + + buf.current_dir = dirp0; + buf.previous = NULL; + buf.count = DIRENT_SIZE; + buf.error = 0; + + oldmm = get_fs(); set_fs(KERNEL_DS); + set_fs(KERNEL_DS); + total = vfs_readdir(&req->in_file, filldir64, &buf); + set_fs(oldmm); + + if (buf.previous) + total = DIRENT_SIZE - buf.count; + + Dprintk("total: %d (buf.error: %d, buf.previous %p)\n", + total, buf.error, buf.previous); + + if (total < 0) { + kfree(dirp0); + req_err(req); + add_req_to_workqueue(req); + return; + } + if (!total) { + kfree(dirp0); + req->in_file.f_pos = 0; + add_req_to_workqueue(req); + return; + } + + if (!req->cwd_dentry) + TUX_BUG(); + add_tux_atom(req, list_directory); + + req->dirp0 = dirp0; + req->curroff = 0; + req->total = total; + add_tux_atom(req, do_dir_line); + + add_req_to_workqueue(req); +} + diff --git a/net/tux/extcgi.c b/net/tux/extcgi.c new file mode 100644 index 000000000..1d1d1d5cd --- /dev/null +++ b/net/tux/extcgi.c @@ -0,0 +1,329 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * extcgi.c: dynamic TUX module which forks and starts an external CGI + */ + +#define __KERNEL_SYSCALLS__ +#define __KERNEL_SYSCALLS_NO_ERRNO__ + +#include +#include "parser.h" + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#define MAX_ENVLEN 1000 +#define MAX_CGI_METAVARIABLES 32 +#define CGI_CHUNK_SIZE 1024 +#define MAX_CGI_COMMAND_LEN 256 + +#if CONFIG_TUX_DEBUG +#define PRINT_MESSAGE_LEFT \ + Dprintk("CGI message left at %s:%d:\n--->{%s}<---\n", \ + __FILE__, __LINE__, curr) +#else +#define PRINT_MESSAGE_LEFT do {} while(0) +#endif + +#define GOTO_INCOMPLETE do { Dprintk("invalid CGI reply at %s:%d.\n", __FILE__, __LINE__); goto invalid; } while (0) + +/* + * Please acknowledge our hard work by not changing this define, or + * at least please acknowledge us by leaving "TUX/2.0 (Linux)" in + * the ID string. Thanks! :-) + */ +#define CGI_SUCCESS2 "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: TUX/2.0 (Linux)\r\n" + +static int handle_cgi_reply (tux_req_t *req) +{ + int first = 1; + int len, left, total; + char *buf, *tmp; + mm_segment_t oldmm; + + buf = tux_kmalloc(CGI_CHUNK_SIZE+1); + tux_close(3); + tux_close(4); + tux_close(5); + oldmm = get_fs(); set_fs(KERNEL_DS); + send_sync_buf(NULL, req->sock, CGI_SUCCESS2, sizeof(CGI_SUCCESS2)-1, MSG_MORE); + set_fs(oldmm); + + req->bytes_sent = 0; + /* + * The new process is the new owner of the socket, it will + * close it. + */ +repeat: + left = CGI_CHUNK_SIZE; + len = 0; + total = 0; + tmp = buf; + do { + mm_segment_t oldmm; + + tmp += len; + total += len; + left -= len; + if (!left) + break; +repeat_read: + Dprintk("reading %d bytes via read().\n", left); + oldmm = get_fs(); set_fs(KERNEL_DS); + len = read(2, tmp, left); + set_fs(oldmm); + Dprintk("got %d bytes from read() (total: %d).\n", len, total); + if (len > 0) + tmp[len] = 0; + Dprintk("CGI reply: (%d bytes, total %d).\n", len, total); + if (len == -ERESTARTSYS) { + flush_all_signals(); + goto repeat_read; + } + } while (len > 0); + if (total > CGI_CHUNK_SIZE) { + printk(KERN_ERR "TUX: CGI weirdness. total: %d, len: %d, left: %d.\n", total, len, left); + TUX_BUG(); + } + Dprintk("CGI done reply chunk: (%d bytes last, total %d).\n", len, total); + if (total) { + mm_segment_t oldmm; + + oldmm = get_fs(); set_fs(KERNEL_DS); + if (!len) + send_sync_buf(NULL, req->sock, buf, total, 0); + else + send_sync_buf(NULL, req->sock, buf, total, MSG_MORE); + set_fs(oldmm); + req->bytes_sent += total; + } + + Dprintk("bytes_sent: %d\n", req->bytes_sent); + if ((total > 0) && first) { + first = 0; + + if (buf[total]) + TUX_BUG(); + tmp = strstr(buf, "\n\n"); + if (tmp) { + req->bytes_sent -= (tmp-buf) + 2; + Dprintk("new bytes_sent: %d\n", req->bytes_sent); + } else { + req->bytes_sent = 0; + req_err(req); + } + } + if (len < 0) + Dprintk("sys_read returned with %d.\n", len); + else { + if (total > 0) + goto repeat; + } + tux_close(2); + + req->status = 200; + add_req_to_workqueue(req); + kfree(buf); + + return -1; +} + +static int exec_external_cgi (void *data) +{ + exec_param_t param; + tux_req_t *req = data; + char *envp[MAX_CGI_METAVARIABLES+1], **envp_p; + char *argv[] = { "extcgi", NULL}; + char *envstr, *tmp; + unsigned int host; + struct k_sigaction *ka; + int in_pipe_fds[2], out_pipe_fds[2], err_pipe_fds[2], len, err; + char *command; + pid_t pid; + + len = strlen(tux_common_docroot); + if (req->objectname_len + len + 12 > MAX_CGI_COMMAND_LEN) + return -ENOMEM; + sprintf(current->comm,"cgimain - %d", current->pid); + host = inet_sk(req->sock->sk)->daddr; + + envstr = tux_kmalloc(MAX_ENVLEN); + command = tux_kmalloc(MAX_CGI_COMMAND_LEN); + + tmp = envstr; + envp_p = envp; + +#define WRITE_ENV(str...) \ + if (envp_p >= envp + MAX_CGI_METAVARIABLES) \ + TUX_BUG(); \ + len = sprintf(tmp, str); \ + *envp_p++ = tmp; \ + tmp += len + 1; \ + if (tmp >= envstr + MAX_ENVLEN) \ + TUX_BUG(); + + #define WRITE_ENV_STR(str,field,len) \ + do { \ + int offset; \ + \ + offset = sizeof(str)-1; \ + err = -EFAULT; \ + if (tmp - envstr + offset + len >= MAX_ENVLEN) \ + goto out; \ + if (envp_p >= envp + MAX_CGI_METAVARIABLES) \ + TUX_BUG(); \ + memcpy(tmp, str, offset); \ + memcpy(tmp + offset, field, len); \ + offset += len; \ + tmp[offset] = 0; \ + *envp_p++ = tmp; \ + tmp += offset + 1; \ + } while (0) + + WRITE_ENV("GATEWAY_INTERFACE=CGI/1.1"); + WRITE_ENV("CONTENT_LENGTH=%d", req->post_data_len); + WRITE_ENV("REMOTE_ADDR=%d.%d.%d.%d", NIPQUAD(host)); + WRITE_ENV("SERVER_PORT=%d", 80); + WRITE_ENV("SERVER_SOFTWARE=TUX/2.0 (Linux)"); + +#if 1 + WRITE_ENV("DOCUMENT_ROOT=/"); + WRITE_ENV("PATH_INFO=/"); +#else + WRITE_ENV_STR("DOCUMENT_ROOT=", tux_common_docroot, len); + WRITE_ENV_STR("PATH_INFO=", tux_common_docroot, len); +#endif + WRITE_ENV_STR("QUERY_STRING=", req->query_str, req->query_len); + WRITE_ENV_STR("REQUEST_METHOD=", req->method_str, req->method_len); + WRITE_ENV_STR("SCRIPT_NAME=", req->objectname, req->objectname_len); + WRITE_ENV_STR("SERVER_PROTOCOL=", req->version_str, req->version_len); + + if (req->content_type_len) + WRITE_ENV_STR("CONTENT_TYPE=", + req->content_type_str, req->content_type_len); + if (req->cookies_len) + WRITE_ENV_STR("HTTP_COOKIE=", + req->cookies_str, req->cookies_len); + + if (req->host_len) + WRITE_ENV_STR("SERVER_NAME=", req->host, req->host_len); + else { + const char *host = "localhost"; + WRITE_ENV_STR("SERVER_NAME=", host, strlen(host)); + } + + *envp_p = NULL; + + spin_lock_irq(¤t->sighand->siglock); + ka = current->sighand->action + SIGPIPE-1; + ka->sa.sa_handler = SIG_IGN; + siginitsetinv(¤t->blocked, sigmask(SIGCHLD)); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + tux_close(0); tux_close(1); + tux_close(2); tux_close(3); + tux_close(4); tux_close(5); + + in_pipe_fds[0] = in_pipe_fds[1] = -1; + out_pipe_fds[0] = out_pipe_fds[1] = -1; + err_pipe_fds[0] = err_pipe_fds[1] = -1; + + err = -ENFILE; + if (do_pipe(in_pipe_fds)) + goto out; + if (do_pipe(out_pipe_fds)) + goto out; + if (do_pipe(err_pipe_fds)) + goto out; + + if (in_pipe_fds[0] != 0) TUX_BUG(); + if (in_pipe_fds[1] != 1) TUX_BUG(); + if (out_pipe_fds[0] != 2) TUX_BUG(); + if (out_pipe_fds[1] != 3) TUX_BUG(); + if (err_pipe_fds[0] != 4) TUX_BUG(); + if (err_pipe_fds[1] != 5) TUX_BUG(); + + if (req->virtual && req->host_len) + sprintf(command, "/%s/cgi-bin/%s", req->host, req->objectname); + else + sprintf(command, "/cgi-bin/%s", req->objectname); + Dprintk("before CGI exec.\n"); + pid = tux_exec_process(command, argv, envp, 1, ¶m, 0); + Dprintk("after CGI exec.\n"); + + if (req->post_data_len) { + mm_segment_t oldmm; + int ret; + + Dprintk("POST data to CGI:\n"); + oldmm = get_fs(); set_fs(KERNEL_DS); + ret = write(1, req->post_data_str, req->post_data_len); + set_fs(oldmm); + Dprintk("write() returned: %d.\n", ret); + if (ret != req->post_data_len) + Dprintk("write() returned: %d.\n", ret); + } + + tux_close(0); + tux_close(1); + + handle_cgi_reply(req); + err = 0; + +out: + kfree(envstr); + kfree(command); + + return err; +} + +void start_external_cgi (tux_req_t *req) +{ + int pid; + +repeat: + pid = kernel_thread(exec_external_cgi, (void*) req, SIGCHLD); + if (pid == -1) + return; + if (pid < 0) { + printk(KERN_INFO "TUX: Could not fork external CGI process due to %d, retrying!\n", pid); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + goto repeat; + } +} + +int query_extcgi (tux_req_t *req) +{ + clear_keepalive(req); + start_external_cgi(req); + return -1; +} + +#define EXTCGI_INVALID_HEADER \ + "HTTP/1.1 503 Service Unavailable\r\n" \ + "Content-Length: 23\r\n\r\n" + +#define EXTCGI_INVALID_BODY \ + "TUX: invalid CGI reply." + +#define EXTCGI_INVALID EXTCGI_INVALID_HEADER EXTCGI_INVALID_BODY + diff --git a/net/tux/gzip.c b/net/tux/gzip.c new file mode 100644 index 000000000..5476dff52 --- /dev/null +++ b/net/tux/gzip.c @@ -0,0 +1,40 @@ +/* $Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $ */ + +#include +#include +#include +#include + +#define STREAM_END_SPACE 12 + +int tux_gzip_compress (tux_req_t *req, unsigned char *data_in, unsigned char *data_out, __u32 *in_len, __u32 *out_len) +{ + z_stream *s = &req->ti->gzip_state; + int ret, left; + + down(&req->ti->gzip_sem); + if (zlib_deflateReset(s) != Z_OK) + BUG(); + + s->next_in = data_in; + s->next_out = data_out; + s->avail_in = *in_len; + s->avail_out = *out_len; + + Dprintk("calling zlib_deflate with avail_in %d, avail_out %d\n", s->avail_in, s->avail_out); + ret = zlib_deflate(s, Z_FINISH); + Dprintk("deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", s->avail_in, s->avail_out, s->total_in, s->total_out); + + if (ret != Z_STREAM_END) { + printk("bad: deflate returned with %d! avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", ret, s->avail_in, s->avail_out, s->total_in, s->total_out); + BUG(); + } + *in_len = s->avail_in; + *out_len = s->avail_out; + left = s->avail_in; + + up(&req->ti->gzip_sem); + + return left; +} + diff --git a/net/tux/input.c b/net/tux/input.c new file mode 100644 index 000000000..054c3edb1 --- /dev/null +++ b/net/tux/input.c @@ -0,0 +1,641 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * input.c: handle requests arriving on accepted connections + */ + +#include +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +void zap_request (tux_req_t *req, int cachemiss) +{ + if (!req->error) + TUX_BUG(); + if (req->error == TUX_ERROR_CONN_TIMEOUT) { + if (req->proto->request_timeout) { + clear_keepalive(req); + req->proto->request_timeout(req, cachemiss); + } else { + clear_keepalive(req); + if (!cachemiss) + flush_request(req, 0); + else { + add_tux_atom(req, flush_request); + add_req_to_workqueue(req); + } + } + return; + } + + if (!cachemiss && (req->error == TUX_ERROR_CONN_CLOSE)) { + /* + * Zap connection as fast as possible, there is + * no valid client connection anymore: + */ + clear_keepalive(req); + flush_request(req, 0); + } else { + if (req->error == TUX_ERROR_CONN_CLOSE) { + clear_keepalive(req); + add_tux_atom(req, flush_request); + } else + /* + * Potentially redirect to the secondary server: + */ + add_tux_atom(req, redirect_request); + add_req_to_workqueue(req); + } +} + +void __switch_docroot(tux_req_t *req) +{ + if (!req->docroot_dentry || !req->docroot_mnt) + TUX_BUG(); + set_fs_root(current->fs, req->docroot_mnt, req->docroot_dentry); +} + +struct dentry * __tux_lookup (tux_req_t *req, const char *filename, + struct nameidata *base, struct vfsmount **mnt) +{ + int err; + + err = path_walk(filename, base); + if (err) { + Dprintk("path_walk() returned with %d!\n", err); + return ERR_PTR(err); + } + if (*mnt) + TUX_BUG(); + *mnt = base->mnt; + + return base->dentry; +} + +int tux_permission (struct inode *inode) +{ + umode_t mode; + int err; + + mode = inode->i_mode; + Dprintk("URL inode mode: %08x.\n", mode); + + if (mode & tux_mode_forbidden) + return -2; + /* + * at least one bit in the 'allowed' set has to + * be present to allow access. + */ + if (!(mode & tux_mode_allowed)) + return -3; + err = permission(inode,MAY_READ,NULL); + return err; +} + +struct dentry * tux_lookup (tux_req_t *req, const char *filename, + const unsigned int flag, struct vfsmount **mnt) +{ + struct dentry *dentry; + struct nameidata base; + + Dprintk("tux_lookup(%p, %s, %d, virtual: %d, host: %s (%d).)\n", req, filename, flag, req->virtual, req->host, req->host_len); + + base.flags = LOOKUP_FOLLOW|flag; + base.last_type = LAST_ROOT; + if (req->objectname[0] == '/') { + base.dentry = dget(req->docroot_dentry); + base.mnt = mntget(req->docroot_mnt); + } else { + if (!req->cwd_dentry) { + req->cwd_dentry = dget(req->docroot_dentry); + req->cwd_mnt = mntget(req->docroot_mnt); + } + base.dentry = req->cwd_dentry; + dget(base.dentry); + base.mnt = mntget(req->cwd_mnt); + } + + switch_docroot(req); + dentry = __tux_lookup (req, filename, &base, mnt); + + Dprintk("looked up {%s} == dentry %p.\n", filename, dentry); + + if (dentry && !IS_ERR(dentry) && !dentry->d_inode) + TUX_BUG(); + return dentry; +} + +int lookup_object (tux_req_t *req, const unsigned int flag) +{ + struct vfsmount *mnt = NULL; + struct dentry *dentry = NULL; + int perm; + + dentry = tux_lookup(req, req->objectname, flag, &mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) + goto cachemiss; + goto abort; + } + perm = tux_permission(dentry->d_inode); + /* + * Only regular files allowed. + */ + if ((perm < 0) || !S_ISREG(dentry->d_inode->i_mode)) { + req->status = 403; + goto abort; + } + req->total_file_len = dentry->d_inode->i_size; +out: + install_req_dentry(req, dentry, mnt); + return 0; +cachemiss: + return 1; +abort: + if (dentry) { + if (!IS_ERR(dentry)) + dput(dentry); + dentry = NULL; + } + if (mnt) { + if (!IS_ERR(mnt)) + mntput(mnt); + mnt = NULL; + } + req_err(req); + goto out; +} + +void install_req_dentry (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt) +{ + if (req->dentry) + TUX_BUG(); + req->dentry = dentry; + if (req->mnt) + TUX_BUG(); + req->mnt = mnt; + if (req->in_file.f_dentry) + TUX_BUG(); + if (dentry) + open_private_file(&req->in_file, dentry, FMODE_READ); +} + +void release_req_dentry (tux_req_t *req) +{ + if (!req->dentry) { + if (req->in_file.f_dentry) + TUX_BUG(); + return; + } + if (req->in_file.f_op && req->in_file.f_op->release) + req->in_file.f_op->release(req->dentry->d_inode, &req->in_file); + memset(&req->in_file, 0, sizeof(req->in_file)); + + dput(req->dentry); + req->dentry = NULL; + mntput(req->mnt); + req->mnt = NULL; +} + +int __connection_too_fast (tux_req_t *req) +{ + unsigned long curr_bw, delta, bytes; + + bytes = req->total_bytes + req->bytes_sent; + if (!bytes) + return 1; + + delta = jiffies - req->first_timestamp; + if (!delta) + delta++; + curr_bw = bytes * HZ / delta; + + if (curr_bw > tux_max_output_bandwidth) + return 2; + return 0; +} + +void unidle_req (tux_req_t *req) +{ + threadinfo_t *ti = req->ti; + + Dprintk("UNIDLE req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d)\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->status); + spin_lock_irq(&ti->work_lock); + if (req->magic != TUX_MAGIC) + TUX_BUG(); + if (!test_and_clear_bit(0, &req->idle_input)) { + Dprintk("unidling %p, wasnt idle!\n", req); + if (list_empty(&req->work)) + TUX_BUG(); + list_del(&req->work); + DEBUG_DEL_LIST(&req->work); + DEC_STAT(nr_work_pending); + } else { + del_keepalive_timer(req); + DEC_STAT(nr_idle_input_pending); + Dprintk("unidled %p.\n", req); + } + if (req->idle_input) + TUX_BUG(); + spin_unlock_irq(&ti->work_lock); +} + +#define GOTO_INCOMPLETE do { Dprintk("incomplete at %s:%d.\n", __FILE__, __LINE__); goto incomplete; } while (0) +#define GOTO_REDIRECT do { TDprintk("redirect at %s:%d.\n", __FILE__, __LINE__); goto redirect; } while (0) +#define GOTO_REDIRECT_NONIDLE do { TDprintk("redirect at %s:%d.\n", __FILE__, __LINE__); goto redirect_nonidle; } while (0) + +static int read_request (struct socket *sock, char *buf, int max_size) +{ + mm_segment_t oldmm; + struct kiocb iocb; + struct msghdr msg; + struct iovec iov; + + int len; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + msg.msg_iov->iov_base = buf; + msg.msg_iov->iov_len = max_size; + + oldmm = get_fs(); set_fs(KERNEL_DS); + +read_again: + init_sync_kiocb(&iocb, NULL); + len = sock->sk->sk_prot->recvmsg(&iocb, sock->sk, &msg, max_size, + MSG_DONTWAIT, MSG_PEEK, NULL); + if (-EIOCBQUEUED == len) + len = wait_on_sync_kiocb(&iocb); + + /* + * We must not get a signal inbetween + */ + if ((len == -EAGAIN) || (len == -ERESTARTSYS)) { + if (!signal_pending(current)) { + len = 0; + goto out; + } + flush_all_signals(); + goto read_again; + } +out: + set_fs(oldmm); + return len; +} + +/* + * We inline URG data so it's at the head of the normal receive queue. + */ +static int zap_urg_data (struct socket *sock) +{ + mm_segment_t oldmm; + struct msghdr msg; + struct iovec iov; + struct kiocb iocb; + int len; + char buf[10]; + + oldmm = get_fs(); set_fs(KERNEL_DS); + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + msg.msg_iov->iov_base = buf; + msg.msg_iov->iov_len = 2; + +read_again: + init_sync_kiocb(&iocb, NULL); + len = sock->sk->sk_prot->recvmsg(&iocb, sock->sk, &msg, 2, + MSG_DONTWAIT, 0, NULL); + if (-EIOCBQUEUED == len) + len = wait_on_sync_kiocb(&iocb); + Dprintk("recvmsg(MSG_OOB) returned %d.\n", len); + + /* + * We must not get a signal inbetween + */ + if ((len == -EAGAIN) || (len == -ERESTARTSYS)) { + if (!signal_pending(current)) { + len = 0; + goto out; + } + flush_all_signals(); + goto read_again; + } +out: + set_fs(oldmm); + + Dprintk("in out:.. and will return %d.!\n", len); + + return len; +} + +void trunc_headers (tux_req_t *req) +{ + struct sock *sk = req->sock->sk; + int len, addr_len = 0; + struct kiocb iocb; + + if (!req->parsed_len) + TUX_BUG(); +repeat_trunc: + init_sync_kiocb(&iocb, NULL); + len = sk->sk_prot->recvmsg(&iocb, sk, NULL, req->parsed_len, 1, MSG_TRUNC, &addr_len); + if (-EIOCBQUEUED == len) + len = wait_on_sync_kiocb(&iocb); + if ((len == -ERESTARTSYS) || (len == -EAGAIN)) { + flush_all_signals(); + goto repeat_trunc; + } + Dprintk("truncated (TRUNC) %d bytes at %p. (wanted: %d.)\n", len, __builtin_return_address(0), req->parsed_len); + + + + req->parsed_len = 0; +} + +void print_req (tux_req_t *req) +{ + struct sock *sk; + + printk("PRINT req %p <%p>, sock %p\n", + req, __builtin_return_address(0), req->sock); + printk("... idx: %d\n", req->atom_idx); + if (req->sock) { + sk = req->sock->sk; + printk("... sock %p, sk %p, sk->state: %d, sk->err: %d\n", req->sock, sk, sk->sk_state, sk->sk_err); + printk("... write_queue: %d, receive_queue: %d, error_queue: %d, keepalive: %d, status: %d\n", !skb_queue_empty(&sk->sk_write_queue), !skb_queue_empty(&sk->sk_receive_queue), !skb_queue_empty(&sk->sk_error_queue), req->keep_alive, req->status); + printk("...tp->send_head: %p\n", tcp_sk(sk)->send_head); + printk("...tp->snd_una: %08x\n", tcp_sk(sk)->snd_una); + printk("...tp->snd_nxt: %08x\n", tcp_sk(sk)->snd_nxt); + printk("...tp->packets_out: %08x\n", tcp_sk(sk)->packets_out); + } + printk("... meth:{%s}, uri:{%s}, query:{%s}, ver:{%s}\n", req->method_str ? req->method_str : "", req->uri_str ? req->uri_str : "", req->query_str ? req->query_str : "", req->version_str ? req->version_str : ""); + printk("... post_data:{%s}(%d).\n", req->post_data_str, req->post_data_len); + printk("... headers: {%s}\n", req->headers); +} +/* + * parse_request() reads all available TCP/IP data and prepares + * the request if the TUX request is complete. (we can get TUX + * requests in several packets.) Invalid requests are redirected + * to the secondary server. + */ + +void parse_request (tux_req_t *req, int cachemiss) +{ + int len, parsed_len; + struct sock *sk = req->sock->sk; + struct tcp_opt *tp = tcp_sk(sk); + int was_keepalive = req->keep_alive; + + if (req->magic != TUX_MAGIC) + TUX_BUG(); + + SET_TIMESTAMP(req->parse_timestamp); + + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + INC_STAT(nr_idle_input_pending); + spin_unlock_irq(&req->ti->work_lock); + + Dprintk("idled request %p.\n", req); + +restart: + + if (tp->urg_data && !(tp->urg_data & TCP_URG_READ)) { + len = zap_urg_data(req->sock); + if (tp->urg_data && !(tp->urg_data & TCP_URG_READ)) { + req->error = TUX_ERROR_CONN_CLOSE; + goto redirect_error; + } + } + + INC_STAT(input_slowpath); + + if (!req->headers) + req->headers = tux_kmalloc(tux_max_header_len); + + /* First, read the data */ + len = read_request(req->sock, (char *)req->headers, tux_max_header_len-1); + if (len < 0) { + req->error = TUX_ERROR_CONN_CLOSE; + goto redirect_error; + } + if (!len) + GOTO_INCOMPLETE; + + /* + * Make it a zero-delimited string to automatically get + * protection against various buffer overflow situations. + * Then pass it to the TUX application protocol stack. + */ + ((char *)req->headers)[len] = 0; + req->headers_len = len; + + parsed_len = req->proto->parse_message(req, len); + + /* + * Is the request fully read? (or is there any error) + */ + if (parsed_len < 0) + GOTO_REDIRECT; + if (!parsed_len) { + /* + * Push pending ACK which was delayed due to the + * pingpong optimization: + */ + if (was_keepalive) { + lock_sock(sk); + tp->ack.pingpong = 0; + tp->ack.pending |= TCP_ACK_PUSHED; + cleanup_rbuf(sk, 1); + release_sock(sk); + } + if (len >= tux_max_header_len-1) + GOTO_REDIRECT; + GOTO_INCOMPLETE; + } + unidle_req(req); + + tp->nonagle = 2; + + add_req_to_workqueue(req); + return; + +redirect: + TDprintk("req %p will be redirected!\n", req); + req_err(req); + +redirect_error: + unidle_req(req); + + if (len < 0) + req->parsed_len = 0; + else + req->parsed_len = len; + + INC_STAT(parse_static_redirect); + if (req->headers) + kfree(req->headers); + req->headers = NULL; + if (req->error) + zap_request(req, cachemiss); + return; + +incomplete: + if (req->error) + goto redirect_error; + if (tp->urg_data && !(tp->urg_data & TCP_URG_READ)) + goto restart; + + add_tux_atom(req, parse_request); + INC_STAT(parse_static_incomplete); + tux_push_req(req); +} + +int process_requests (threadinfo_t *ti, tux_req_t **user_req) +{ + struct list_head *head, *curr; + int count = 0; + tux_req_t *req; + + *user_req = NULL; + +restart_loop: + spin_lock_irq(&ti->work_lock); + head = &ti->work_pending; + curr = head->next; + + if (curr != head) { + int i; + + req = list_entry(curr, tux_req_t, work); + Dprintk("PROCESS req %p <%p>.\n", + req, __builtin_return_address(0)); + for (i = 0; i < req->atom_idx; i++) + Dprintk("... atom %d: %p\n", i, req->atoms[i]); + + if (req->ti != ti) + TUX_BUG(); + if (req->magic != TUX_MAGIC) + TUX_BUG(); + + if (list_empty(&req->work)) + TUX_BUG(); + list_del(curr); + DEBUG_DEL_LIST(&req->work); + spin_unlock_irq(&ti->work_lock); + + if (!req->atom_idx) { + if (req->usermode) { + *user_req = req; + return count; + } + /* + * idx == 0 requests are flushed automatically. + */ + flush_request(req, 0); + } else + tux_schedule_atom(req, 0); + count++; + goto restart_loop; + } + spin_unlock_irq(&ti->work_lock); + + return count; +} + +int tux_flush_workqueue (threadinfo_t *ti) +{ + struct list_head *head, *curr, *next; + tux_req_t *req; + int count = 0; + +restart: + spin_lock_irq(&ti->work_lock); + head = &ti->work_pending; + curr = head->next; + + if (curr != head) { + req = list_entry(curr, tux_req_t, work); + next = curr->next; + clear_bit(0, &req->idle_input); + clear_bit(0, &req->wait_output_space); + if (list_empty(&req->work)) + TUX_BUG(); + list_del(curr); + DEBUG_DEL_LIST(curr); + DEC_STAT(nr_input_pending); + spin_unlock_irq(&ti->work_lock); +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + req->in_file.f_pos = 0; + req->atom_idx = 0; + clear_keepalive(req); + req->status = -1; + if (req->usermode) { + req->usermode = 0; + req->private = 0; + } + flush_request(req, 0); + count++; + goto restart; + } + spin_unlock_irq(&ti->work_lock); + + return count; +} + +int print_all_requests (threadinfo_t *ti) +{ + struct list_head *head, *curr; + tux_req_t *req; + int count = 0; + + spin_lock_irq(&ti->work_lock); + head = &ti->all_requests; + curr = head->next; + + while (curr != head) { + req = list_entry(curr, tux_req_t, all); + curr = curr->next; + print_req(req); + count++; + } + spin_unlock_irq(&ti->work_lock); + + return count; +} + diff --git a/net/tux/logger.c b/net/tux/logger.c new file mode 100644 index 000000000..5ce80c17e --- /dev/null +++ b/net/tux/logger.c @@ -0,0 +1,855 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * Cleaned up logger output for Alpha. + * -- Phil Ezolt (Phillip.Ezolt@compaq.com) & Bill Carr (wcarr92@yahoo.com) + * + * logger.c: log requests finished by TUX. + */ + +#define __KERNEL_SYSCALLS__ +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; +static unsigned int log_head, log_tail; +static char * log_buffer = NULL; +static DECLARE_WAIT_QUEUE_HEAD(log_wait); +static DECLARE_WAIT_QUEUE_HEAD(log_full); +static int logger_pid = 0; + +/* + * High-speed TUX logging architecture: + * + * All fast threads share a common log-ringbuffer. (default size 1MB) + * Log entries are binary and are padded to be cacheline aligned, this + * ensures that there is no cache-pingpong between fast threads. + * + * The logger thread writes out pending log entries within 1 second + * (buffer-cache writes data out within 5 seconds). The logger thread + * gets activated once we have more than 25% of the log ringbuffer + * filled - or the 1 second log timeout expires. Fast threads block + * if if more than 95% of the ringbuffer is filled and unblock only + * if used logbuffer space drops below 90%. + * + * This architecture guarantees that 1) logging is reliable (no + * log entry is ever lost), 2) timely (touches disk within 6 seconds), + * 3) in the log-contention case the saturation behavior is still + * write-clustered, but 4) if the logger thread can keep up then + * the coupling is completely asynchron and parallel. + * + * The binary log format gives us about 50% saved IO/memory bandwith + * and 50% less on-disk used log space than the traditional W3C ASCII + * format. + * + * (We might switch to raw IO though to write the logfile.) + */ + +#define SOFT_LIMIT (LOG_LEN*25/100) +#define HARD_LIMIT (LOG_LEN*95/100) +#define HARD_RELAX_LIMIT (LOG_LEN*90/100) + +unsigned int tux_logentry_align_order = 5; + +#if SMP_CACHE_BYTES == 8 +# define TUX_LOGENTRY_ALIGN 3 +#else +#if SMP_CACHE_BYTES == 16 +# define TUX_LOGENTRY_ALIGN 4 +#else +#if SMP_CACHE_BYTES == 32 +# define TUX_LOGENTRY_ALIGN 5 +#else +#if SMP_CACHE_BYTES == 64 +# define TUX_LOGENTRY_ALIGN 6 +#else +#if SMP_CACHE_BYTES == 128 +# define TUX_LOGENTRY_ALIGN 7 +#else +#if SMP_CACHE_BYTES == 256 +# define TUX_LOGENTRY_ALIGN 8 +#else +#error Add entry! +#endif +#endif +#endif +#endif +#endif +#endif + +#define ROUND_UP(x) (((((x)-1) >> TUX_LOGENTRY_ALIGN) + 1) \ + << TUX_LOGENTRY_ALIGN) + +static void __throttle_logging (void) +{ + DECLARE_WAITQUEUE(wait, current); + int pending; + + add_wait_queue(&log_full, &wait); + for (;;) { + static unsigned long last_warning = 0; + + if (jiffies - last_warning > 10*HZ) { + last_warning = jiffies; + printk(KERN_NOTICE "TUX: log buffer overflow, have to throttle TUX thread!\n"); + } + + current->state = TASK_INTERRUPTIBLE; + + spin_lock(&log_lock); + pending = log_head-log_tail; + spin_unlock(&log_lock); + + if ((pending % LOG_LEN) < HARD_LIMIT) + break; + + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&log_full, &wait); +} + +#if CONFIG_TUX_DEBUG +#define CHECK_LOGPTR(ptr) \ +do { \ + if ((ptr < log_buffer) || (ptr > log_buffer + LOG_LEN)) { \ + printk(KERN_ERR "TUX: ouch: log ptr %p > %p + %ld!\n", \ + ptr, log_buffer, LOG_LEN); \ + TUX_BUG(); \ + } \ +} while (0) +#else +#define CHECK_LOGPTR(ptr) do { } while (0) +#endif + +void __log_request (tux_req_t *req) +{ + char *str, *next; + const char *uri_str; + unsigned int inc, len, uri_len, pending, next_head, def_vhost_len = 0; + unsigned long flags; + + if (req->proto->pre_log) + req->proto->pre_log(req); + /* + * Log the reply status (success, or type of failure) + */ + if (!tux_log_incomplete && (!req->status || (req->bytes_sent == -1))) { + + Dprintk("not logging req %p: {%s} [%d/%d]\n", req, req->uri_str, req->status, req->bytes_sent); + return; + } + Dprintk("uri: {%s} [%d]\n", req->uri_str, req->uri_len); + +#define NO_URI "" + if (req->uri_len) { + uri_len = req->uri_len; + uri_str = req->uri_str; + } else { + uri_str = NO_URI; + uri_len = sizeof(NO_URI)-1; + } + len = uri_len + 1; + + if (req->virtual) { + if (req->host_len) + len += req->host_len; + else { + def_vhost_len = strlen(tux_default_vhost); + len += def_vhost_len; + } + } + + Dprintk("method_str: {%s} [%d]\n", req->method_str, req->method_len); + len += req->method_len + 1; + + Dprintk("version_str: {%s} [%d]\n", req->version_str, req->version_len); + len += req->version_len + 1; + +#if CONFIG_TUX_EXTENDED_LOG + Dprintk("user_agent_str: {%s} [%d]\n", req->user_agent_str, req->user_agent_len); + len += req->user_agent_len + 1; +#endif + if (tux_referer_logging) { + Dprintk("referer_str: {%s} [%d]\n", req->referer_str, req->referer_len); + len += req->referer_len; + } + len++; + + inc = 5*sizeof(u32) + len; +#if CONFIG_TUX_EXTENDED_LOG + inc += 7*sizeof(u32); +#endif + + spin_lock_irqsave(&log_lock, flags); + + next_head = ROUND_UP(log_head + inc); + + if (next_head < LOG_LEN) { + str = log_buffer + log_head; + if (str > log_buffer + LOG_LEN) + TUX_BUG(); + log_head = next_head; + } else { + if (log_head < LOG_LEN) + memset(log_buffer+log_head, 0, LOG_LEN-log_head); + str = log_buffer; + log_head = ROUND_UP(inc); + } + + if (str < log_buffer || str+inc >= log_buffer+LOG_LEN) + TUX_BUG(); + + /* + * Log record signature - this makes finding the next entry + * easier (since record length is variable), and makes the + * binary logfile more robust against potential data corruption + * and other damage. The signature also servers as a log format + * version identifier. + */ +#if CONFIG_TUX_EXTENDED_LOG + *(u32 *)str = 0x2223beef; +#else + *(u32 *)str = 0x1112beef; +#endif + str += sizeof(u32); + CHECK_LOGPTR(str); + + *(u32 *)str = 0; + /* + * Log the client IP address: + */ + if (tux_ip_logging) + *(u32 *)str = req->client_addr; + str += sizeof(u32); + CHECK_LOGPTR(str); + +#if CONFIG_TUX_EXTENDED_LOG + /* + * Log the client port number: + */ + *(u32 *)str = 0; + if (tux_ip_logging) + *(u32 *)str = req->client_port; + str += sizeof(u32); + CHECK_LOGPTR(str); +#endif + + /* + * Log the request timestamp, in units of 'seconds since 1970'. + */ + *(u32 *)str = CURRENT_TIME.tv_sec; + str += sizeof(u32); + CHECK_LOGPTR(str); + +#if CONFIG_TUX_EXTENDED_LOG + *(u32 *)str = req->accept_timestamp; str += sizeof(u32); + *(u32 *)str = req->parse_timestamp; str += sizeof(u32); + *(u32 *)str = req->output_timestamp; str += sizeof(u32); + *(u32 *)str = req->flush_timestamp; str += sizeof(u32); + *(u32 *)str = req->had_cachemiss; str += sizeof(u32); + *(u32 *)str = req->keep_alive; str += sizeof(u32); +#endif + /* + * Log the requested file size (in fact, log actual bytes sent.) + */ + *(u32 *)str = req->bytes_sent; + str += sizeof(u32); + CHECK_LOGPTR(str); + + *(u32 *)str = req->status; + str += sizeof(u32); + CHECK_LOGPTR(str); + + /* + * Zero-terminated method, (base) URI, query and version string. + */ + if (req->method_len) { + memcpy(str, req->method_str, req->method_len); + str += req->method_len; + CHECK_LOGPTR(str); + } + *str++ = 0; + + if (req->virtual) { + if (req->host_len) { + memcpy(str, req->host, req->host_len); + str += req->host_len; + } else { + memcpy(str, tux_default_vhost, def_vhost_len); + str += def_vhost_len; + } + CHECK_LOGPTR(str); + } + + memcpy(str, uri_str, uri_len); + str += uri_len; + *str++ = 0; + + CHECK_LOGPTR(str); + + if (req->version_len) { + memcpy(str, req->version_str, req->version_len); + str += req->version_len; + CHECK_LOGPTR(str); + } + *str++ = 0; +#if CONFIG_TUX_EXTENDED_LOG + if (req->user_agent_len) { + memcpy(str, req->user_agent_str, req->user_agent_len); + str += req->user_agent_len; + CHECK_LOGPTR(str); + } + *str++ = 0; +#endif + CHECK_LOGPTR(str); + + if (tux_referer_logging && req->referer_len) { + memcpy(str, req->referer_str, req->referer_len); + str += req->referer_len; + CHECK_LOGPTR(str); + } + *str++ = 0; + CHECK_LOGPTR(str); + /* + * pad with spaces to next cacheline, with an ending newline. + * (not needed for the user-space log utility, but results in + * a more readable binary log file, and reduces the amount + * of cache pingpong.) + */ + next = (char *)ROUND_UP((unsigned long)str); + + CHECK_LOGPTR(next); + len = next-str; + memset(str, ' ', len); + + pending = (log_head-log_tail) % LOG_LEN; + spin_unlock_irqrestore(&log_lock, flags); + + if (pending >= SOFT_LIMIT) + wake_up(&log_wait); + + if (pending >= HARD_LIMIT) + __throttle_logging(); +} + +void tux_push_pending (struct sock *sk) +{ + struct tcp_opt *tp = tcp_sk(sk); + + Dprintk("pushing pending frames on sock %p.\n", sk); + lock_sock(sk); + if ((sk->sk_state == TCP_ESTABLISHED) && !sk->sk_err) { + tp->ack.pingpong = tux_ack_pingpong; + tp->nonagle = 1; + __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 0), TCP_NAGLE_OFF); + } + release_sock(sk); +} + +inline void tux_push_req (tux_req_t *req) +{ + if (req->sock) + tux_push_pending(req->sock->sk); + if (req->data_sock) + tux_push_pending(req->data_sock->sk); +} + +void __put_data_sock (tux_req_t *req) +{ + unlink_tux_data_socket(req); + if (req->data_sock->file) + fput(req->data_sock->file); + else + sock_release(req->data_sock); + req->data_sock = NULL; +} + +/* open-coded sys_close */ + +long tux_close(unsigned int fd) +{ + struct file * filp; + struct files_struct *files = current->files; + + spin_lock(&files->file_lock); + if (fd >= files->max_fds) + goto out_unlock; + filp = files->fd[fd]; + if (!filp) + goto out_unlock; + files->fd[fd] = NULL; + FD_CLR(fd, files->close_on_exec); + /* __put_unused_fd(files, fd); */ + __FD_CLR(fd, files->open_fds); + if (fd < files->next_fd) + files->next_fd = fd; + spin_unlock(&files->file_lock); + return filp_close(filp, files); + +out_unlock: + spin_unlock(&files->file_lock); + return -EBADF; +} + +void flush_request (tux_req_t *req, int cachemiss) +{ + struct socket *sock; + struct sock *sk; + int keep_alive; + + if (cachemiss) + TUX_BUG(); + __set_task_state(current, TASK_RUNNING); + + if (req->magic != TUX_MAGIC) + TUX_BUG(); + if (req->ti->thread != current) + TUX_BUG(); +#if CONFIG_TUX_DEBUG + if (req->bytes_expected && (req->bytes_sent != req->bytes_expected)) { + printk("hm, bytes_expected: %d != bytes_sent: %d!\n", + req->bytes_expected, req->bytes_sent); + TUX_BUG(); + } +#endif + SET_TIMESTAMP(req->flush_timestamp); + + log_request(req); + sock = req->sock; + sk = NULL; + if (sock) + sk = sock->sk; + Dprintk("FLUSHING req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d)\n", req, __builtin_return_address(0), sock, sk, req->keep_alive, req->status); + if (req->in_file.f_pos) + /*TUX_BUG()*/; + release_req_dentry(req); + req->private = 0; + + if (req->docroot_dentry) { + dput(req->docroot_dentry); + req->docroot_dentry = NULL; + if (!req->docroot_mnt) + TUX_BUG(); + } + if (req->docroot_mnt) { + mntput(req->docroot_mnt); + req->docroot_mnt = NULL; + } + + req->offset_start = 0; + req->offset_end = 0; + req->output_len = 0; + req->total_file_len = 0; + req->lendigits = 0; + req->mtime = 0; + req->etaglen = 0; + req->etag[0] = 0; + req->ftp_command = 0; + + if (req->postponed) + TUX_BUG(); + if (test_bit(0, &req->idle_input)) + TUX_BUG(); + if (test_bit(0, &req->wait_output_space)) + TUX_BUG(); + if (req->parsed_len) + trunc_headers(req); + if (req->parsed_len) + TUX_BUG(); + req->attr = NULL; + req->usermode = 0; + req->usermodule_idx = 0; + req->atom_idx = 0; + if (req->module_dentry) { + dput(req->module_dentry); + req->module_dentry = NULL; + } + if (req->headers) + kfree(req->headers); + req->headers = NULL; + req->headers_len = 0; + + req->method = METHOD_NONE; + req->method_len = 0; + req->method_str = NULL; + req->version = 0; + req->version_str = NULL; + req->version_len = 0; + + req->uri_str = NULL; + req->uri_len = 0; + + req->objectname[0] = 0; + req->objectname_len = 0; + + req->query_str = NULL; + req->query_len = 0; + + req->cookies_str = NULL; + req->cookies_len = 0; + req->parse_cookies = 0; + + req->contentlen_str = NULL; + req->contentlen_len = 0; + req->content_len = 0; + + req->user_agent_str = NULL; + req->user_agent_len = 0; + + req->may_send_gzip = 0; + req->content_gzipped = 0; + + req->content_type_str = NULL; + req->content_type_len = 0; + + req->accept_str = NULL; + req->accept_len = 0; + + req->accept_charset_str = NULL; + req->accept_charset_len = 0; + + req->accept_encoding_str = NULL; + req->accept_encoding_len = 0; + + req->accept_language_str = NULL; + req->accept_language_len = 0; + + req->cache_control_str = NULL; + req->cache_control_len = 0; + + req->if_modified_since_str = NULL; + req->if_modified_since_len = 0; + + req->if_none_match_str = NULL; + req->if_none_match_len = 0; + + req->if_range_str = NULL; + req->if_range_len = 0; + + req->negotiate_str = NULL; + req->negotiate_len = 0; + + req->pragma_str = NULL; + req->pragma_len = 0; + + req->referer_str = NULL; + req->referer_len = 0; + + req->post_data_str = NULL; + req->post_data_len = 0; + + SET_TIMESTAMP(req->accept_timestamp); +#if CONFIG_TUX_EXTENDED_LOG + req->parse_timestamp = 0; + req->output_timestamp = 0; + req->flush_timestamp = 0; +#endif + req->status = 0; + + req->total_bytes += req->bytes_sent; + req->bytes_sent = 0; +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + req->body_len = 0; + keep_alive = req->keep_alive; + clear_keepalive(req); + req->had_cachemiss = 0; + // first_timestamp and total_bytes is kept! + req->event = 0; + req->lookup_dir = 0; + req->lookup_404 = 0; + + req->error = 0; + req->user_error = 0; + + if (req->abuf.page) + __free_page(req->abuf.page); + memset(&req->abuf, 0, sizeof(req->abuf)); + + if (sk && keep_alive) { + add_tux_atom(req, parse_request); + if (skb_queue_empty(&sk->sk_receive_queue)) { + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + /* + * Avoid the race with the event callback: + */ + if (skb_queue_empty(&sk->sk_receive_queue) || + !test_and_clear_bit(0, &req->idle_input)) { + INC_STAT(nr_idle_input_pending); + spin_unlock_irq(&req->ti->work_lock); + tux_push_req(req); + goto out; + } + del_keepalive_timer(req); + spin_unlock_irq(&req->ti->work_lock); + } + Dprintk("KEEPALIVE PENDING req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d)\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->status); + add_req_to_workqueue(req); + INC_STAT(nr_keepalive_optimized); + goto out; + } + + del_timer_sync(&req->keepalive_timer); + del_timer_sync(&req->output_timer); + + if (timer_pending(&req->keepalive_timer)) + TUX_BUG(); + if (timer_pending(&req->output_timer)) + TUX_BUG(); + if (!list_empty(&req->lru)) + TUX_BUG(); + req->nr_keepalives = 0; + req->client_addr = 0; + req->client_port = 0; + req->virtual = 0; + req->ftp_offset_start = 0; + + req->host[0] = 0; + req->host_len = 0; + + if (req->cwd_dentry) { + dput(req->cwd_dentry); + req->cwd_dentry = NULL; + if (!req->cwd_mnt) + TUX_BUG(); + } + if (req->cwd_mnt) { + mntput(req->cwd_mnt); + req->cwd_mnt = NULL; + } + put_data_sock(req); + req->prev_pos = 0; + req->curroff = 0; + req->total = 0; + if (req->dirp0) { + kfree(req->dirp0); + req->dirp0 = NULL; + } + + if (sk) + unlink_tux_socket(req); + req->sock = NULL; + /* + * Close potential user-space file descriptors. + */ + { + int fd = req->fd, ret; + + if (fd != -1) { + req->fd = -1; + ret = tux_close(fd); + if (ret) + TUX_BUG(); + } else + if (sock) + sock_release(sock); + } + kfree_req(req); +out: + ; +} + +static int warn_once = 1; + +static unsigned int writeout_log (void) +{ + unsigned int len, pending, next_log_tail; + mm_segment_t oldmm = get_fs(); + struct file *log_filp; + char * str; + unsigned int ret; + + if (tux_logging) + Dprintk("TUX logger: opening log file {%s}.\n", tux_logfile); + log_filp = tux_open_file(tux_logfile, O_CREAT|O_APPEND|O_WRONLY|O_LARGEFILE); + if (!log_filp) { + if (warn_once) { + printk(KERN_ERR "TUX: could not open log file {%s}!\n", + tux_logfile); + warn_once = 0; + } + __set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + return 0; + } + spin_lock(&log_lock); + str = log_buffer + log_tail; + if (log_head < log_tail) { + len = LOG_LEN-log_tail; + next_log_tail = 0; + } else { + len = log_head-log_tail; + next_log_tail = log_head; + } + if (!len) + goto out; + spin_unlock(&log_lock); + + set_fs(KERNEL_DS); + ret = log_filp->f_op->write(log_filp, str, len, &log_filp->f_pos); + set_fs(oldmm); + + if (len != ret) { + if (ret == -ENOSPC) { + printk(KERN_ERR "TUX: trying to write TUX logfile %s, but filesystem is full! Lost %d bytes of log data.\n", tux_logfile, len); + } else { + printk(KERN_ERR "TUX: log write %d != %d.\n", ret, len); + printk(KERN_ERR "TUX: log_filp: %p, str: %p, len: %d str[len-1]: %d.\n", log_filp, str, len, str[len-1]); + } + goto out_lock; + } + + /* + * Sync log data to disk: + */ + if (log_filp->f_op && log_filp->f_op->fsync) { + down(&log_filp->f_dentry->d_inode->i_sem); + log_filp->f_op->fsync(log_filp, log_filp->f_dentry, 1); + up(&log_filp->f_dentry->d_inode->i_sem); + } + + /* + * Reduce the cache footprint of the logger file - it's + * typically write-once. + */ + invalidate_inode_pages(log_filp->f_dentry->d_inode->i_mapping); + +out_lock: + spin_lock(&log_lock); +out: + log_tail = next_log_tail; + pending = (log_head-log_tail) % LOG_LEN; + spin_unlock(&log_lock); + + if (pending < HARD_LIMIT) + wake_up(&log_full); + + fput(log_filp); + return pending; +} + +static DECLARE_WAIT_QUEUE_HEAD(stop_logger_wait); +static int stop_logger = 0; + +static int logger_thread (void *data) +{ + DECLARE_WAITQUEUE(wait, current); + mm_segment_t oldmm; + + daemonize("TUX logger"); + + oldmm = get_fs(); + set_fs(KERNEL_DS); + printk(KERN_NOTICE "TUX: logger thread started.\n"); +#if CONFIG_SMP + { + cpumask_t log_mask, map; + + mask_to_cpumask(log_cpu_mask, &log_mask); + cpus_and(map, cpu_online_map, log_mask); + if(!(cpus_empty(map))) + set_cpus_allowed(current, map); + + } +#endif + + + spin_lock_irq(¤t->sighand->siglock); + siginitsetinv(¤t->blocked, 0); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (log_buffer) + TUX_BUG(); + log_buffer = vmalloc(LOG_LEN); + memset(log_buffer, 0, LOG_LEN); + log_head = log_tail = 0; + + current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + + add_wait_queue(&log_wait, &wait); + for (;;) { + if (tux_logging) + Dprintk("logger does writeout - stop:%d.\n", stop_logger); + + while (writeout_log() >= SOFT_LIMIT) { + if (stop_logger) + break; + } + if (stop_logger) + break; + /* nothing */; + + if (tux_logging) + Dprintk("logger does sleep - stop:%d.\n", stop_logger); + __set_current_state(TASK_INTERRUPTIBLE); + if (log_head != log_tail) { + __set_current_state(TASK_RUNNING); + continue; + } + schedule_timeout(HZ); + if (tux_logging) + Dprintk("logger back from sleep - stop:%d.\n", stop_logger); + if (signal_pending(current)) + flush_all_signals(); + } + remove_wait_queue(&log_wait, &wait); + + vfree(log_buffer); + log_buffer = NULL; + stop_logger = 0; + wake_up(&stop_logger_wait); + + set_fs(oldmm); + + return 0; +} + +void start_log_thread (void) +{ + warn_once = 1; + + logger_pid = kernel_thread(logger_thread, NULL, 0); + if (logger_pid < 0) + TUX_BUG(); +} + +void stop_log_thread (void) +{ + DECLARE_WAITQUEUE(wait, current); + + Dprintk("stopping logger thread %d ...\n", logger_pid); + + __set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&stop_logger_wait, &wait); + stop_logger = 1; + wake_up(&log_wait); + schedule(); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&stop_logger_wait, &wait); + + Dprintk("logger thread stopped!\n"); +} diff --git a/net/tux/main.c b/net/tux/main.c new file mode 100644 index 000000000..e33241fec --- /dev/null +++ b/net/tux/main.c @@ -0,0 +1,1413 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * main.c: main management and initialization routines + */ + +#define __KERNEL_SYSCALLS__ +#define __KERNEL_SYSCALLS_NO_ERRNO__ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +/* + * Threads information. + */ +unsigned int nr_tux_threads; +static atomic_t nr_tux_threads_running = ATOMIC_INIT(0); +static int stop_threads = 0; + +threadinfo_t threadinfo[CONFIG_TUX_NUMTHREADS]; + +static void flush_all_requests (threadinfo_t *ti); + +void flush_all_signals (void) +{ + spin_lock_irq(¤t->sighand->siglock); + flush_signals(current); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); +} + +int nr_requests_used (void) +{ + unsigned int i, nr = 0; + + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + nr += ti->nr_requests - ti->nr_free_requests; + } + + return nr; +} + +static inline int accept_pending (threadinfo_t *ti) +{ + int j; + + for (j = 0; j < CONFIG_TUX_NUMSOCKETS; j++) { + if (!ti->listen[j].proto) + break; + if (!ti->listen[j].sock) + break; + if (tcp_sk(ti->listen[j].sock->sk)->accept_queue) + return 1; + } + return 0; +} + +static inline int requests_pending (threadinfo_t *ti) +{ + if (!list_empty(&ti->work_pending)) + return 1; + return 0; +} + +static int event_loop (threadinfo_t *ti) +{ + tux_req_t *req; + int work_done; + +repeat_accept: + if (ti->thread != current) + TUX_BUG(); + + /* + * Any (relevant) event on the socket will change this + * thread to TASK_RUNNING because we add it to both + * the main listening and the connection request socket + * waitqueues. Thus we can do 'lazy checking' of work + * to be done and schedule away only if the thread is + * still TASK_INTERRUPTIBLE. This makes TUX fully + * event driven. + */ + set_task_state(current, TASK_INTERRUPTIBLE); + current->flags |= PF_MEMALLOC; + work_done = 0; + if (accept_pending(ti)) + work_done = accept_requests(ti); + + if (requests_pending(ti)) { + work_done = process_requests(ti, &req); + if (req) + goto handle_userspace_req; + } + + /* + * Be nice to other processes: + */ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) { + __set_task_state(current, TASK_RUNNING); + schedule(); + goto repeat_accept; + } + + if (ti->userspace_req) + TUX_BUG(); + if (unlikely(stop_threads)) + goto handle_stop; + + /* Any signals? */ + if (unlikely(signal_pending(current))) + goto handle_signal; + + if (work_done) + goto repeat_accept; + /* + * Any socket event either on the listen socket + * or on the request sockets will wake us up: + */ + if ((current->state != TASK_RUNNING) && + !requests_pending(ti) && !accept_pending(ti)) { + Dprintk("fast thread: no work to be done, sleeping.\n"); + schedule(); + Dprintk("fast thread: back from sleep!\n"); + goto repeat_accept; + } + goto repeat_accept; + +handle_userspace_req: + if (req->attr) + TUX_BUG(); + switch_docroot(req); + ti->userspace_req = req; + __set_task_state(current, TASK_RUNNING); + return TUX_RETURN_USERSPACE_REQUEST; + +handle_signal: + __set_task_state(current, TASK_RUNNING); + return TUX_RETURN_SIGNAL; + +handle_stop: + __set_task_state(current, TASK_RUNNING); + return TUX_RETURN_EXIT; +} + +static int init_queues (int nr_tux_threads) +{ + int i; + + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + + INIT_LIST_HEAD(&ti->all_requests); + + ti->free_requests_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&ti->free_requests); + + ti->work_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&ti->work_pending); + INIT_LIST_HEAD(&ti->lru); + + } + return 0; +} + +int tux_chroot (char *dir) +{ + kernel_cap_t saved_cap = current->cap_effective; + mm_segment_t oldmm; + int err; + + /* Allow chroot dir to be in kernel space. */ + oldmm = get_fs(); set_fs(KERNEL_DS); + set_fs(KERNEL_DS); + cap_raise (current->cap_effective, CAP_SYS_CHROOT); + + err = chroot(dir); + if (!err) + chdir("/"); + + current->cap_effective = saved_cap; + set_fs(oldmm); + + return err; +} + +/* + * Right now this is not fully SMP-safe against multiple TUX + * managers. It's just a rudimentary protection against typical + * mistakes. + */ +static int initialized = 0; + +#define MAX_DOCROOTLEN 500 + +static int lookup_docroot(struct nameidata *docroot, const char *name) +{ + int err; + + docroot->mnt = mntget(current->fs->rootmnt); + docroot->dentry = dget(current->fs->root); + docroot->last.len = 0; + docroot->flags = LOOKUP_FOLLOW; + + err = path_walk(name, docroot); + if (err) { + mntput(docroot->mnt); + docroot->mnt = NULL; + return err; + } + return 0; +} + +static int user_req_startup (void) +{ + char name[MAX_DOCROOTLEN]; + struct nameidata *docroot; + unsigned int i; + int err; + + if (initialized) + return -EINVAL; + initialized = 1; + + /* + * Look up the HTTP and FTP document root. + * (typically they are shared, but can be + * different directories.) + */ + docroot = &tux_proto_http.main_docroot; + if (docroot->mnt) + TUX_BUG(); + strcpy(name, tux_common_docroot); + strcat(name, tux_http_subdocroot); + + err = lookup_docroot(docroot, name); + if (err) { + initialized = 0; + printk(KERN_ERR "TUX: could not look up HTTP documentroot: \"%s\"\n", name); + return err; + } + + docroot = &tux_proto_ftp.main_docroot; + if (docroot->mnt) + TUX_BUG(); + strcpy(name, tux_common_docroot); + strcat(name, tux_ftp_subdocroot); + + err = lookup_docroot(docroot, name); + if (err) { +abort: + docroot = &tux_proto_http.main_docroot; + path_release(docroot); + memset(docroot, 0, sizeof(*docroot)); + initialized = 0; + printk(KERN_ERR "TUX: could not look up FTP documentroot: \"%s\"\n", name); + return err; + } + + /* + * Start up the logger thread. (which opens the logfile) + */ + start_log_thread(); + + nr_tux_threads = tux_threads; + if (nr_tux_threads < 1) + nr_tux_threads = 1; + if (nr_tux_threads > CONFIG_TUX_NUMTHREADS) + nr_tux_threads = CONFIG_TUX_NUMTHREADS; + tux_threads = nr_tux_threads; + + /* + * Set up per-thread work-queues: + */ + memset(threadinfo, 0, CONFIG_TUX_NUMTHREADS*sizeof(threadinfo_t)); + init_queues(nr_tux_threads); + + /* + * Prepare the worker thread structures. + */ + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + ti->cpu = i; + ti->gzip_state.workspace = + vmalloc(zlib_deflate_workspacesize()); + if (!ti->gzip_state.workspace || + (zlib_deflateInit(&ti->gzip_state, 6) != Z_OK)) { + stop_log_thread(); + goto abort; + } + init_MUTEX(&ti->gzip_sem); + } + + __module_get(tux_module); + + return 0; +} + +static DECLARE_WAIT_QUEUE_HEAD(wait_stop); +static DECLARE_WAIT_QUEUE_HEAD(thread_stopped); + +static int user_req_shutdown (void) +{ + DECLARE_WAITQUEUE(wait, current); + struct nameidata *docroot; + int i, err = -EINVAL; + + lock_kernel(); + if (!initialized) { + Dprintk("TUX is not up - cannot shut down.\n"); + goto err; + } + initialized = 0; + stop_threads = 1; + add_wait_queue(&thread_stopped, &wait); + +wait_more: + /* + * Wake up all the worker threads so they notice + * that we are being stopped. + */ + set_task_state(current, TASK_UNINTERRUPTIBLE); + if (atomic_read(&nr_tux_threads_running)) { + Dprintk("TUX: shutdown, %d threads still running.\n", + atomic_read(&nr_tux_threads_running)); + wake_up(&wait_stop); + schedule(); + goto wait_more; + } + set_task_state(current, TASK_RUNNING); + stop_threads = 0; + remove_wait_queue(&thread_stopped, &wait); + + if (nr_async_io_pending()) + TUX_BUG(); + + stop_log_thread(); + + docroot = &tux_proto_http.main_docroot; + path_release(docroot); + memset(docroot, 0, sizeof(*docroot)); + docroot = &tux_proto_ftp.main_docroot; + path_release(docroot); + memset(docroot, 0, sizeof(*docroot)); + err = 0; + + flush_dentry_attributes(); + free_mimetypes(); + unregister_all_tuxmodules(); + + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + vfree(ti->gzip_state.workspace); + } + + module_put(tux_module); + +err: + unlock_kernel(); + return err; +} + +void drop_permissions (void) +{ + /* + * Userspace drops privileges already, and group + * membership is important to keep. + */ + /* Give the new process no privileges.. */ + current->uid = current->euid = + current->suid = current->fsuid = tux_cgi_uid; + current->gid = current->egid = + current->sgid = current->fsgid = tux_cgi_gid; + cap_clear(current->cap_permitted); + cap_clear(current->cap_inheritable); + cap_clear(current->cap_effective); +} + +static int wait_for_others (void) +{ + threadinfo_t *ti; + unsigned int cpu; + +repeat: + if (signal_pending(current)) + return -1; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + + for (cpu = 0; cpu < nr_tux_threads; cpu++) { + ti = threadinfo + cpu; + if (ti->listen_error) + return -1; + if (!ti->started) + goto repeat; + } + /* ok, all threads have started up. */ + return 0; +} + +static void zap_listen_sockets (threadinfo_t *ti) +{ + struct socket *sock; + int i; + + for (i = 0; i < CONFIG_TUX_NUMSOCKETS; i++) { + if (!ti->listen[i].proto) + break; + sock = ti->listen[i].sock; + if (!ti->listen[i].cloned && sock) { + while (waitqueue_active(sock->sk->sk_sleep)) + yield(); + sock_release(sock); + } + ti->listen[i].sock = NULL; + ti->listen[i].proto = NULL; + ti->listen[i].cloned = 0; + } +} + +static DECLARE_MUTEX(serialize_startup); + +static int user_req_start_thread (threadinfo_t *ti) +{ + unsigned int err, cpu, i, j, k; + struct k_sigaction *ka; + + cpu = ti->cpu; +#if CONFIG_SMP + { + unsigned int mask; + cpumask_t cpu_mask, map; + + mask = 1 << ((cpu + tux_cpu_offset) % num_online_cpus()); + + mask_to_cpumask(mask, &cpu_mask); + cpus_and(map, cpu_mask, cpu_online_map); + if(!(cpus_empty(map))) + set_cpus_allowed(current, map); + } +#endif + ti->thread = current; + atomic_inc(&nr_tux_threads_running); + + err = start_cachemiss_threads(ti); + if (err) + goto out; + + init_waitqueue_entry(&ti->stop, current); + for (j = 0; j < CONFIG_TUX_NUMSOCKETS; j++) + init_waitqueue_entry(ti->wait_event + j, current); + + ka = current->sighand->action + SIGCHLD-1; + ka->sa.sa_handler = SIG_IGN; + + /* Block all signals except SIGKILL, SIGSTOP, SIGHUP and SIGCHLD */ + spin_lock_irq(¤t->sighand->siglock); + siginitsetinv(¤t->blocked, sigmask(SIGKILL) | + sigmask(SIGSTOP)| sigmask(SIGHUP) | sigmask(SIGCHLD)); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (!tux_listen[cpu][0].proto) { + printk(KERN_ERR "no listen socket specified for TUX thread %d, in /proc/net/tux/%d/listen/, aborting.\n", cpu, cpu); + goto error; + } + + /* + * Serialize startup so that listen sockets can be + * created race-free. + */ + down(&serialize_startup); + + Dprintk("thread %d initializing sockets.\n", cpu); + + for (k = 0; k < CONFIG_TUX_NUMSOCKETS; k++) { + tux_socket_t *e1, *e2; + + e1 = tux_listen[cpu] + k; + if (!e1->proto) + break; + for (i = 0; i < CONFIG_TUX_NUMTHREADS; i++) { + if (i == cpu) + continue; + for (j = 0; j < CONFIG_TUX_NUMSOCKETS; j++) { + e2 = tux_listen[i] + j; + if (!e2->proto) + continue; + if ((e1->ip == e2->ip) && (e1->port == e2->port) && (e1->proto == e2->proto) && threadinfo[i].listen[j].proto) { + ti->listen[k] = threadinfo[i].listen[j]; + ti->listen[k].cloned = 1; + Dprintk("cloned socket %d from thread %d's socket %d.\n", k, i, j); + goto next_socket; + } + } + } + + ti->listen[k].sock = start_listening(tux_listen[cpu] + k, cpu); + if (!ti->listen[k].sock) + goto error_unlock; + ti->listen[k].cloned = 0; + ti->listen[k].proto = tux_listen[cpu][k].proto; + Dprintk("thread %d got sock %p (%d), proto %s.\n", cpu, ti->listen[k].sock, k, ti->listen[k].proto->name); +next_socket: + ; + } + Dprintk("thread %d done initializing sockets.\n", cpu); + up(&serialize_startup); + + if (wait_for_others()) + goto error_nomsg; + + if (!ti->listen[0].proto) { + printk("hm, socket 0 has no protocol.\n"); + goto error; + } + + add_wait_queue(&wait_stop, &ti->stop); + for (j = 0; j < CONFIG_TUX_NUMSOCKETS; j++) + if (ti->listen[j].proto) + add_wait_queue_exclusive(ti->listen[j].sock->sk->sk_sleep, + ti->wait_event + j); + drop_permissions(); + + __module_get(tux_module); + return 0; + +error_unlock: + up(&serialize_startup); +error: + printk(KERN_NOTICE "TUX: could not start worker thread %d.\n", ti->cpu); + +error_nomsg: + ti->listen_error = 1; + ti->started = 0; + + zap_listen_sockets(ti); + flush_all_requests(ti); + stop_cachemiss_threads(ti); + + err = -EINVAL; + +out: + /* + * Last thread close the door: + */ + if (atomic_dec_and_test(&nr_tux_threads_running)) + user_req_shutdown(); + + return -err; +} + +static int flush_idleinput (threadinfo_t * ti) +{ + struct list_head *head, *tmp; + tux_req_t *req; + int count = 0; + + head = &ti->all_requests; + tmp = head->next; + + while (tmp != head) { + req = list_entry(tmp, tux_req_t, all); + tmp = tmp->next; + if (test_bit(0, &req->idle_input)) { + idle_event(req); + count++; + } + } + return count; +} + +static int flush_waitoutput (threadinfo_t * ti) +{ + struct list_head *head, *tmp; + tux_req_t *req; + int count = 0; + + head = &ti->all_requests; + tmp = head->next; + + while (tmp != head) { + req = list_entry(tmp, tux_req_t, all); + tmp = tmp->next; + if (test_bit(0, &req->wait_output_space)) { + output_space_event(req); + count++; + } + } + return count; +} + +static void flush_all_requests (threadinfo_t *ti) +{ + for (;;) { + int count; + + count = flush_idleinput(ti); + count += flush_waitoutput(ti); + count += tux_flush_workqueue(ti); + count += flush_freequeue(ti); + if (!ti->nr_requests) + break; + /* + * Go through again if we advanced: + */ + if (count) + continue; + Dprintk("flush_all_requests: %d requests still waiting.\n", ti->nr_requests); +#if TUX_DEBUG + count = print_all_requests(ti); + Dprintk("flush_all_requests: printed %d requests.\n", count); +#endif + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); + } +} + +int nr_async_io_pending (void) +{ + unsigned int i, sum = 0; + + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + if (ti->iot) + sum += ti->iot->nr_async_pending; + } + return sum; +} + +static int user_req_stop_thread (threadinfo_t *ti) +{ + int j; + + printk(KERN_NOTICE "TUX: thread %d stopping ...\n", + (int)(ti-threadinfo)); + + if (!ti->started) + TUX_BUG(); + for (j = 0; j < CONFIG_TUX_NUMSOCKETS; j++) + if (ti->listen[j].proto) + remove_wait_queue(ti->listen[j].sock->sk->sk_sleep, + ti->wait_event + j); + remove_wait_queue(&wait_stop, &ti->stop); + + Dprintk(KERN_NOTICE "TUX: thread %d waiting for sockets to go inactive ...\n", (int)(ti-threadinfo)); + zap_listen_sockets(ti); + + Dprintk(KERN_NOTICE "TUX: thread %d has all sockets inactive.\n", (int)(ti-threadinfo)); + + flush_all_requests(ti); + stop_cachemiss_threads(ti); + + if (ti->nr_requests) + TUX_BUG(); + ti->started = 0; + + printk(KERN_INFO "TUX: thread %d stopped.\n", ti->cpu); + + ti->thread = NULL; + current->tux_info = NULL; + current->tux_exit = NULL; + atomic_dec(&nr_tux_threads_running); + wake_up(&thread_stopped); + + module_put(tux_module); + + return 0; +} + +#define COPY_INT(u_field, k_field) \ +do { \ + if (__copy_to_user(&u_info->u_field, &req->k_field, \ + sizeof(req->k_field))) \ + return_EFAULT; \ +} while (0) + +#define GETLEN(k_field, maxlen) \ + ((req->k_field##_len < maxlen) ? \ + req->k_field##_len : maxlen-1) + +#define COPY_STR(u_field, k_field, maxlen) \ +do { \ + if (__copy_to_user(u_info->u_field, req->k_field##_str, \ + GETLEN(k_field, maxlen))) \ + return_EFAULT; \ +} while (0) + +#define COPY_COND_STR(u_field,k_field,maxlen) \ +do { \ + if (req->k_field##_len) \ + COPY_STR(u_field, k_field, maxlen); \ + if (__put_user((char)0, u_info->u_field + \ + GETLEN(k_field, maxlen))) \ + return_EFAULT; \ +} while (0) + +static void finish_userspace_req (tux_req_t *req) +{ + threadinfo_t *ti = req->ti; + + ti->userspace_req = NULL; + req->usermode = 0; + req->private = 0; + req->error = 0; + DEC_STAT(nr_userspace_pending); + flush_request(req, 0); +} + +static void zap_userspace_req (tux_req_t *req) +{ + clear_keepalive(req); + finish_userspace_req(req); +} + +/* + * Fills in the user-space request structure: + */ +static int prepare_userspace_req (threadinfo_t *ti, user_req_t *u_info) +{ + u64 u_req; + tux_req_t *req = ti->userspace_req; + unsigned int tmp; + int filelen; + int fd; + + Dprintk("prepare_userspace_req(%p).\n", req); + if (!req) + TUX_BUG(); + if (req->error) { + TDprintk("userspace request has error %d.\n", req->error); + return -1; + } + fd = req->fd; + if (fd == -1) { + fd = sock_map_fd(req->sock); + Dprintk("sock_map_fd(%p) :%d.\n", req, fd); + if (fd < 0) { + Dprintk("sock_map_fd() returned %d.\n", fd); + return -EMFILE; + } + req->fd = fd; + } + +#define return_EFAULT do { Dprintk("-EFAULT at %d:%s.\n", __LINE__, __FILE__); return -EFAULT; } while (0) + + if (!access_ok(VERIFY_WRITE, u_info, sizeof(*u_info))) + return_EFAULT; + if (__copy_to_user(&u_info->sock, &fd, sizeof(fd))) + return_EFAULT; + if (req->attr) + TUX_BUG(); + + COPY_INT(module_index, usermodule_idx); + + COPY_COND_STR(query, query, MAX_URI_LEN); + + COPY_INT(event, event); + Dprintk("prepare userspace, user error: %d, event %d.\n", req->user_error, req->event); + COPY_INT(error, user_error); + req->user_error = 0; + + filelen = req->total_file_len; + if (filelen < 0) + filelen = 0; + if (__copy_to_user(&u_info->objectlen, &filelen, sizeof(filelen))) + return_EFAULT; + if ((req->method == METHOD_POST) && !filelen) + if (__copy_to_user(&u_info->objectlen, + &req->content_len, sizeof(filelen))) + return_EFAULT; + if (req->objectname_len) { + if (req->objectname[req->objectname_len]) + TUX_BUG(); + if (__copy_to_user(u_info->objectname, req->objectname, + req->objectname_len + 1)) + return_EFAULT; + } else + if (__put_user((char)0, u_info->objectname)) + return_EFAULT; + + COPY_INT(http_version, version); + COPY_INT(http_method, method); + COPY_INT(keep_alive, keep_alive); + + COPY_INT(cookies_len, cookies_len); + if (req->cookies_len) + COPY_STR(cookies, cookies, MAX_COOKIE_LEN); + if (__put_user((char)0, u_info->cookies + req->cookies_len)) + return_EFAULT; + + u_req = (u64)(unsigned long)req; + if (__copy_to_user(&u_info->id, &u_req, sizeof(u_req))) + return_EFAULT; + COPY_INT(priv, private); + COPY_INT(bytes_sent, bytes_sent); + + tmp = inet_sk(req->sock->sk)->daddr; + if (__copy_to_user(&u_info->client_host, &tmp, sizeof(tmp))) + return_EFAULT; + + COPY_COND_STR(content_type, content_type, MAX_FIELD_LEN); + COPY_COND_STR(user_agent, user_agent, MAX_FIELD_LEN); + COPY_COND_STR(accept, accept, MAX_FIELD_LEN); + COPY_COND_STR(accept_charset, accept_charset, MAX_FIELD_LEN); + COPY_COND_STR(accept_encoding, accept_encoding, MAX_FIELD_LEN); + COPY_COND_STR(accept_language, accept_language, MAX_FIELD_LEN); + COPY_COND_STR(cache_control, cache_control, MAX_FIELD_LEN); + COPY_COND_STR(if_modified_since, if_modified_since, MAX_FIELD_LEN); + COPY_COND_STR(negotiate, negotiate, MAX_FIELD_LEN); + COPY_COND_STR(pragma, pragma, MAX_FIELD_LEN); + COPY_COND_STR(referer, referer, MAX_FIELD_LEN); + + return TUX_RETURN_USERSPACE_REQUEST; +} + +#define GOTO_ERR_no_unlock do { Dprintk("sys_tux() ERR at %s:%d.\n", __FILE__, __LINE__); goto err_no_unlock; } while (0) +#define GOTO_ERR_unlock do { Dprintk("sys_tux() ERR at %s:%d.\n", __FILE__, __LINE__); goto err_unlock; } while (0) + +static int register_mimetype(user_req_t *u_info) +{ + char extension[MAX_URI_LEN], mimetype[MAX_URI_LEN], expires[MAX_URI_LEN]; + u64 u_addr; + char *addr; + int ret; + + ret = strncpy_from_user(extension, u_info->objectname, MAX_URI_LEN); + if (ret <= 0) + GOTO_ERR_no_unlock; + extension[ret] = 0; + Dprintk("got MIME extension: %s.\n", extension); + ret = copy_from_user(&u_addr, &u_info->object_addr, sizeof(u_addr)); + if (ret) + GOTO_ERR_no_unlock; + addr = (char *)(unsigned long)u_addr; + ret = strncpy_from_user(mimetype, addr, MAX_URI_LEN); + if (ret <= 0) + GOTO_ERR_no_unlock; + mimetype[ret] = 0; + Dprintk("got MIME type: %s.\n", mimetype); + ret = strncpy_from_user(expires, u_info->cache_control, MAX_URI_LEN); + if (ret >= 0) + expires[ret] = 0; + else + expires[0] = 0; + Dprintk("got expires header: %s.\n", expires); + + add_mimetype(extension, mimetype, expires); + ret = 0; +err_no_unlock: + return ret; +} + +void user_send_buffer (tux_req_t *req, int cachemiss) +{ + int ret; + + + SET_TIMESTAMP(req->output_timestamp); + +repeat: + ret = send_sync_buf(req, req->sock, req->userbuf, req->userlen, MSG_DONTWAIT | MSG_MORE); + switch (ret) { + case -EAGAIN: + add_tux_atom(req, user_send_buffer); + if (add_output_space_event(req, req->sock)) { + del_tux_atom(req); + goto repeat; + } + INC_STAT(user_sendbuf_write_misses); + break; + default: + if (ret <= 0) { + req_err(req); + req->usermode = 0; + req->private = 0; + add_req_to_workqueue(req); + break; + } + req->userbuf += ret; + req->userlen -= ret; + if ((int)req->userlen < 0) + TUX_BUG(); + if (req->userlen) + goto repeat; + add_req_to_workqueue(req); + break; + } +} + +void user_send_object (tux_req_t *req, int cachemiss) +{ + int ret; + + + SET_TIMESTAMP(req->output_timestamp); + +repeat: + ret = generic_send_file(req, req->sock, cachemiss); + switch (ret) { + case -5: + add_tux_atom(req, user_send_object); + output_timeout(req); + break; + case -4: + add_tux_atom(req, user_send_object); + if (add_output_space_event(req, req->sock)) { + del_tux_atom(req); + goto repeat; + } + INC_STAT(user_sendobject_write_misses); + break; + case -3: + INC_STAT(user_sendobject_cachemisses); + add_tux_atom(req, user_send_object); + queue_cachemiss(req); + break; + case -1: + break; + default: + req->in_file.f_pos = 0; + add_req_to_workqueue(req); + break; + } +} + +void user_get_object (tux_req_t *req, int cachemiss) +{ + int missed; + + if (!req->dentry) { + req->usermode = 0; + missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC); + if (req->usermode) + TUX_BUG(); + req->usermode = 1; + if (!missed && !req->dentry) { + req->error = 0; + req->user_error = -ENOENT; + add_req_to_workqueue(req); + return; + } + if (missed) { + if (cachemiss) + TUX_BUG(); + INC_STAT(user_lookup_cachemisses); +fetch_missed: + req->ti->userspace_req = NULL; + DEC_STAT(nr_userspace_pending); + add_tux_atom(req, user_get_object); + queue_cachemiss(req); + return; + } + } + req->total_file_len = req->dentry->d_inode->i_size; + if (!req->output_len) + req->output_len = req->total_file_len; + if (tux_fetch_file(req, !cachemiss)) { + INC_STAT(user_fetch_cachemisses); + goto fetch_missed; + } + req->in_file.f_pos = 0; + add_req_to_workqueue(req); +} + +asmlinkage long __sys_tux (unsigned int action, user_req_t *u_info) +{ + int ret = -1; + threadinfo_t *ti; + tux_req_t *req; + + if (action != TUX_ACTION_CURRENT_DATE) + Dprintk("got sys_tux(%d, %p).\n", action, u_info); + + if (action >= MAX_TUX_ACTION) + GOTO_ERR_no_unlock; + + ti = (threadinfo_t *) current->tux_info; + if (ti) + if (ti->thread != current) + TUX_BUG(); + + if (!capable(CAP_SYS_ADMIN) + && (action != TUX_ACTION_CONTINUE_REQ) && + (action != TUX_ACTION_STOPTHREAD)) + goto userspace_actions; + + switch (action) { + case TUX_ACTION_CONTINUE_REQ: + ret = continue_request((int)(long)u_info); + goto out; + + case TUX_ACTION_STARTUP: + lock_kernel(); + ret = user_req_startup(); + unlock_kernel(); + goto out; + + case TUX_ACTION_SHUTDOWN: + lock_kernel(); + ret = user_req_shutdown(); + unlock_kernel(); + goto out; + + case TUX_ACTION_REGISTER_MODULE: + ret = user_register_module(u_info); + goto out; + + case TUX_ACTION_UNREGISTER_MODULE: + ret = user_unregister_module(u_info); + goto out; + + case TUX_ACTION_STARTTHREAD: + { + unsigned int nr; + + ret = copy_from_user(&nr, &u_info->thread_nr, + sizeof(int)); + if (ret) + GOTO_ERR_no_unlock; + if (nr >= nr_tux_threads) + GOTO_ERR_no_unlock; + ti = threadinfo + nr; + if (ti->started) + GOTO_ERR_unlock; + ti->started = 1; + current->tux_info = ti; + current->tux_exit = tux_exit; + if (ti->thread) + TUX_BUG(); + Dprintk("TUX: current open files limit for TUX%d: %ld.\n", nr, current->rlim[RLIMIT_NOFILE].rlim_cur); + lock_kernel(); + ret = user_req_start_thread(ti); + unlock_kernel(); + if (ret) { + current->tux_info = NULL; + current->tux_exit = NULL; + } else { + if (ti->thread != current) + TUX_BUG(); + } + goto out_userreq; + } + + case TUX_ACTION_STOPTHREAD: + if (!ti) + GOTO_ERR_no_unlock; + if (!ti->started) + GOTO_ERR_unlock; + req = ti->userspace_req; + if (req) + zap_userspace_req(req); + + lock_kernel(); + ret = user_req_stop_thread(ti); + unlock_kernel(); + goto out_userreq; + + case TUX_ACTION_CURRENT_DATE: + ret = strncpy_from_user(tux_date, u_info->new_date, + DATE_LEN); + if (ret <= 0) + GOTO_ERR_no_unlock; + goto out; + + case TUX_ACTION_REGISTER_MIMETYPE: + ret = register_mimetype(u_info); + if (ret) + GOTO_ERR_no_unlock; + goto out; + + case TUX_ACTION_QUERY_VERSION: + ret = (TUX_MAJOR_VERSION << 24) | (TUX_MINOR_VERSION << 16) | TUX_PATCHLEVEL_VERSION; + goto out; + default: + ; + } + +userspace_actions: + + if (!ti) + GOTO_ERR_no_unlock; + + if (!ti->started) + GOTO_ERR_unlock; + + req = ti->userspace_req; + if (!req) { + if (action == TUX_ACTION_EVENTLOOP) + goto eventloop; + GOTO_ERR_unlock; + } + if (!req->usermode) + TUX_BUG(); + + ret = copy_from_user(&req->event, &u_info->event, sizeof(int)); + if (ret) + GOTO_ERR_unlock; + ret = copy_from_user(&req->status, &u_info->http_status, sizeof(int)); + if (ret) + GOTO_ERR_unlock; + ret = copy_from_user(&req->bytes_sent, &u_info->bytes_sent, sizeof(int)); + if (ret) + GOTO_ERR_unlock; + ret = copy_from_user(&req->private, &u_info->priv, sizeof(req->private)); + if (ret) + GOTO_ERR_unlock; + + switch (action) { + + case TUX_ACTION_EVENTLOOP: +eventloop: + req = ti->userspace_req; + if (req) + zap_userspace_req(req); + ret = event_loop(ti); + goto out_userreq; + + /* + * Module forces keepalive off, server will close + * the connection. + */ + case TUX_ACTION_FINISH_CLOSE_REQ: + clear_keepalive(req); + + case TUX_ACTION_FINISH_REQ: + finish_userspace_req(req); + goto eventloop; + + case TUX_ACTION_REDIRECT_REQ: + + ti->userspace_req = NULL; + req->usermode = 0; + req->private = 0; + req->error = TUX_ERROR_REDIRECT; + DEC_STAT(nr_userspace_pending); + add_tux_atom(req, redirect_request); + add_req_to_workqueue(req); + + goto eventloop; + + case TUX_ACTION_POSTPONE_REQ: + + postpone_request(req); + ti->userspace_req = NULL; + ret = TUX_RETURN_USERSPACE_REQUEST; + break; + + case TUX_ACTION_GET_OBJECT: + release_req_dentry(req); + ret = strncpy_from_user(req->objectname, + u_info->objectname, MAX_URI_LEN-1); + if (ret <= 0) { + req->objectname[0] = 0; + req->objectname_len = 0; + GOTO_ERR_unlock; + } + req->objectname[ret] = 0; // string delimit + req->objectname_len = ret; + + Dprintk("got objectname {%s} (%d) from user-space req %p (req: %p).\n", req->objectname, req->objectname_len, u_info, req); + req->ti->userspace_req = NULL; + DEC_STAT(nr_userspace_pending); + user_get_object(req, 0); + goto eventloop; + + case TUX_ACTION_READ_OBJECT: + { + u64 u_addr; + char *addr; + loff_t ppos = 0; + struct file *filp; + + if (!req->dentry) + GOTO_ERR_unlock; + + ret = copy_from_user(&u_addr, &u_info->object_addr, + sizeof(u_addr)); + if (ret) + GOTO_ERR_unlock; + addr = (char *)(unsigned long)u_addr; + filp = dentry_open(req->dentry, O_RDONLY, 0); + dget(req->dentry); + generic_file_read(filp, addr, req->total_file_len, &ppos); + fput(filp); + ret = TUX_RETURN_USERSPACE_REQUEST; + break; + } + + case TUX_ACTION_SEND_OBJECT: + if (!req->dentry) + GOTO_ERR_unlock; + req->ti->userspace_req = NULL; + DEC_STAT(nr_userspace_pending); + user_send_object(req, 0); + goto eventloop; + + case TUX_ACTION_SEND_BUFFER: + { + u64 u_addr; + char *addr; + unsigned int len; + + ret = copy_from_user(&u_addr, + &u_info->object_addr, sizeof(u_addr)); + if (ret) + GOTO_ERR_unlock; + addr = (char *)(unsigned long)u_addr; + ret = copy_from_user(&len, + &u_info->objectlen, sizeof(addr)); + if (ret) + GOTO_ERR_unlock; + if ((int)len <= 0) + GOTO_ERR_unlock; + + ret = -EFAULT; + if (!access_ok(VERIFY_READ, addr, len)) + GOTO_ERR_unlock; + req->userbuf = addr; + req->userlen = len; + + req->ti->userspace_req = NULL; + DEC_STAT(nr_userspace_pending); + user_send_buffer(req, 0); + ret = 0; + goto eventloop; + } + + case TUX_ACTION_READ_HEADERS: + { + char *addr; + u64 u_addr; + + ret = copy_from_user(&u_addr, &u_info->object_addr, + sizeof(u_addr)); + if (ret) + GOTO_ERR_unlock; + addr = (char *)(unsigned long)u_addr; + ret = copy_to_user(&u_info->objectlen, + &req->headers_len, sizeof(req->headers_len)); + if (ret) + GOTO_ERR_unlock; + ret = copy_to_user(addr,req->headers, req->headers_len); + if (ret) + GOTO_ERR_unlock; + break; + } + + case TUX_ACTION_READ_POST_DATA: + { + char *addr; + unsigned int size; + u64 u_addr; + + ret = copy_from_user(&u_addr, &u_info->object_addr, + sizeof(u_addr)); + if (ret) + GOTO_ERR_unlock; + addr = (char *)(unsigned long)u_addr; + + ret = copy_from_user(&size, &u_info->objectlen, + sizeof(size)); + if (ret) + GOTO_ERR_unlock; + Dprintk("READ_POST_DATA: got %p(%d).\n", addr, size); + if (req->post_data_len < size) + size = req->post_data_len; + Dprintk("READ_POST_DATA: writing %d.\n", size); + ret = copy_to_user(&u_info->objectlen, + &size, sizeof(size)); + if (ret) + GOTO_ERR_unlock; + ret = copy_to_user(addr, req->post_data_str, size); + if (ret) + GOTO_ERR_unlock; + goto out; + } + + case TUX_ACTION_WATCH_PROXY_SOCKET: + { + struct socket *sock; + int err; + long fd; + u64 u_addr; + + ret = copy_from_user(&u_addr, &u_info->object_addr, + sizeof(u_addr)); + if (ret) + GOTO_ERR_unlock; + fd = (int)(unsigned long)u_addr; + + sock = sockfd_lookup(fd, &err); + if (!sock) + GOTO_ERR_unlock; + put_data_sock(req); + link_tux_data_socket(req, sock); + + ret = 0; + goto out; + } + + case TUX_ACTION_WAIT_PROXY_SOCKET: + { + if (!req->data_sock) + GOTO_ERR_unlock; + if (socket_input(req->data_sock)) { + ret = TUX_RETURN_USERSPACE_REQUEST; + goto out_userreq; + } + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + spin_unlock_irq(&req->ti->work_lock); + if (socket_input(req->data_sock)) { + unidle_req(req); + ret = TUX_RETURN_USERSPACE_REQUEST; + goto out_userreq; + } + req->ti->userspace_req = NULL; + goto eventloop; + } + + default: + GOTO_ERR_unlock; + } + +out_userreq: + req = ti->userspace_req; + if (req) { + ret = prepare_userspace_req(ti, u_info); + if (ret < 0) { + TDprintk("hm, user req %p returned %d, zapping.\n", + req, ret); + zap_userspace_req(req); + goto eventloop; + } + } +out: + if (action != TUX_ACTION_CURRENT_DATE) + Dprintk("sys_tux(%d, %p) returning %d.\n", action, u_info, ret); + while (unlikely(test_thread_flag(TIF_NEED_RESCHED))) { + __set_task_state(current, TASK_RUNNING); + schedule(); + } + return ret; +err_unlock: +err_no_unlock: + Dprintk("sys_tux(%d, %p) returning -EINVAL (ret:%d)!\n", action, u_info, ret); + while (unlikely(test_thread_flag(TIF_NEED_RESCHED))) { + __set_task_state(current, TASK_RUNNING); + schedule(); + } + return -EINVAL; +} + +/* + * This gets called if a TUX thread does an exit(). + */ +void tux_exit (void) +{ + __sys_tux(TUX_ACTION_STOPTHREAD, NULL); +} + +int tux_init(void) +{ + start_sysctl(); + +#if CONFIG_TUX_MODULE + spin_lock(&tux_module_lock); + sys_tux_ptr = __sys_tux; + tux_module = THIS_MODULE; + spin_unlock(&tux_module_lock); +#endif + + return 0; +} + +void tux_cleanup (void) +{ +#if CONFIG_TUX_MODULE + spin_lock(&tux_module_lock); + tux_module = NULL; + sys_tux_ptr = NULL; + spin_unlock(&tux_module_lock); +#endif + + end_sysctl(); +} + +module_init(tux_init) +module_exit(tux_cleanup) + +MODULE_LICENSE("GPL"); + diff --git a/net/tux/mod.c b/net/tux/mod.c new file mode 100644 index 000000000..14891140e --- /dev/null +++ b/net/tux/mod.c @@ -0,0 +1,262 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * mod.c: loading/registering of dynamic TUX modules + */ + +#include +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +spinlock_t tuxmodules_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(tuxmodules_list); + +tcapi_template_t * get_first_usermodule (void) +{ + tcapi_template_t *tcapi; + struct list_head *head, *curr, *next; + + spin_lock(&tuxmodules_lock); + head = &tuxmodules_list; + next = head->next; + + while ((curr = next) != head) { + tcapi = list_entry(curr, tcapi_template_t, modules); + next = curr->next; + if (tcapi->userspace_id) { + spin_unlock(&tuxmodules_lock); + return tcapi; + } + } + spin_unlock(&tuxmodules_lock); + return NULL; +} + +static tcapi_template_t * lookup_module (const char *vfs_name) +{ + tcapi_template_t *tcapi; + struct list_head *head, *curr, *next; + + while (*vfs_name == '/') + vfs_name++; + Dprintk("looking up TUX module {%s}.\n", vfs_name); + head = &tuxmodules_list; + next = head->next; + + while ((curr = next) != head) { + tcapi = list_entry(curr, tcapi_template_t, modules); + next = curr->next; + Dprintk("checking module {%s} == {%s}?\n", vfs_name, tcapi->vfs_name); + if (!strcmp(tcapi->vfs_name, vfs_name)) + return tcapi; + } + return NULL; +} + +/* + * Attempt to load a TUX application module. + * This is the slow path, we cache ('link') the module's + * API vector to the inode. + * The module loading path is serialized, and we handshake + * with the loaded module and fetch its API vector. + */ +tcapi_template_t * lookup_tuxmodule (const char *filename) +{ + tcapi_template_t *tcapi; + + spin_lock(&tuxmodules_lock); + tcapi = lookup_module(filename); + if (!tcapi) + Dprintk("did not find module vfs:{%s}\n", filename); + spin_unlock(&tuxmodules_lock); + return tcapi; +} + + +int register_tuxmodule (tcapi_template_t *tcapi) +{ + int ret = -EEXIST; + + spin_lock(&tuxmodules_lock); + + if (lookup_module(tcapi->vfs_name)) { + Dprintk("module with VFS binding '%s' already registered!\n", + tcapi->vfs_name); + goto out; + } + + list_add(&tcapi->modules, &tuxmodules_list); + ret = 0; + Dprintk("TUX module %s registered.\n", tcapi->vfs_name); +out: + spin_unlock(&tuxmodules_lock); + + return ret; +} + +void unregister_all_tuxmodules (void) +{ + tcapi_template_t *tcapi; + struct list_head *curr; + + spin_lock(&tuxmodules_lock); + while (((curr = tuxmodules_list.next)) != &tuxmodules_list) { + tcapi = list_entry(curr, tcapi_template_t, modules); + list_del(curr); + kfree(tcapi->vfs_name); + kfree(tcapi); + } + spin_unlock(&tuxmodules_lock); +} + +tcapi_template_t * unregister_tuxmodule (char *vfs_name) +{ + tcapi_template_t *tcapi; + int err = 0; + + spin_lock(&tuxmodules_lock); + tcapi = lookup_module(vfs_name); + if (!tcapi) { + Dprintk("huh, module %s not registered??\n", vfs_name); + err = -1; + } else { + list_del(&tcapi->modules); + Dprintk("TUX module %s unregistered.\n", vfs_name); + } + spin_unlock(&tuxmodules_lock); + + return tcapi; +} + +static int check_module_version (user_req_t *u_info) +{ + int major, minor, patch, ret; + + ret = copy_from_user(&major, &u_info->version_major, sizeof(int)); + ret += copy_from_user(&minor, &u_info->version_minor, sizeof(int)); + ret += copy_from_user(&patch, &u_info->version_patch, sizeof(int)); + if (ret) + return -EFAULT; + + if ((major != TUX_MAJOR_VERSION) || (minor > TUX_MINOR_VERSION)) { + + printk(KERN_ERR "TUX: module version %d:%d incompatible with kernel version %d:%d!\n", major, minor, TUX_MAJOR_VERSION, TUX_MINOR_VERSION); + return -EINVAL; + } + return 0; +} + +int user_register_module (user_req_t *u_info) +{ + int idx, len, ret; + tcapi_template_t *tcapi; + char modulename [MAX_URI_LEN+1]; + + ret = check_module_version(u_info); + if (ret) + return ret; + + /* + * Check module name length. + */ + ret = strnlen_user(u_info->objectname, MAX_URI_LEN+2); + if (ret < 0) + goto out; + ret = -EINVAL; + if (ret >= MAX_URI_LEN) + goto out; + + Dprintk("register user-module, %p.\n", u_info); + ret = strncpy_from_user(modulename, u_info->objectname, MAX_URI_LEN); + if (ret < 0) + goto out; + modulename[ret] = 0; + Dprintk("... user-module is: {%s}.\n", modulename); + len = strlen(modulename); + if (!len) + printk(KERN_ERR "no module name provided: please upgrade your TUX user-space utilities!\n"); + if (!len || (len > MAX_URI_LEN)) + return -EINVAL; + Dprintk("... user-module len is: %d.\n", len); + + ret = copy_from_user(&idx, &u_info->module_index, sizeof(int)); + if (ret || !idx) + goto out; + Dprintk("... user-module index is: %d.\n", idx); + + ret = -ENOMEM; + tcapi = (tcapi_template_t *) kmalloc(sizeof(*tcapi), GFP_KERNEL); + if (!tcapi) + goto out; + memset(tcapi, 0, sizeof(*tcapi)); + + tcapi->vfs_name = (char *) kmalloc(len+1, GFP_KERNEL); + if (!tcapi->vfs_name) { + kfree(tcapi); + goto out; + } + strcpy(tcapi->vfs_name, modulename); + tcapi->userspace_id = idx; + + Dprintk("... registering module {%s}.\n", tcapi->vfs_name); + ret = register_tuxmodule(tcapi); +out: + return ret; +} + +int user_unregister_module (user_req_t *u_info) +{ + int len, ret; + tcapi_template_t *tcapi; + char modulename [MAX_URI_LEN+1]; + + /* + * Check module name length. + */ + ret = strnlen_user(u_info->objectname, MAX_URI_LEN+2); + if (ret < 0) + goto out; + ret = -EINVAL; + if (ret >= MAX_URI_LEN) + goto out; + Dprintk("unregister user-module, %p.\n", u_info); + ret = strncpy_from_user(modulename, u_info->objectname, MAX_URI_LEN); + if (ret <= 0) + goto out; + modulename[ret] = 0; + Dprintk("... user-module is: {%s}.\n", modulename); + len = strlen(modulename); + if (!len || (len > MAX_URI_LEN)) + return -EINVAL; + Dprintk("... user-module len is: %d.\n", len); + + Dprintk("... unregistering module {%s}.\n", modulename); + tcapi = unregister_tuxmodule(modulename); + ret = -EINVAL; + if (tcapi) { + ret = 0; + kfree(tcapi->vfs_name); + kfree(tcapi); + } +out: + return ret; +} + diff --git a/net/tux/output.c b/net/tux/output.c new file mode 100644 index 000000000..2d0f073fe --- /dev/null +++ b/net/tux/output.c @@ -0,0 +1,352 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * output.c: Send data to clients + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +int send_sync_buf (tux_req_t *req, struct socket *sock, const char *buf, const size_t length, unsigned long flags) +{ + struct msghdr msg; + struct iovec iov; + int len, written = 0, left = length; + struct tcp_opt *tp = tcp_sk(sock->sk); + + tp->nonagle = 2; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags | MSG_NOSIGNAL; +repeat_send: + msg.msg_iov->iov_len = left; + msg.msg_iov->iov_base = (char *) buf + written; + + len = sock_sendmsg(sock, &msg, left); + + Dprintk("sendmsg ret: %d, written: %d, left: %d.\n", len,written,left); + if ((len == -ERESTARTSYS) || (!(flags & MSG_DONTWAIT) && + (len == -EAGAIN))) { + flush_all_signals(); + goto repeat_send; + } + if (len > 0) { + written += len; + left -= len; + if (left) + goto repeat_send; + } + if (len >= 0) { + if (written != length) + TUX_BUG(); + if (left) + TUX_BUG(); + } + if (req && (written > 0)) + req->bytes_sent += written; + Dprintk("sendmsg FINAL ret: %d, written: %d, left: %d.\n", len,written,left); + return written ? written : len; +} + +unsigned int tux_zerocopy_sendfile = 1; + +typedef struct sock_send_desc +{ + struct socket *sock; + tux_req_t *req; +} sock_send_desc_t; + +static int sock_send_actor (read_descriptor_t * desc, struct page *page, + unsigned long offset, unsigned long orig_size) +{ + sock_send_desc_t *sock_desc = (sock_send_desc_t *)desc->buf; + struct socket *sock = sock_desc->sock; + tux_req_t *req = sock_desc->req; + unsigned int flags; + ssize_t written; + char *buf = NULL; + unsigned int size; + + flags = MSG_DONTWAIT | MSG_NOSIGNAL; + if (desc->count < orig_size) + orig_size = desc->count; + if (desc->count > orig_size) + flags |= MSG_MORE; + Dprintk("sock_send_actor(), page: %p, offset: %ld, orig_size: %ld, sock: %p, desc->count: %d, desc->written: %d, MSG_MORE: %d.\n", page, offset, orig_size, sock, desc->count, desc->written, flags & MSG_MORE); + + if (req->content_gzipped >= 2) { + unsigned int gzip_left; + struct msghdr msg; + struct iovec iov; + mm_segment_t oldmm; + char *kaddr = kmap(page); + __u32 in_len, out_len; + out_len = orig_size*101/100 + 12; + buf = tux_kmalloc(out_len); + in_len = orig_size; + size = out_len; + gzip_left = 0; +// 8b1f 0808 fdc4 3bd8 0300 79 +buf[1] = 0x8b; buf[0] = 0x1f; buf[3] = 0x08; buf[2] = 0x08; +buf[5] = 0xfd; buf[4] = 0xc4; buf[7] = 0x3b; buf[6] = 0xd8; +buf[9] = 0x03; buf[8] = 0x00; buf[10] = 0x79; + size += 11; + Dprintk("pre-compress: in_len: %d, out_len: %d, gzip_left: %d, uncompressed size: %d.\n", in_len, out_len, gzip_left, size); + gzip_left = tux_gzip_compress(req, kaddr, buf+11, &in_len, &out_len); + size -= out_len; + buf[11] = 0x79; buf[12] = 0x00; + + Dprintk("post-compress: in_len: %d, out_len: %d, gzip_left: %d, compressed size: %d.\n", in_len, out_len, gzip_left, size); + kunmap(page); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + flags &= ~MSG_DONTWAIT; + msg.msg_flags = flags; + iov.iov_base = buf; + iov.iov_len = size; + + oldmm = get_fs(); set_fs(KERNEL_DS); + written = sock_sendmsg(sock, &msg, size); + set_fs(oldmm); + + Dprintk("buf: %p, offset: %ld, size: %d, written: %d.\n", buf, offset, size, written); + if (written == size) + written = orig_size; + else + written = size; + + } else { + size = orig_size; + if (tux_zerocopy_sendfile && sock->ops->sendpage && + (sock->sk->sk_route_caps&NETIF_F_SG)) { + written = sock->ops->sendpage(sock, page, offset, size, flags); + } else { + struct msghdr msg; + struct iovec iov; + char *kaddr; + mm_segment_t oldmm; + + if (offset+size > PAGE_SIZE) + return -EFAULT; + + kaddr = kmap(page); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags; + iov.iov_base = kaddr + offset; + iov.iov_len = size; + + oldmm = get_fs(); set_fs(KERNEL_DS); + written = sock_sendmsg(sock, &msg, size); + set_fs(oldmm); + + Dprintk("kaddr: %p, offset: %ld, size: %d, written: %d.\n", kaddr, offset, size, written); + kunmap(page); + } + } + if (written < 0) { + desc->error = written; + written = 0; + } + Dprintk("desc->count: %d, desc->written: %d, written: %d.\n", desc->count, desc->written, written); + desc->count -= written; + if ((int)desc->count < 0) + TUX_BUG(); + desc->written += written; + + if (buf) + kfree(buf); + + return written; +} + +/* + * Return 1 if the output space condition went away + * before adding the handler. + */ +int add_output_space_event (tux_req_t *req, struct socket *sock) +{ + struct sock *sk = sock->sk; + /* + * blocked due to socket IO? + */ + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0,&req->wait_output_space)) + TUX_BUG(); + INC_STAT(nr_output_space_pending); + + if ((sk->sk_state == TCP_ESTABLISHED) && enough_wspace(sk)) { + if (test_and_clear_bit(0, &req->wait_output_space)) { + DEC_STAT(nr_output_space_pending); + del_keepalive_timer(req); + spin_unlock_irq(&req->ti->work_lock); + return 1; + } + } + spin_unlock_irq(&req->ti->work_lock); + + return 0; +} + +#define SEND_BLOCKSIZE (164*1024) + +int generic_send_file (tux_req_t *req, struct socket *sock, int cachemiss) +{ + sock_send_desc_t sock_desc; + int len, want, nonblock = !cachemiss; + struct tcp_opt *tp = tcp_sk(sock->sk); + + tp->nonagle = 2; + + sock_desc.sock = sock; + sock_desc.req = req; + +repeat: + Dprintk("generic_send_file(%p,%d,%p) called, f_pos: %Ld, output_len: %Ld.\n", req, nonblock, sock, req->in_file.f_pos, req->output_len); + + if (req->proto->check_req_err(req, cachemiss)) + return -1; + if (connection_too_fast(req) == 2) { + len = -5; + goto out; + } + if (req->total_file_len < req->in_file.f_pos) + TUX_BUG(); + + req->desc.written = 0; + /* + * Careful, output_len can be 64-bit, while 'want' can be 32-bit. + */ + if (req->output_len > SEND_BLOCKSIZE) + want = SEND_BLOCKSIZE; + else + want = req->output_len; + req->desc.count = want; + req->desc.buf = (char *) &sock_desc; + req->desc.error = 0; + Dprintk("sendfile(), desc.count: %d.\n", req->desc.count); + do_generic_file_read(&req->in_file, &req->in_file.f_pos, &req->desc, sock_send_actor, nonblock); + if (req->desc.written > 0) { + req->bytes_sent += req->desc.written; + req->output_len -= req->desc.written; + } + if (!nonblock && (req->desc.error == -EWOULDBLOCKIO)) + TUX_BUG(); + Dprintk("sendfile() wrote: %d bytes.\n", req->desc.written); + if (req->output_len && !req->desc.written && !req->desc.error) { +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + req->in_file.f_pos = 0; + req->error = TUX_ERROR_CONN_CLOSE; + zap_request(req, cachemiss); + return -1; + } + + switch (req->desc.error) { + + case -EWOULDBLOCKIO: + len = -3; + break; + case -EAGAIN: +no_write_space: + Dprintk("sk->wmem_queued: %d, sk->sndbuf: %d.\n", + sock->sk->sk_wmem_queued, sock->sk->sk_sndbuf); + len = -4; + break; + default: + len = req->desc.written; +#if CONFIG_TUX_DEBUG + if (req->desc.error) + TDprintk("TUX: sendfile() returned error %d (signals pending: %08lx)!\n", req->desc.error, current->pending.signal.sig[0]); +#endif + if (!req->desc.error) { + if (req->output_len < 0) + BUG(); + if (req->output_len) { + if (test_bit(SOCK_NOSPACE, &sock->flags)) + goto no_write_space; + goto repeat; + } + } +#if CONFIG_TUX_DEBUG + if (req->desc.written != want) + TDprintk("TUX: sendfile() wrote %d bytes, wanted %d! (pos %Ld) (signals pending: %08lx).\n", req->desc.written, want, req->in_file.f_pos, current->pending.signal.sig[0]); + else + Dprintk("TUX: sendfile() FINISHED for req %p, wrote %d bytes.\n", req, req->desc.written); + req->bytes_expected = 0; +#endif + break; + } + +out: + Dprintk("sendfile() wrote %d bytes.\n", len); + + return len; +} + +static int file_fetch_actor (read_descriptor_t * desc, struct page *page, + unsigned long offset, unsigned long size) +{ + if (desc->count < size) + size = desc->count; + + desc->count -= size; + desc->written += size; + + return size; +} + +int tux_fetch_file (tux_req_t *req, int nonblock) +{ + int len; + + req->desc.written = 0; + req->desc.count = req->output_len; + req->desc.buf = NULL; + req->desc.error = 0; + + do_generic_file_read(&req->in_file, &req->in_file.f_pos, &req->desc, + file_fetch_actor, nonblock); + if (nonblock && (req->desc.error == -EWOULDBLOCKIO)) + return 1; + len = req->desc.written; + if (req->desc.error) + Dprintk("fetchfile() returned %d error!\n", req->desc.error); + Dprintk("fetchfile() fetched %d bytes.\n", len); + return 0; +} + diff --git a/net/tux/parser.h b/net/tux/parser.h new file mode 100644 index 000000000..f355c1e14 --- /dev/null +++ b/net/tux/parser.h @@ -0,0 +1,102 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, Ingo Molnar + * + * parser.h: generic parsing routines + */ + +#define get_c(ptr,left) \ +({ \ + char __ret; \ + \ + if (!left) \ + GOTO_INCOMPLETE; \ + left--; \ + __ret = *((ptr)++); \ + if (!__ret) \ + GOTO_REDIR; \ + __ret; \ +}) + +#define PARSE_TOKEN(ptr,str,left) \ + ({ \ + int __ret; \ + \ + if (!left) \ + GOTO_INCOMPLETE; \ + if (sizeof(str)-1 > left) { \ + if (memcmp(ptr, str, left)) \ + GOTO_REDIR; \ + GOTO_INCOMPLETE; \ + } \ + \ + if (memcmp(ptr, str, sizeof(str)-1)) \ + __ret = 0; \ + else { \ + ptr += sizeof(str)-1; \ + left -= sizeof(str)-1; \ + __ret = 1; \ + } \ + __ret; \ + }) + +#define PARSE_METHOD(req,ptr,name,left) \ + ({ \ + int __ret; \ + \ + if (PARSE_TOKEN(ptr,#name" ",left)) { \ + req->method = METHOD_##name; \ + __ret = 1; \ + } else \ + __ret = 0; \ + __ret; \ + }) + +#define COPY_LINE(ptr,target,left) \ + do { \ + char prev_c = 0, c; \ + while (((c = get_c(ptr,left))) != '\n') \ + *target++ = prev_c = c; \ + if (prev_c != '\r') \ + GOTO_REDIR; \ + } while (0) + +#define COPY_LINE_TOLOWER(ptr,target,left,limit) \ + do { \ + char prev_c = 0, c; \ + while (((c = get_c(ptr,left))) != '\n') { \ + if ((c >= 'A') && (c <= 'Z')) \ + c -= 'A'-'a'; \ + *target++ = prev_c = c; \ + if (target == (limit)) \ + GOTO_REDIR; \ + } \ + if (prev_c != '\r') \ + GOTO_REDIR; \ + } while (0) + +#define COPY_FIELD(ptr,target,left) \ + do { \ + char c; \ + while ((c = get_c(ptr,left)) != ' ') \ + *target++ = c; \ + } while (0) + +#define SKIP_LINE(ptr,left) \ + do { \ + char prev_c = 0, c; \ + while (((c = get_c(ptr,left))) != '\n') \ + prev_c = c; \ + if (prev_c != '\r') \ + GOTO_REDIR; \ + } while (0) + +#define SKIP_WHITESPACE(curr,left) \ +do { \ + while ((left) && (*(curr) == ' ')) \ + (curr)++, (left)--; \ + if (!(left)) \ + GOTO_REDIR; \ +} while (0) + diff --git a/net/tux/postpone.c b/net/tux/postpone.c new file mode 100644 index 000000000..d4a693b93 --- /dev/null +++ b/net/tux/postpone.c @@ -0,0 +1,77 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * postpone.c: postpone/continue userspace requests + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +void postpone_request (tux_req_t *req) +{ + if (!req->usermode) + TUX_BUG(); + INC_STAT(nr_postpone_pending); + req->postponed = 1; +} + +/* + * Continue a postponed request. The request will show up in the + * userspace queue and will be handled by the fast thread. + * A request can only be postponed in a TUX process, but can be + * continued from any process that has access to the socket file + * descriptor. + */ +int continue_request (int fd) +{ + threadinfo_t *ti; + struct socket *sock; + tux_req_t *req; + int err; + + sock = sockfd_lookup(fd, &err); + if (!sock || !sock->sk) + goto out; + req = sock->sk->sk_user_data; + + err = -EINVAL; + if (!req) + goto out_put; + ti = req->ti; + if (!req->postponed) + goto out_unlock_put; + if (!req->usermode) + TUX_BUG(); + + req->postponed = 0; + DEC_STAT(nr_postpone_pending); + + Dprintk("continuing postponed req %p.\n", req); + add_req_to_workqueue(req); + +out_unlock_put: + err = 0; +out_put: + fput(sock->file); +out: + return err; +} + diff --git a/net/tux/proc.c b/net/tux/proc.c new file mode 100644 index 000000000..2973a482b --- /dev/null +++ b/net/tux/proc.c @@ -0,0 +1,1190 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * proc.c: /proc/sys/tux handling + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +char tux_common_docroot[200] = "/var/www/tux/"; +char tux_http_subdocroot[200] = ""; +char tux_ftp_subdocroot[200] = ""; +char tux_logfile[200] = "/var/log/tux"; +char tux_cgiroot[200] = "/var/www/tux/cgiroot/"; +char tux_404_page[200] = "404.html"; +char tux_default_vhost[200] = "default"; +char tux_extra_html_header[600]; +unsigned int tux_extra_html_header_size = 0; + +int tux_cgi_uid = -1; +int tux_cgi_gid = -1; +unsigned int tux_clientport = 8080; +unsigned int tux_logging = 0; +unsigned int tux_threads = 2; +unsigned int tux_max_connect = 10000; +unsigned int tux_max_keepalives = 10000; +unsigned int tux_max_backlog = 2048; +unsigned int tux_keepalive_timeout = 0; +unsigned int tux_max_output_bandwidth = 0; +unsigned int tux_defer_accept = 1; +unsigned int tux_mode_forbidden = 0 /*S_IXUGO*/; /* do not allow executable (CGI) files */ +unsigned int tux_mode_allowed = S_IROTH; /* allow access if read-other is set */ +unsigned int tux_virtual_server = 0; +unsigned int tux_ftp_virtual_server = 0; +unsigned int mass_hosting_hash = 0; +unsigned int strip_host_tail = 0; +unsigned int tux_max_object_size = 0; +unsigned int log_cpu_mask = ~0; +unsigned int tux_compression = 0; +unsigned int tux_noid = 0; +unsigned int tux_cgi_inherit_cpu = 0; +unsigned int tux_cgi_cpu_mask = ~0; +unsigned int tux_zerocopy_header = 1; +unsigned int tux_max_free_requests = 1000; +unsigned int tux_ignore_query = 0; +unsigned int tux_all_userspace = 0; +unsigned int tux_redirect_logging = 1; +unsigned int tux_max_header_len = 3000; +unsigned int tux_referer_logging = 0; +unsigned int tux_generate_etags = 1; +unsigned int tux_generate_last_mod = 1; +unsigned int tux_generate_cache_control = 1; +unsigned int tux_ip_logging = 1; +unsigned int tux_ftp_wait_close = 1; +unsigned int tux_ftp_log_retr_only = 0; +unsigned int tux_hide_unreadable = 1; +unsigned int tux_http_dir_indexing = 0; +unsigned int tux_log_incomplete = 0; +unsigned int tux_cpu_offset = 0; +unsigned int tux_ftp_login_message = 0; + +static struct ctl_table_header *tux_table_header; + +static ctl_table tux_table[] = { + { NET_TUX_DOCROOT, + "documentroot", + &tux_common_docroot, + sizeof(tux_common_docroot), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_DOCROOT, + "http_subdocroot", + &tux_http_subdocroot, + sizeof(tux_http_subdocroot), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_DOCROOT, + "ftp_subdocroot", + &tux_ftp_subdocroot, + sizeof(tux_ftp_subdocroot), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_LOGFILE, + "logfile", + &tux_logfile, + sizeof(tux_logfile), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_THREADS, + "threads", + &tux_threads, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_KEEPALIVE_TIMEOUT, + "keepalive_timeout", + &tux_keepalive_timeout, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_KEEPALIVE_BW, + "max_output_bandwidth", + &tux_max_output_bandwidth, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_DEFER_ACCEPT, + "defer_accept", + &tux_defer_accept, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_BACKLOG, + "max_backlog", + &tux_max_backlog, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_CONNECT, + "max_connect", + &tux_max_connect, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_KEEPALIVES, + "max_keepalives", + &tux_max_keepalives, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MODE_FORBIDDEN, + "mode_forbidden", + &tux_mode_forbidden, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MODE_ALLOWED, + "mode_allowed", + &tux_mode_allowed, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CGI_UID, + "cgi_uid", + &tux_cgi_uid, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CGI_GID, + "cgi_gid", + &tux_cgi_gid, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CGIROOT, + "cgiroot", + &tux_cgiroot, + sizeof(tux_cgiroot), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_404_PAGE, + "404_page", + &tux_404_page, + sizeof(tux_404_page), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_404_PAGE, + "default_vhost", + &tux_default_vhost, + sizeof(tux_default_vhost), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_404_PAGE, + "extra_html_header", + &tux_extra_html_header, + sizeof(tux_extra_html_header), + 0644, + NULL, + proc_dostring, + &sysctl_string, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "extra_html_header_size", + &tux_extra_html_header_size, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "clientport", + &tux_clientport, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "generate_etags", + &tux_generate_etags, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "generate_last_mod", + &tux_generate_last_mod, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "generate_cache_control", + &tux_generate_cache_control, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "ip_logging", + &tux_ip_logging, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "ftp_wait_close", + &tux_ftp_wait_close, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "ftp_log_retr_only", + &tux_ftp_log_retr_only, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "http_dir_indexing", + &tux_http_dir_indexing, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "hide_unreadable", + &tux_hide_unreadable, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CLIENTPORT, + "log_incomplete", + &tux_log_incomplete, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_LOGGING, + "TDprintk", + &tux_TDprintk, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_LOGGING, + "Dprintk", + &tux_Dprintk, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, +#if TUX_DPRINTK +#endif + { NET_TUX_LOGGING, + "logging", + &tux_logging, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_LOGENTRY_ALIGN_ORDER, + "logentry_align_order", + &tux_logentry_align_order, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_ACK_PINGPONG, + "ack_pingpong", + &tux_ack_pingpong, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_PUSH_ALL, + "push_all", + &tux_push_all, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_ZEROCOPY_PARSE, + "zerocopy_parse", + &tux_zerocopy_parse, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_VIRTUAL_SERVER, + "virtual_server", + &tux_virtual_server, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_VIRTUAL_SERVER, + "mass_hosting_hash", + &mass_hosting_hash, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_VIRTUAL_SERVER, + "strip_host_tail", + &strip_host_tail, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_VIRTUAL_SERVER, + "ftp_virtual_server", + &tux_ftp_virtual_server, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_OBJECT_SIZE, + "max_object_size", + &tux_max_object_size, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_COMPRESSION, + "compression", + &tux_compression, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_NOID, + "noid", + &tux_noid, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CGI_INHERIT_CPU, + "cgi_inherit_cpu", + &tux_cgi_inherit_cpu, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_CGI_CPU_MASK, + "cgi_cpu_mask", + &tux_cgi_cpu_mask, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_ZEROCOPY_HEADER, + "zerocopy_header", + &tux_zerocopy_header, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_ZEROCOPY_SENDFILE, + "zerocopy_sendfile", + &tux_zerocopy_sendfile, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_FREE_REQUESTS, + "max_free_requests", + &tux_max_free_requests, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_ALL_USERSPACE, + "all_userspace", + &tux_all_userspace, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_REDIRECT_LOGGING, + "redirect_logging", + &tux_redirect_logging, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_IGNORE_QUERY, + "ignore_query", + &tux_ignore_query, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_REFERER_LOGGING, + "referer_logging", + &tux_referer_logging, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_REFERER_LOGGING, + "cpu_offset", + &tux_cpu_offset, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_REFERER_LOGGING, + "ftp_login_message", + &tux_ftp_login_message, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + { NET_TUX_MAX_HEADER_LEN, + "max_header_len", + &tux_max_header_len, + sizeof(int), + 0644, + NULL, + proc_dointvec, + &sysctl_intvec, + NULL, + NULL, + NULL + }, + {0,0,0,0,0,0,0,0,0,0,0} }; + + +static ctl_table tux_dir_table[] = { + {NET_TUX, "tux", NULL, 0, 0555, tux_table,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0} +}; + +static ctl_table tux_root_table[] = { + {CTL_NET, "net", NULL, 0, 0555, tux_dir_table,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0} +}; + + +static struct proc_dir_entry * root_tux_dir; +static struct proc_dir_entry * log_cpu_mask_entry; +static struct proc_dir_entry * stat_entry; +static struct proc_dir_entry * tux_dir [CONFIG_TUX_NUMTHREADS]; +static struct proc_dir_entry * listen_dir [CONFIG_TUX_NUMTHREADS]; + +tux_socket_t tux_listen [CONFIG_TUX_NUMTHREADS][CONFIG_TUX_NUMSOCKETS] = + { [0 ... CONFIG_TUX_NUMTHREADS-1] = { {&tux_proto_http, 0, 80, NULL}, } }; + +#define HEX_DIGITS 8 + +static int hex_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", *(unsigned int *)data); +} + +static int hex_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char hexnum [HEX_DIGITS]; + unsigned int new_value; + unsigned int i, full_count = count; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are the same. + */ + new_value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + new_value = (new_value << 4) | c; + } +out: + *(int *)data = new_value; + + return full_count; +} + +#define LINE_SIZE 1024 +#define LINE_MASK (LINE_SIZE-1) + +static int print_request_stats (threadinfo_t *ti, char *page, unsigned int skip_count, unsigned int max_count) +{ + struct list_head *head, *curr; + tux_req_t *req; + unsigned int count = 0, size, line_off, len; + char stat_line [LINE_SIZE]; + + if (!max_count) + BUG(); + + head = &ti->all_requests; + curr = head->next; + + while (curr != head) { + req = list_entry(curr, tux_req_t, all); + curr = curr->next; + count++; + if (count <= skip_count) + continue; + line_off = 0; +#define SP(x...) \ + line_off += sprintf(stat_line + line_off, x) + + if (req->proto == &tux_proto_http) + SP("0 "); + else + SP("1 "); + + SP("%p ", req); + SP("%d ", req->atom_idx); + if (req->atom_idx >= 1) + SP("%p ", req->atoms[0]); + else + SP("........ "); + if (req->atom_idx >= 2) + SP("%p ", req->atoms[1]); + else + SP("........ "); + if (!list_empty(&req->work)) SP("W"); else SP("."); + if (!list_empty(&req->free)) SP("F"); else SP("."); + if (!list_empty(&req->lru)) SP("L"); else SP("."); + if (req->keep_alive) SP("K"); else SP("."); + if (req->idle_input) SP("I"); else SP("."); + if (timer_pending(&req->keepalive_timer)) + SP("T(%lu/%lu)",jiffies,req->keepalive_timer.expires); else SP("."); + if (req->wait_output_space) SP("O"); else SP("."); + if (timer_pending(&req->output_timer)) + SP("T"); else SP("."); + SP(" %d ", req->error); + SP(" %d ", req->status); + +#define SP_HOST(ip,port) \ + SP("%d.%d.%d.%d:%d ",NIPQUAD(ip),port) + + if (req->sock) { + if (req->sock->sk) + SP("%d:", req->sock->sk->sk_state); + else + SP("-2:"); + } else + SP("-1:"); + SP_HOST(req->client_addr, req->client_port); + + SP("%Ld ", req->total_file_len); + SP("%Ld ", req->in_file.f_pos); + if (req->proto == &tux_proto_http) { + SP("%d ", req->method); + SP("%d ", req->version); + } + if (req->proto == &tux_proto_ftp) { + SP("%d ", req->ftp_command); + if (req->data_sock) { + if (req->data_sock->sk) + SP("%d:",req->data_sock->sk->sk_state); + else + SP("-2:"); + if (req->data_sock->sk) + SP_HOST(inet_sk(req->data_sock->sk)->daddr, + inet_sk(req->data_sock->sk)->dport); + else + SP("-1:-1 "); + } else + SP("-1 "); + } + SP("%p/%p %p/%p ", req->sock, req->sock ? req->sock->sk : (void *)-1, req->data_sock, req->data_sock ? req->data_sock->sk : (void *)-1); + + SP("%d\n", req->parsed_len); + len = req->headers_len; + if (len > 500) + len = 500; + SP("\n%d\n", len); + memcpy(stat_line + line_off, req->headers, len); + line_off += len; + len = req->objectname_len; + if (len > 100) + len = 100; + SP("\n%d\n", len); + memcpy(stat_line + line_off, req->objectname, len); + line_off += len; + SP("\n\n"); + if (line_off >= LINE_SIZE) + BUG(); + Dprintk("printing req %p, count %d, page %p: {%s}.\n", req, count, page, stat_line); + size = sprintf(page, "%-*s\n", LINE_SIZE-1, stat_line); + if (size != LINE_SIZE) + BUG(); + page += LINE_SIZE; + if (count-skip_count >= max_count) + break; + } + + Dprintk("count: %d.\n", count-skip_count); + return count - skip_count; +} + +static int stat_read_proc (char *page, char **start, off_t off, + int max_size, int *eof, void *data) +{ + unsigned int i, nr_total = 0, nr, nr_off, nr_skip, size = 0, nr_wanted; + + Dprintk("START, page: %p, max_size: %d, off: %ld.\n", page, max_size, off); + *eof = 1; + if (max_size & LINE_MASK) + return 0; + if (off & LINE_MASK) + return 0; + if (!max_size) + return 0; + + nr_off = off/LINE_SIZE; + + for (i = 0; i < nr_tux_threads; i++) { + threadinfo_t *ti = threadinfo + i; + spin_lock_irq(&ti->work_lock); + nr = ti->nr_requests; + Dprintk("ti: %p, nr: %d, nr_total: %d, nr_off: %d.\n", ti, nr, nr_total, nr_off); + nr_total += nr; + if (nr_off >= nr_total) { + spin_unlock_irq(&ti->work_lock); + continue; + } + nr_skip = nr_off - (nr_total - nr); + nr_wanted = (max_size-size) / LINE_SIZE; + Dprintk("nr_skip: %d, nr_wanted: %d.\n", nr_skip, nr_wanted); + nr = print_request_stats(ti, page + size, nr_skip, nr_wanted); + spin_unlock_irq(&ti->work_lock); + nr_off += nr; + size += nr * LINE_SIZE; + Dprintk("ret: %d requests, size: %d.\n", nr, size); + if (size > max_size) + BUG(); + if (size == max_size) + break; + } + Dprintk("DONE: size: %d.\n", size); + + *start = page; + + if (size) + *eof = 0; + return size; +} + +static int stat_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + return -EINVAL; +} + +#define MAX_STRING "http://255.255.255.255:65535" +#define MAX_STRINGLEN (sizeof(MAX_STRING)) + +#define INACTIVE_1 "[inactive]\n" +#define INACTIVE_2 "0\n" + +static int listen_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + tux_socket_t *listen = data; + + if (count < MAX_STRINGLEN) + return -EINVAL; + + if (!listen->proto) + return sprintf(page, INACTIVE_1); + + return sprintf (page, "%s://%u.%u.%u.%u:%hu\n", listen->proto->name, + HIPQUAD(listen->ip), listen->port); +} + +static int listen_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char string [MAX_STRINGLEN]; + unsigned int d1, d2, d3, d4; + unsigned short port; + tux_socket_t *listen = data; + + if (!count) + return -EINVAL; + if (count > MAX_STRINGLEN) + count = MAX_STRINGLEN; + if (copy_from_user(string, buffer, count)) + return -EFAULT; + string[count] = 0; + + if (!strcmp(string, INACTIVE_1) || !strcmp(string, INACTIVE_2)) { + listen->proto = NULL; + listen->ip = 0; + listen->port = 0; + return count; + } + +#define MK_IP(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d) + + if (sscanf(string, "http://%u.%u.%u.%u:%hu\n", + &d1, &d2, &d3, &d4, &port) == 5) { + listen->ip = MK_IP(d1,d2,d3,d4); + listen->port = port; + listen->proto = &tux_proto_http; + return count; + } + + if (sscanf(string, "ftp://%u.%u.%u.%u:%hu\n", + &d1, &d2, &d3, &d4, &port) == 5) { + listen->ip = MK_IP(d1,d2,d3,d4); + listen->port = port; + listen->proto = &tux_proto_ftp; + return count; + } + printk(KERN_ERR "tux: invalid listen-socket parameters: %s\n", string); + return -EINVAL; +} + +#define MAX_NAMELEN 10 + +static void register_tux_proc (unsigned int nr) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + int i; + + if (!root_tux_dir) + TUX_BUG(); + + sprintf(name, "%d", nr); + + /* create /proc/net/tux/1234/ */ + tux_dir[nr] = proc_mkdir(name, root_tux_dir); + + /* create /proc/net/tux/1234/listen/ */ + listen_dir[nr] = proc_mkdir("listen", tux_dir[nr]); + + /* create /proc/net/tux/1234/listen/ */ + for (i = 0; i < CONFIG_TUX_NUMSOCKETS; i++) { + sprintf(name, "%d", i); + entry = create_proc_entry(name, 0700, listen_dir[nr]); + + entry->nlink = 1; + entry->data = (void *)(tux_listen[nr] + i); + entry->read_proc = listen_read_proc; + entry->write_proc = listen_write_proc; + tux_listen[nr][i].entry = entry; + } +} + +static void unregister_tux_proc (unsigned int nr) +{ + int i; + + for (i = 0; i < CONFIG_TUX_NUMSOCKETS; i++) { + remove_proc_entry(tux_listen[nr][i].entry->name,listen_dir[nr]); + tux_listen[nr][i].entry = NULL; + } + + remove_proc_entry(listen_dir[nr]->name, tux_dir[nr]); + + remove_proc_entry(tux_dir[nr]->name, root_tux_dir); +} + +static void cleanup_tux_proc (void) +{ + int i; + + Dprintk("cleaning up /proc/net/tux/\n"); + + for (i = 0; i < CONFIG_TUX_NUMTHREADS; i++) + unregister_tux_proc(i); + remove_proc_entry(stat_entry->name, root_tux_dir); + remove_proc_entry(log_cpu_mask_entry->name, root_tux_dir); + remove_proc_entry(root_tux_dir->name, proc_net); +} + +static void init_tux_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + if (root_tux_dir) + return; + + /* create /proc/net/tux */ + root_tux_dir = proc_mkdir("tux", proc_net); + + entry = create_proc_entry("log_cpu_mask", 0700, root_tux_dir); + + entry->nlink = 1; + entry->data = (void *)&log_cpu_mask; + entry->read_proc = hex_read_proc; + entry->write_proc = hex_write_proc; + + log_cpu_mask_entry = entry; + + entry = create_proc_entry("stat", 0700, root_tux_dir); + + entry->nlink = 1; + entry->data = NULL; + entry->read_proc = stat_read_proc; + entry->write_proc = stat_write_proc; + + stat_entry = entry; + + /* + * Create entries for all existing threads. + */ + for (i = 0; i < CONFIG_TUX_NUMTHREADS; i++) + register_tux_proc(i); +} + +void start_sysctl(void) +{ + init_tux_proc(); + tux_table_header = register_sysctl_table(tux_root_table,1); +} + +void end_sysctl(void) +{ + cleanup_tux_proc(); + unregister_sysctl_table(tux_table_header); +} + +#if CONFIG_SMP +void mask_to_cpumask(unsigned int mask, cpumask_t *cpu_mask) +{ + + unsigned int bit_mask, i; + + bit_mask = 1 << 31; + + for (i=NR_CPUS-1; i--; i >= 0) { + if(mask & bit_mask) + cpu_set(i, *cpu_mask); + else + cpu_clear(i, *cpu_mask); + mask <<= 1; + } + +} +#endif + diff --git a/net/tux/proto_ftp.c b/net/tux/proto_ftp.c new file mode 100644 index 000000000..fbb9d8eef --- /dev/null +++ b/net/tux/proto_ftp.c @@ -0,0 +1,1549 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * ftp_proto.c: FTP application protocol support + */ + +#define __KERNEL_SYSCALLS__ +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#define HELLO "220 Linux/TUX 3.0 FTP server welcomes you!\r\n" +#define WRITE_DONE "226 Transfer complete.\r\n" +#define BAD_FILENAME "550 No such file or directory.\r\n" +#define GOOD_DIR "250 CWD command successful.\r\n" +#define LIST_ERR "503 LIST without PORT! Closing connection.\r\n" +#define LIST_ERR_MEM "503 LIST could not allocate memory! Closing connection.\r\n" +#define WRITE_FILE "150 Opening BINARY mode data connection.\r\n" +#define WRITE_LIST "150 Opening ASCII mode data connection.\r\n" +#define RETR_ERR "503 RETR without PORT! Closing connection.\r\n" +#define PORT_OK "200 PORT command successful.\r\n" +#define LOGIN_OK "230-There are currently %d users logged in, out of %d maximum.\r\n230-Bandwidth served by TUX currently: %d KB/sec\r\n230 TUX Guest login ok.\r\n" +#define LOGIN_OK_ONE "230-There is currently 1 user logged in, out of %d maximum.\r\n230-Bandwidth served by TUX currently: %d KB/sec\r\n230 TUX Guest login ok.\r\n" +#define LOGIN_OK_PASS "230 TUX Guest login ok.\r\n" +#define LOGIN_FORBIDDEN "530 Sorry, Login Denied!\r\n" +#define TYPE_OK "200 Type set to I.\r\n" +#define BYE "221 Thank You for using TUX!\r\n" +#define NOT_IMPLEMENTED "502 Command not implemented.\r\n" +#define CLOSE_2 "221 Cannot handle request, closing connection!\r\n" +#define CLOSE "500 Unknown command.\r\n" +#define CLOSE_TIMEOUT "421 Timeout, closing connection!\r\n" +#define LINUX_SYST "215 UNIX Type: L8, Linux/TUX/3.0\r\n" +#define COMMAND_OK "200 Command OK.\r\n" +#define REST_OK "350 Restart offset OK.\r\n" +#define WRITE_ABORTED "426 Transfer aborted, data connection closed.\r\n" +#define SITE "214 No SITE commands are recognized.\r\n" + +#define INTERVAL 10 + +unsigned long last_measurement; +unsigned int ftp_bytes_sent; +unsigned int ftp_bandwidth; + +static void __update_bandwidth (tux_req_t *req, unsigned int bytes) +{ + /* + * Bandwidth measurement. Not completely accurate, + * but it's good enough and lightweight enough. + */ + if (jiffies >= last_measurement + INTERVAL*HZ) { + ftp_bandwidth = (ftp_bytes_sent + 1023)/INTERVAL/1024; + ftp_bytes_sent = 0; + last_measurement = jiffies; + } + if (bytes) + atomic_add(bytes, (atomic_t *)&ftp_bytes_sent); + Dprintk("update_bandwidth(%p,%d), bytes_sent: %d, bandwidth: %d.\n", + req, bytes, ftp_bytes_sent, ftp_bandwidth); +} + +#define update_bandwidth(req,bytes) \ + do { \ + if (unlikely(tux_ftp_login_message)) \ + __update_bandwidth(req, bytes); \ + } while (0) + +static inline void __ftp_send_async_message (tux_req_t *req, + const char *message, int status, unsigned int size) +{ + update_bandwidth(req, size); + __send_async_message(req, message, status, size, 1); +} + +#define ftp_send_async_message(req,str,status) \ + __ftp_send_async_message(req,str,status,sizeof(str)-1) + + +static void ftp_flush_req (tux_req_t *req, int cachemiss) +{ + tux_push_pending(req->sock->sk); + add_req_to_workqueue(req); +} + +static void ftp_execute_command (tux_req_t *req, int cachemiss); + +static void ftp_lookup_vhost (tux_req_t *req, int cachemiss) +{ + struct dentry *dentry; + struct nameidata base; + struct vfsmount *mnt = NULL; + unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC; + char ip[3+1+3+1+3+1+3 + 2]; + + sprintf(ip, "%d.%d.%d.%d", NIPQUAD(inet_sk(req->sock->sk)->rcv_saddr)); + Dprintk("ftp_lookup_vhost(%p, %d, virtual: %d, host: %s.)\n", + req, flag, req->virtual, ip); + + base.flags = LOOKUP_FOLLOW|flag; + base.last_type = LAST_ROOT; + base.dentry = dget(req->proto->main_docroot.dentry); + base.mnt = mntget(req->proto->main_docroot.mnt); + + dentry = __tux_lookup(req, ip, &base, &mnt); + + Dprintk("looked up dentry %p.\n", dentry); + if (dentry && !IS_ERR(dentry) && !dentry->d_inode) + TUX_BUG(); + + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + add_tux_atom(req, ftp_lookup_vhost); + queue_cachemiss(req); + return; + } + goto abort; + } + + req->docroot_dentry = dentry; + req->docroot_mnt = mnt; + + add_tux_atom(req, ftp_execute_command); + add_req_to_workqueue(req); + return; +abort: + if (dentry) { + if (!IS_ERR(dentry)) + dput(dentry); + dentry = NULL; + } + if (mnt) { + if (!IS_ERR(mnt)) + mntput(mnt); + mnt = NULL; + } + req_err(req); + add_req_to_workqueue(req); +} + +static void ftp_got_request (tux_req_t *req) +{ + add_tux_atom(req, parse_request); + add_tux_atom(req, ftp_flush_req); + ftp_send_async_message(req, HELLO, 220); +} + +#define GOTO_ERR { TDprintk("FTP protocol error at: %s:%d\n", \ + __FILE__, __LINE__); goto error; } + +static void zap_data_socket (tux_req_t *req) +{ + if (!req->data_sock) + return; + Dprintk("zapping req %p's data socket %p.\n", req, req->data_sock); + + unlink_tux_data_socket(req); + sock_release(req->data_sock); + req->data_sock = NULL; +} + +static int parse_ftp_message (tux_req_t *req, const int total_len) +{ + int comm, comm1 = 0, comm2 = 0, comm3 = 0, comm4 = 0; + int newline_pos, i; + const char *mess, *curr; + + curr = mess = req->headers; + + Dprintk("FTP parser got %d bytes: --->{%s}<---\n", total_len, curr); + + newline_pos = -1; + for (i = 0; i < total_len; i++, curr++) { + if (!*curr) + GOTO_ERR; + if (!(*curr == '\r') || !(*(curr+1) == '\n')) + continue; + newline_pos = i; + break; + } + Dprintk("Newline pos: %d\n", newline_pos); + if (newline_pos == -1) { + Dprintk("incomplete mess on req %p!\n", req); + return 0; + } + if (newline_pos < 3) + GOTO_ERR; + +#define toup(c) ((((c) >= 'a') && ((c) <= 'z')) ? ((c) + 'A' - 'a') : (c)) + +#define STRING_VAL(c1,c2,c3,c4) \ + (toup(c1) + (toup(c2) << 8) + (toup(c3) << 16) + (toup(c4) << 24)) + +#define STRING_VAL_STR(str) \ + STRING_VAL(str[0], str[1], str[2], str[3]) + + Dprintk("string val (%c%c%c%c): %08x\n", + mess[0], mess[1], mess[2], mess[3], + STRING_VAL_STR(mess)); + +#define PARSE_FTP_COMM(c1,c2,c3,c4,name,num) \ + if (STRING_VAL_STR(mess) == STRING_VAL(c1,c2,c3,c4)) \ + { \ + Dprintk("parsed "#name".\n"); \ + comm##num = FTP_COMM_##name; \ + } + + PARSE_FTP_COMM('A','C','C','T', ACCT,2); + PARSE_FTP_COMM('C','D','U','P', CDUP,3); + PARSE_FTP_COMM('S','M','N','T', SMNT,4); + PARSE_FTP_COMM('Q','U','I','T', QUIT,1); + PARSE_FTP_COMM('R','E','I','N', REIN,2); + PARSE_FTP_COMM('P','A','S','V', PASV,3); + PARSE_FTP_COMM('S','T','R','U', STRU,4); + PARSE_FTP_COMM('S','T','O','R', STOR,2); + PARSE_FTP_COMM('S','T','O','U', STOU,3); + PARSE_FTP_COMM('A','P','P','E', APPE,4); + PARSE_FTP_COMM('A','L','L','O', ALLO,1); + PARSE_FTP_COMM('R','N','F','R', RNFR,2); + PARSE_FTP_COMM('R','N','T','O', RNTO,3); + PARSE_FTP_COMM('A','B','O','R', ABOR,4); + PARSE_FTP_COMM('D','E','L','E', DELE,1); + PARSE_FTP_COMM('R','M','D',' ', RMD, 2); + PARSE_FTP_COMM('M','K','D',' ', MKD, 3); + PARSE_FTP_COMM('P','W','D',' ', PWD, 4); + PARSE_FTP_COMM('S','Y','S','T', SYST,2); + PARSE_FTP_COMM('N','O','O','P', NOOP,3); + PARSE_FTP_COMM('F','E','A','T', FEAT,4); + + comm = comm1 | comm2 | comm3 | comm4; + + if (comm) { + if (newline_pos != 4) + GOTO_ERR; + req->ftp_command = comm; + goto out; + } + + switch (STRING_VAL(mess[0], mess[1], mess[2], mess[3])) { + +#define PARSE_FTP_COMM_3CHAR(c1,c2,c3,name) \ + case STRING_VAL(c1,c2,c3,'\r'): \ + { \ + Dprintk("parsed "#name".\n"); \ + req->ftp_command = FTP_COMM_##name; \ + if (newline_pos != 3) \ + GOTO_ERR; \ + } + +#define PARSE_FTP_3CHAR_COMM_IGNORE(c1,c2,c3,name) \ + case STRING_VAL(c1,c2,c3,' '): \ + { \ + Dprintk("parsed "#name".\n"); \ + req->ftp_command = FTP_COMM_##name; \ + } + +#define PARSE_FTP_COMM_IGNORE(c1,c2,c3,c4,name) \ + case STRING_VAL(c1,c2,c3,c4): \ + { \ + Dprintk("parsed "#name".\n"); \ + req->ftp_command = FTP_COMM_##name; \ + } + +#define PARSE_FTP_3CHAR_COMM_1_FIELD(c1,c2,c3,name,field,field_len,max) \ + case STRING_VAL(c1,c2,c3,' '): \ + { \ + Dprintk("parsed "#name".\n"); \ + req->ftp_command = FTP_COMM_##name; \ + if (newline_pos == 4) \ + GOTO_ERR; \ + if (newline_pos >= 5) { \ + curr = mess + 3; \ + if (*curr++ != ' ') \ + GOTO_ERR; \ + *(field_len) = newline_pos-4; \ + if (*(field_len) >= max) \ + GOTO_ERR; \ + memcpy(field, curr, *(field_len)); \ + (field)[*(field_len)] = 0; \ + } \ + } + +#define PARSE_FTP_COMM_1_FIELD(c1,c2,c3,c4,name,field,field_len,max) \ + case STRING_VAL(c1,c2,c3,c4): \ + { \ + Dprintk("parsed "#name".\n"); \ + req->ftp_command = FTP_COMM_##name; \ + if (newline_pos < 4) \ + GOTO_ERR; \ + if (newline_pos == 4) \ + *(field_len) = 0; \ + else { \ + curr = mess + 4; \ + if (*curr++ != ' ') \ + GOTO_ERR; \ + *(field_len) = newline_pos-5; \ + if (*(field_len) >= max) \ + GOTO_ERR; \ + memcpy(field, curr, *(field_len)); \ + (field)[*(field_len)] = 0; \ + } \ + } + + PARSE_FTP_COMM_1_FIELD('U','S','E','R', USER, + req->username, &req->username_len, + MAX_USERNAME_LEN-1); + if (!req->username_len) + GOTO_ERR; + break; + + { + #define MAX_PASS_LEN 100 + char pass[MAX_PASS_LEN]; + unsigned int pass_len; + PARSE_FTP_COMM_1_FIELD('P','A','S','S', PASS, + pass, &pass_len, + MAX_PASS_LEN-1); + if (!pass_len) + GOTO_ERR; + break; + } + + PARSE_FTP_3CHAR_COMM_1_FIELD('C','W','D', CWD, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (!req->objectname_len) + GOTO_ERR; + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + break; + + PARSE_FTP_COMM_3CHAR('P','W','D', PWD); break; + + { + char type[3]; + unsigned int type_len; + + PARSE_FTP_COMM_1_FIELD('T','Y','P','E', TYPE, + type, &type_len, 2); + if (!type_len) + GOTO_ERR; + if ((type[0] != 'I') && (type[0] != 'A')) + GOTO_ERR; + } + break; + + PARSE_FTP_COMM_1_FIELD('R','E','T','R', RETR, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (!req->objectname_len) { + zap_data_socket(req); + req->ftp_command = FTP_COMM_NONE; + } + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + break; + + PARSE_FTP_COMM_1_FIELD('S','I','Z','E', SIZE, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (!req->objectname_len) + req->ftp_command = FTP_COMM_NONE; + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + break; + + PARSE_FTP_COMM_1_FIELD('M','D','T','M', MDTM, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (!req->objectname_len) + req->ftp_command = FTP_COMM_NONE; + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + break; + + PARSE_FTP_COMM_IGNORE('M','O','D','E', MODE); + break; + + PARSE_FTP_COMM_IGNORE('S','T','A','T', STAT); + break; + + PARSE_FTP_COMM_IGNORE('S','I','T','E', SITE); + break; + + PARSE_FTP_COMM_1_FIELD('L','I','S','T', LIST, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (req->objectname[0] == '-') { + req->objectname_len = 0; + req->objectname[0] = 0; + } + if (req->objectname_len) { + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + } + break; + + PARSE_FTP_COMM_1_FIELD('N','L','S','T', NLST, + req->objectname, &req->objectname_len, + MAX_OBJECTNAME_LEN-1); + if (req->objectname[0] == '-') { + req->objectname_len = 0; + req->objectname[0] = 0; + } + if (req->objectname_len) { + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + } + break; + + PARSE_FTP_COMM_IGNORE('H','E','L','P', HELP); + break; + + PARSE_FTP_COMM_IGNORE('C','L','N','T', CLNT); + break; + +#define IS_NUM(n) (((n) >= '0') && ((n) <= '9')) + +#define GET_DIGIT(curr,n) \ + n += (*curr) - '0'; \ + curr++; \ + if (IS_NUM(*curr)) { \ + n *= 10; + +#define PARSE_PORTNUM(curr,n) \ +do { \ + Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\ + if (!IS_NUM(*curr)) \ + GOTO_ERR; \ + n = 0; \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + }}} \ + if (n > 255) \ + GOTO_ERR; \ + Dprintk("PORT NUM parser:--->{%s}<---\n", curr);\ + Dprintk("PORT NUM parser parsed %d.\n", n); \ +} while (0) + +#define PARSE_NUM(curr,n) \ +do { \ + Dprintk("NUM parser:--->{%s}<---\n", curr); \ + if (!IS_NUM(*curr)) \ + GOTO_ERR; \ + n = 0; \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + GET_DIGIT(curr,n); \ + }}}}}}}}}} \ + Dprintk("NUM parser:--->{%s}<---\n", curr); \ + Dprintk("NUM parser parsed %d.\n", n); \ +} while (0) + + case STRING_VAL('P','O','R','T'): + { + unsigned int h1, h2, h3, h4, p1, p2; + if (req->data_sock) + zap_data_socket(req); + /* + * Minimum size: "PORT 0,0,0,0,0,0", 16 bytes. + */ + if (newline_pos < 16) + GOTO_ERR; + Dprintk("parsed PORT.\n"); + if (req->data_sock) + GOTO_ERR; + curr = mess + 4; + if (*curr++ != ' ') + GOTO_ERR; + PARSE_PORTNUM(curr,h1); + if (*curr++ != ',') + GOTO_ERR; + PARSE_PORTNUM(curr,h2); + if (*curr++ != ',') + GOTO_ERR; + PARSE_PORTNUM(curr,h3); + if (*curr++ != ',') + GOTO_ERR; + PARSE_PORTNUM(curr,h4); + if (*curr++ != ',') + GOTO_ERR; + PARSE_PORTNUM(curr,p1); + if (*curr++ != ',') + GOTO_ERR; + PARSE_PORTNUM(curr,p2); + if (curr-mess != newline_pos) + GOTO_ERR; + req->ftp_command = FTP_COMM_PORT; + req->ftp_user_addr = (h1<<24) + (h2<<16) + (h3<<8) + h4; + req->ftp_user_port = (p1<<8) + p2; + Dprintk("FTP PORT got: %d.%d.%d.%d:%d.\n", + h1, h2, h3, h4, req->ftp_user_port); + Dprintk("FTP user-addr: %08x (htonl: %08x), socket: %08x.\n", + req->ftp_user_addr, htonl(req->ftp_user_addr), + inet_sk(req->sock->sk)->daddr); + /* + * Do not allow redirection of connections, and do + * not allow reserved ports to be accessed. + */ + if (inet_sk(req->sock->sk)->daddr != htonl(req->ftp_user_addr)) + GOTO_ERR; + if (req->ftp_user_port < 1024) + GOTO_ERR; + break; + } + case STRING_VAL('R','E','S','T'): + { + unsigned int offset; + + /* + * Minimum size: "REST 0", 6 bytes. + */ + if (newline_pos < 6) + GOTO_ERR; + Dprintk("parsed REST.\n"); + curr = mess + 4; + if (*curr++ != ' ') + GOTO_ERR; + PARSE_NUM(curr,offset); + if (curr-mess != newline_pos) + GOTO_ERR; + req->ftp_command = FTP_COMM_REST; + req->ftp_offset_start = offset; + Dprintk("FTP REST got: %d bytes offset.\n", offset); + + break; + } + default: + req->ftp_command = FTP_COMM_NONE; + break; + } + +out: + req->parsed_len = newline_pos + 2; + + req->virtual = tux_ftp_virtual_server; + if (req->virtual) + add_tux_atom(req, ftp_lookup_vhost); + else { + req->docroot_dentry = dget(req->proto->main_docroot.dentry); + req->docroot_mnt = mntget(req->proto->main_docroot.mnt); + add_tux_atom(req, ftp_execute_command); + } + + return req->parsed_len; +error: + clear_keepalive(req); + TDprintk("rejecting FTP session!\n"); + TDprintk("mess :--->{%s}<---\n", mess); + TDprintk("mess left:--->{%s}<---\n", curr); + req_err(req); + return -1; +} + +static void ftp_wait_close (tux_req_t *req, int cachemiss); +static void ftp_wait_syn (tux_req_t *req, int cachemiss); + +static int ftp_check_req_err (tux_req_t *req, int cachemiss) +{ + int state = req->sock->sk->sk_state; + int err = req->sock->sk->sk_err | req->error; + int urg = tcp_sk(req->sock->sk)->urg_data; + + if (req->data_sock) { + urg |= tcp_sk(req->data_sock->sk)->urg_data; + state |= req->data_sock->sk->sk_state; + err |= req->data_sock->sk->sk_err; + } + + if ((state <= TCP_SYN_RECV) && !err) { + if (!urg) + return 0; + req->in_file.f_pos = 0; + add_tux_atom(req, flush_request); + zap_data_socket(req); + ftp_send_async_message(req, WRITE_ABORTED, 426); + return 1; + } +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; + if (tux_TDprintk) + dump_stack(); +#endif + req->in_file.f_pos = 0; + TDprintk("zapping, data sock state: %d (err: %d, urg: %d)\n", + state, err, urg); + /* + * We are in the middle of a file transfer, + * zap it immediately: + */ + req->error = TUX_ERROR_CONN_CLOSE; + zap_request(req, cachemiss); + return 1; +} + +void ftp_send_file (tux_req_t *req, int cachemiss) +{ + int ret; + + SET_TIMESTAMP(req->output_timestamp); +repeat: + ret = generic_send_file(req, req->data_sock, cachemiss); + update_bandwidth(req, req->in_file.f_pos - req->prev_pos); + req->prev_pos = req->in_file.f_pos; + + switch (ret) { + case -5: + add_tux_atom(req, ftp_send_file); + output_timeout(req); + break; + case -4: + add_tux_atom(req, ftp_send_file); + if (add_output_space_event(req, req->data_sock)) { + del_tux_atom(req); + goto repeat; + } + break; + case -3: + add_tux_atom(req, ftp_send_file); + queue_cachemiss(req); + break; + case -1: + break; + default: + req->in_file.f_pos = 0; + + if (tux_ftp_wait_close) { + req->data_sock->ops->shutdown(req->data_sock, SEND_SHUTDOWN); + add_tux_atom(req, ftp_wait_close); + add_req_to_workqueue(req); + return; + } + Dprintk("FTP send file req %p finished!\n", req); + zap_data_socket(req); + add_tux_atom(req, ftp_flush_req); + if (req->error) + ftp_send_async_message(req, BAD_FILENAME, 200); + else + ftp_send_async_message(req, WRITE_DONE, 200); + break; + } +} + +#define sk_syn(sk) \ + (!(sk)->sk_err && ((1 << (sk)->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) +#define req_syn(req) \ + (!(req)->error && sk_syn((req)->data_sock->sk)) + +static void ftp_wait_syn (tux_req_t *req, int cachemiss) +{ + Dprintk("ftp_wait_syn in: data socket state %d.\n", req->data_sock->state); + if (req_syn(req)) { + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + spin_unlock_irq(&req->ti->work_lock); + if (req_syn(req)) { + add_tux_atom(req, ftp_wait_syn); + return; + } + unidle_req(req); + } + Dprintk("ftp_wait_syn out: data socket state %d.\n", req->data_sock->state); + add_req_to_workqueue(req); +} + +static void ftp_wait_close (tux_req_t *req, int cachemiss) +{ + struct sock *sk = req->data_sock->sk; + + Dprintk("ftp_wait_close: data socket state %d.\n", sk->sk_state); + + if (!req->error && (sk->sk_state <= TCP_FIN_WAIT1) && !sk->sk_err) { + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + spin_unlock_irq(&req->ti->work_lock); + if (!req->error && (sk->sk_state <= TCP_FIN_WAIT1) && !sk->sk_err) { + add_tux_atom(req, ftp_wait_close); + return; + } + unidle_req(req); + } + zap_data_socket(req); + add_tux_atom(req, ftp_flush_req); + if (req->error) + ftp_send_async_message(req, BAD_FILENAME, 200); + else + ftp_send_async_message(req, WRITE_DONE, 200); +} + +void ftp_get_size (tux_req_t *req, int cachemiss) +{ + char file_size[200]; + int missed, len; + + if (!req->dentry) { + missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC); + if (!missed && !req->dentry) { + ftp_send_async_message(req, BAD_FILENAME, 200); + return; + } + if (missed) { + if (cachemiss) + TUX_BUG(); + add_tux_atom(req, ftp_get_size); + queue_cachemiss(req); + return; + } + } + req->in_file.f_pos = 0; + len = sprintf(file_size, "213 %Li\r\n", req->dentry->d_inode->i_size); + __ftp_send_async_message(req, file_size, 200, len); +} + +void ftp_get_mdtm (tux_req_t *req, int cachemiss) +{ + unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC; + struct dentry *dentry; + struct vfsmount *mnt = NULL; + char file_mdtm[200]; + unsigned int len; + int err; + + dentry = tux_lookup(req, req->objectname, flag, &mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + if (cachemiss) + TUX_BUG(); + add_tux_atom(req, ftp_get_mdtm); + queue_cachemiss(req); + return; + } + goto out_err; + } + err = permission(dentry->d_inode, MAY_READ, NULL); + if (err) + goto out_err_put; + + req->in_file.f_pos = 0; + len = mdtm_time (file_mdtm, dentry->d_inode->i_mtime.tv_sec); + dput(dentry); + mntput(mnt); + __ftp_send_async_message(req, file_mdtm, 200, len); + return; + +out_err_put: + dput(dentry); + mntput(mnt); +out_err: + ftp_send_async_message(req, BAD_FILENAME, 550); +} + +static void ftp_get_file (tux_req_t *req, int cachemiss) +{ + int missed; + + if (!req->dentry) { + missed = lookup_object(req, cachemiss ? 0 : LOOKUP_ATOMIC); + if (!missed && !req->dentry) { + ftp_send_async_message(req, BAD_FILENAME, 200); + return; + } + if (missed) { + if (cachemiss) + TUX_BUG(); + add_tux_atom(req, ftp_get_file); + queue_cachemiss(req); + return; + } + } + Dprintk("ftp_send_file %p, ftp_offset: %Ld, total_len: %Ld.\n", req, req->ftp_offset_start, req->total_file_len); + req->in_file.f_pos = 0; + if (req->ftp_offset_start) { + if (req->ftp_offset_start <= req->total_file_len) { + req->offset_start = req->ftp_offset_start; + req->in_file.f_pos = req->offset_start; + } + req->ftp_offset_start = 0; + } + req->output_len = req->total_file_len - req->offset_start; + req->prev_pos = req->in_file.f_pos; + Dprintk("ftp_send_file %p, f_pos: %Ld (out_len: %Ld).\n", req, req->in_file.f_pos, req->output_len); + add_tux_atom(req, ftp_send_file); + add_tux_atom(req, ftp_wait_syn); + add_tux_atom(req, ftp_flush_req); + ftp_send_async_message(req, WRITE_FILE, 200); +} + +static void __exchange_sockets (tux_req_t *req) +{ + struct socket *tmp; + + tmp = req->data_sock; + req->data_sock = req->sock; + req->sock = tmp; + + req->in_file.f_pos = 0; +} + +static void ftp_do_ls_start (tux_req_t *req, int cachemiss) +{ + Dprintk("ftp_do_ls_start(%p, %d).\n", req, cachemiss); + if (!req->cwd_dentry) + TUX_BUG(); + __exchange_sockets(req); + queue_cachemiss(req); +} + +static void ftp_do_ls_end (tux_req_t *req, int cachemiss) +{ + Dprintk("ftp_do_ls_end(%p, %d).\n", req, cachemiss); + __exchange_sockets(req); + if (tux_ftp_wait_close) { + req->data_sock->ops->shutdown(req->data_sock, SEND_SHUTDOWN); + add_tux_atom(req, ftp_wait_close); + add_req_to_workqueue(req); + return; + } + zap_data_socket(req); + add_tux_atom(req, ftp_flush_req); + if (req->error) + ftp_send_async_message(req, BAD_FILENAME, 200); + else + ftp_send_async_message(req, WRITE_DONE, 200); +} + +static void ftp_chdir (tux_req_t *req, int cachemiss) +{ + unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC; + struct dentry *dentry; + struct vfsmount *mnt = NULL; + int err; + + Dprintk("ftp_chdir(%p, %d, {%s})\n", req, cachemiss, req->objectname); + dentry = tux_lookup(req, req->objectname, flag, &mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + if (cachemiss) + TUX_BUG(); + add_tux_atom(req, ftp_chdir); + queue_cachemiss(req); + return; + } + goto out_err; + } + err = permission(dentry->d_inode, MAY_EXEC, NULL); + if (err) + goto out_err_put; + req->cwd_dentry = dentry; + req->cwd_mnt = mnt; + ftp_send_async_message(req, GOOD_DIR, 200); + return; + +out_err_put: + dput(dentry); + mntput(mnt); +out_err: + ftp_send_async_message(req, BAD_FILENAME, 550); +} + +void ftp_accept_pasv (tux_req_t *req, int cachemiss) +{ + struct socket *sock, *new_sock = NULL; + struct tcp_opt *tp1, *tp2; + int err; + + tp1 = tcp_sk(req->data_sock->sk); + + Dprintk("PASV accept on req %p, accept_queue: %p.\n", + req, tp1->accept_queue); + if (req->error || (req->data_sock->sk->sk_state != TCP_LISTEN)) + goto error; +new_socket: + if (!tp1->accept_queue) { + spin_lock_irq(&req->ti->work_lock); + add_keepalive_timer(req); + if (test_and_set_bit(0, &req->idle_input)) + TUX_BUG(); + spin_unlock_irq(&req->ti->work_lock); + if (!tp1->accept_queue) { + add_tux_atom(req, ftp_accept_pasv); + return; + } + unidle_req(req); + } + new_sock = sock_alloc(); + if (!new_sock) + goto error; + sock = req->data_sock; + new_sock->type = sock->type; + new_sock->ops = sock->ops; + + err = sock->ops->accept(sock, new_sock, O_NONBLOCK); + Dprintk("PASV accept() returned %d (state %d).\n", err, new_sock->sk->sk_state); + if (err < 0) + goto error; + if (new_sock->sk->sk_state != TCP_ESTABLISHED) + goto error; + /* + * Do not allow other clients to steal the FTP connection! + */ + if (inet_sk(new_sock->sk)->daddr != inet_sk(req->sock->sk)->daddr) { + Dprintk("PASV: ugh, unauthorized connect?\n"); + sock_release(new_sock); + new_sock = NULL; + goto new_socket; + } + /* + * Zap the listen socket: + */ + zap_data_socket(req); + + tp2 = tcp_sk(new_sock->sk); + tp2->nonagle = 2; + tp2->ack.pingpong = tux_ack_pingpong; + new_sock->sk->sk_reuse = 1; + sock_set_flag(new_sock->sk, SOCK_URGINLINE); + sock_reset_flag(new_sock->sk, SOCK_LINGER); + + link_tux_data_socket(req, new_sock); + add_req_to_workqueue(req); + return; + +error: + if (new_sock) + sock_release(new_sock); + req_err(req); + zap_data_socket(req); + ftp_send_async_message(req, CLOSE, 500); +} + +static char * ftp_print_dir_line (tux_req_t *req, char *tmp, char *d_name, int d_len, int d_type, struct dentry *dentry, struct inode *inode) +{ + char *string0 = tmp; + unsigned int size; + + if (req->ftp_command == FTP_COMM_NLST) { + memcpy(tmp, d_name, d_len); + tmp += d_len; + *tmp++ = '\r'; + *tmp++ = '\n'; + *tmp = 0; + return tmp; + } + switch (d_type) { + default: + case DT_UNKNOWN: + case DT_WHT: + if (tux_hide_unreadable) + goto out_dput; + *tmp++ = '?'; + break; + + case DT_FIFO: + if (tux_hide_unreadable) + goto out_dput; + *tmp++ = 'p'; + break; + + case DT_CHR: + if (tux_hide_unreadable) + goto out_dput; + *tmp++ = 'c'; + break; + + case DT_DIR: + *tmp++ = 'd'; + break; + + case DT_BLK: + if (tux_hide_unreadable) + goto out_dput; + *tmp++ = 'b'; + break; + + case DT_REG: + *tmp++ = '-'; + break; + + case DT_LNK: + *tmp++ = 'l'; + break; + + case DT_SOCK: + if (tux_hide_unreadable) + goto out_dput; + *tmp++ = 's'; + break; + } + + if (inode->i_mode & S_IRUSR) *tmp++ = 'r'; else *tmp++ = '-'; + if (inode->i_mode & S_IWUSR) *tmp++ = 'w'; else *tmp++ = '-'; + if (inode->i_mode & S_IXUSR) *tmp++ = 'x'; else *tmp++ = '-'; + if (inode->i_mode & S_IRGRP) *tmp++ = 'r'; else *tmp++ = '-'; + if (inode->i_mode & S_IWGRP) *tmp++ = 'w'; else *tmp++ = '-'; + if (inode->i_mode & S_IXGRP) *tmp++ = 'x'; else *tmp++ = '-'; + if (inode->i_mode & S_IROTH) *tmp++ = 'r'; else *tmp++ = '-'; + if (inode->i_mode & S_IWOTH) *tmp++ = 'w'; else *tmp++ = '-'; + if (inode->i_mode & S_IXOTH) *tmp++ = 'x'; else *tmp++ = '-'; + + *tmp++ = ' '; + + size = sprintf(tmp, "%4i %d", inode->i_nlink, inode->i_uid); + tmp += size; + + size = 14 - size; + if (size <= 0) + size = 1; + memset(tmp, ' ', size); + tmp += size; + + size = sprintf(tmp, "%d", inode->i_gid); + tmp += size; + + size = 9 - size; + if (size <= 0) + size = 1; + memset(tmp, ' ', size); + tmp += size; + + tmp += sprintf(tmp, "%8Li", inode->i_size); + *tmp++ = ' '; + + tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp); + *tmp++ = ' '; + + memcpy(tmp, d_name, d_len); + tmp += d_len; + + if (d_type == DT_LNK) { + int len = 0, max_len; + #define ARROW " -> " + + memcpy(tmp, ARROW, sizeof(ARROW)-1); + tmp += sizeof(ARROW)-1; + max_len = MAX_OBJECTNAME_LEN-(tmp-string0); + if (inode->i_op && inode->i_op->readlink) { + mm_segment_t oldmm; + + oldmm = get_fs(); set_fs(KERNEL_DS); + set_fs(KERNEL_DS); + len = inode->i_op->readlink(dentry, tmp, max_len); + set_fs(oldmm); + } + if (len > 0) + tmp += len; + else + Dprintk("hm, readlink() returned %d.\n", len); + } + *tmp++ = '\r'; + *tmp++ = '\n'; + *tmp = 0; + + return tmp; +out_dput: + return NULL; +} + +static void ftp_do_ls_onefile (tux_req_t *req, int cachemiss) +{ + char string0[MAX_OBJECTNAME_LEN+200], *tmp; + + tmp = ftp_print_dir_line(req, string0, req->objectname, req->objectname_len, +DT_REG, req->dentry, req->dentry->d_inode); + if (!tmp) { + req_err(req); + add_req_to_workqueue(req); + return; + } + if (tmp - string0 >= MAX_OBJECTNAME_LEN+200) + BUG(); + __ftp_send_async_message(req, string0, 200, tmp - string0); +} + +static void ftp_lookup_listfile (tux_req_t *req, int cachemiss) +{ + unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC; + struct dentry *dentry; + struct vfsmount *mnt = NULL; + int err; + + Dprintk("ftp_lookup_listfile(%p, %d, {%s})\n", req, cachemiss, req->objectname); + dentry = tux_lookup(req, req->objectname, flag, &mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + if (cachemiss) + TUX_BUG(); + add_tux_atom(req, ftp_lookup_listfile); + queue_cachemiss(req); + return; + } + goto out_err; + } + + if (S_ISDIR(dentry->d_inode->i_mode)) { + err = permission(dentry->d_inode, MAY_EXEC, NULL); + if (err) { + Dprintk("Directory permission error: %d.\n", err); + goto out_err_put; + } + install_req_dentry(req, dentry, mnt); + + add_tux_atom(req, ftp_do_ls_end); + if (!req->cwd_dentry) + TUX_BUG(); + add_tux_atom(req, list_directory); + } else { + install_req_dentry(req, dentry, mnt); + + add_tux_atom(req, ftp_do_ls_end); + add_tux_atom(req, ftp_do_ls_onefile); + } + + add_tux_atom(req, ftp_do_ls_start); + add_tux_atom(req, ftp_wait_syn); + add_tux_atom(req, ftp_flush_req); + ftp_send_async_message(req, WRITE_LIST, 200); + return; + +out_err_put: + dput(dentry); + mntput(mnt); +out_err: + ftp_send_async_message(req, BAD_FILENAME, 550); +} + +static void ftp_execute_command (tux_req_t *req, int cachemiss) +{ + if (!req->parsed_len) + TUX_BUG(); + trunc_headers(req); + req->keep_alive = 1; + + switch (req->ftp_command) { + +#define ABORTED \ + "226 Abort successful.\r\n" + + case FTP_COMM_ABOR: + { + zap_data_socket(req); + ftp_send_async_message(req, ABORTED, 226); + break; + } + + case FTP_COMM_PWD: + { + unsigned int str_len; + char *buf, *path; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) { + req_err(req); + ftp_send_async_message(req, LIST_ERR_MEM, 200); + GOTO_ERR; + } + + if (!req->cwd_dentry) { + req->cwd_dentry = dget(req->docroot_dentry); + req->cwd_mnt = mntget(req->docroot_mnt); + } + +// "257 "/" is current directory.\r\n" + +#define PART_1 "257 \"" +#define PART_1_LEN (sizeof(PART_1)-1) + +#define PART_3 "\" is current directory.\r\n" +#define PART_3_LEN sizeof(PART_3) + + path = tux_print_path(req, req->cwd_dentry, req->cwd_mnt, + buf+PART_1_LEN, PAGE_SIZE - PART_3_LEN - PART_1_LEN); + + if (path < buf + PART_1_LEN) + BUG(); + + memcpy(path - PART_1_LEN, PART_1, PART_1_LEN); + memcpy(buf + PAGE_SIZE-PART_3_LEN-1, PART_3, PART_3_LEN); + str_len = buf + PAGE_SIZE-1 - (path - PART_1_LEN) - 1; + + __ftp_send_async_message(req, path - PART_1_LEN, 226, str_len); + free_page((unsigned long)buf); + break; + } + + case FTP_COMM_CDUP: + { + memcpy(req->objectname, "..", 3); + req->objectname_len = 2; + req->uri_str = req->objectname; + req->uri_len = req->objectname_len; + + // fall through to CWD: + } + case FTP_COMM_CWD: + { + ftp_chdir(req, cachemiss); + break; + } + + case FTP_COMM_NLST: + case FTP_COMM_LIST: + { + if (!req->data_sock) { + req_err(req); + ftp_send_async_message(req, LIST_ERR, 200); + GOTO_ERR; + } + if (req->dentry) + TUX_BUG(); + if (!req->cwd_dentry) { + req->cwd_dentry = dget(req->docroot_dentry); + req->cwd_mnt = mntget(req->docroot_mnt); + } + if (req->objectname_len) + ftp_lookup_listfile(req, cachemiss); + else { + dget(req->cwd_dentry); + mntget(req->cwd_mnt); + install_req_dentry(req, req->cwd_dentry, req->cwd_mnt); + if (!req->dentry) + TUX_BUG(); + add_tux_atom(req, ftp_do_ls_end); + if (!req->cwd_dentry) + TUX_BUG(); + add_tux_atom(req, list_directory); + add_tux_atom(req, ftp_do_ls_start); + add_tux_atom(req, ftp_wait_syn); + add_tux_atom(req, ftp_flush_req); + ftp_send_async_message(req, WRITE_LIST, 200); + } + break; + } + + case FTP_COMM_RETR: + { + if (!req->data_sock) { + req_err(req); + ftp_send_async_message(req, RETR_ERR, 200); + GOTO_ERR; + } + ftp_get_file(req, cachemiss); + break; + } + + case FTP_COMM_SIZE: + { + ftp_get_size(req, cachemiss); + break; + } + + case FTP_COMM_MDTM: + { + ftp_get_mdtm(req, cachemiss); + break; + } + + case FTP_COMM_PASV: + { + char buf [36 + 4*3 + 5 + 10]; + struct socket *data_sock; + struct sockaddr_in addr; + unsigned int str_len; + struct tcp_opt *tp; + u32 local_addr; + int err; + + if (req->data_sock) + zap_data_socket(req); + /* + * Create FTP data connection to client: + */ + err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock); + if (err < 0) { + Dprintk("sock create err: %d\n", err); + req_err(req); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + + local_addr = inet_sk(req->sock->sk)->rcv_saddr; + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = local_addr; + Dprintk("client address: (%d,%d,%d,%d).\n", + NIPQUAD(inet_sk(req->sock->sk)->daddr)); + + data_sock->sk->sk_reuse = 1; + sock_set_flag(data_sock->sk, SOCK_URGINLINE); + sock_reset_flag(data_sock->sk, SOCK_LINGER); + + err = data_sock->ops->bind(data_sock, + (struct sockaddr*)&addr, sizeof(addr)); + tp = tcp_sk(data_sock->sk); + tp->nonagle = 2; + Dprintk("PASV bind() ret: %d.\n", err); + if (err < 0) { + req_err(req); + sock_release(data_sock); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + + tp->ack.pingpong = tux_ack_pingpong; + + if (!tux_keepalive_timeout) + tp->linger2 = 0; + else + tp->linger2 = tux_keepalive_timeout * HZ; + + err = data_sock->ops->listen(data_sock, 1); + Dprintk("PASV listen() ret: %d\n", err); + if (err) { + req_err(req); + sock_release(data_sock); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + link_tux_data_socket(req, data_sock); + + Dprintk("FTP PASV listen sock state: %d, sk state: %d\n", + data_sock->state, data_sock->sk->sk_state); + + str_len = sprintf(buf, + "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", + NIPQUAD(local_addr), + ntohs(inet_sk(data_sock->sk)->sport) / 256, + ntohs(inet_sk(data_sock->sk)->sport) & 255 ); + Dprintk("PASV mess: {%s}\n", buf); + + add_tux_atom(req, ftp_accept_pasv); + add_tux_atom(req, ftp_flush_req); + __ftp_send_async_message(req, buf, 227, str_len); + break; + } + + case FTP_COMM_PORT: + { + struct socket *data_sock; + struct sockaddr_in addr; + kernel_cap_t saved_cap; + u32 local_addr; + int err; + + /* + * Create FTP data connection to client: + */ + err = sock_create(AF_INET, SOCK_STREAM, IPPROTO_IP, &data_sock); + if (err < 0) { + Dprintk("sock create err: %d\n", err); + req_err(req); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + + local_addr = inet_sk(req->sock->sk)->rcv_saddr; + addr.sin_family = AF_INET; + addr.sin_port = htons(20); + addr.sin_addr.s_addr = local_addr; + + Dprintk("data socket address: (%d,%d,%d,%d).\n", + NIPQUAD(local_addr)); + + data_sock->sk->sk_reuse = 1; + sock_set_flag(data_sock->sk, SOCK_URGINLINE); + sock_reset_flag(data_sock->sk, SOCK_LINGER); + + saved_cap = current->cap_effective; + cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE); + err = data_sock->ops->bind(data_sock, + (struct sockaddr*)&addr, sizeof(addr)); + current->cap_effective = saved_cap; + + Dprintk("ACTIVE bind() ret: %d.\n", err); + if (err) { + sock_release(data_sock); + req_err(req); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + tcp_sk(data_sock->sk)->nonagle = 2; + + link_tux_data_socket(req, data_sock); + + addr.sin_family = AF_INET; + addr.sin_port = htons(req->ftp_user_port); + addr.sin_addr.s_addr = htonl(req->ftp_user_addr); + + err = data_sock->ops->connect(data_sock, (struct sockaddr *) &addr, sizeof(addr), O_RDWR|O_NONBLOCK); + if (err && (err != -EINPROGRESS)) { + Dprintk("connect error: %d\n", err); + zap_data_socket(req); + req_err(req); + ftp_send_async_message(req, CLOSE, 500); + GOTO_ERR; + } + Dprintk("FTP data sock state: %d, sk state: %d\n", data_sock->state, data_sock->sk->sk_state); + ftp_send_async_message(req, PORT_OK, 200); + break; + } + + case FTP_COMM_USER: + { + if (!strcmp(req->username, "ftp") + || !strcmp(req->username, "FTP") + || !strcmp(req->username, "anonymous") + || !strcmp(req->username, "ANONYMOUS")) { + unsigned int str_len; + char login_ok [200]; + + if (!tux_ftp_login_message) { + ftp_send_async_message(req, LOGIN_OK_PASS, 230); + break; + } + update_bandwidth(req, 0); /* get current bandwidth */ + if (nr_requests_used() == 1) + str_len = sprintf(login_ok, LOGIN_OK_ONE, + tux_max_connect, ftp_bandwidth); + else + str_len = sprintf(login_ok, LOGIN_OK, + nr_requests_used(), tux_max_connect, ftp_bandwidth); + __ftp_send_async_message(req, login_ok, 200, str_len); + } else { + clear_keepalive(req); + ftp_send_async_message(req, LOGIN_FORBIDDEN, 530); + } + break; + } + case FTP_COMM_PASS: + { + ftp_send_async_message(req, LOGIN_OK_PASS, 230); + break; + } + case FTP_COMM_SITE: + { + ftp_send_async_message(req, SITE, 214); + break; + } + case FTP_COMM_SYST: + { + ftp_send_async_message(req, LINUX_SYST, 200); + break; + } + case FTP_COMM_TYPE: + { + ftp_send_async_message(req, TYPE_OK, 200); + break; + } +#define EXTRA_FEATURES "211-Extensions supported:\r\n SIZE\r\n MDTM\r\n211 End\r\n" + + case FTP_COMM_FEAT: + { + ftp_send_async_message(req, EXTRA_FEATURES, 211); + break; + } + case FTP_COMM_HELP: + case FTP_COMM_CLNT: + case FTP_COMM_NOOP: + { + ftp_send_async_message(req, COMMAND_OK, 200); + break; + } + case FTP_COMM_REST: + { + ftp_send_async_message(req, REST_OK, 200); + break; + } + case FTP_COMM_QUIT: + { + clear_keepalive(req); + ftp_send_async_message(req, BYE, 200); + break; + } + + default: + { + req->keep_alive = 1; + ftp_send_async_message(req, CLOSE, 500); + break; + } + } + return; +error: + Dprintk("rejecting FTP session!\n"); + return; +} + + +static void ftp_timeout (tux_req_t *req, int cachemiss) +{ + Dprintk("called ftp_timeout(%p)\n", req); + if (req->error != TUX_ERROR_CONN_TIMEOUT) + TUX_BUG(); + ftp_send_async_message(req, CLOSE_TIMEOUT, 421); +} + +static void ftp_close (tux_req_t *req, int cachemiss) +{ + Dprintk("called ftp_close(%p)\n", req); + ftp_send_async_message(req, CLOSE, 500); +} + +static void ftp_pre_log (tux_req_t *req) +{ + if (tux_ftp_log_retr_only && (req->ftp_command != FTP_COMM_RETR)) + req->status = 0; + else + req->status = req->ftp_command; +} + +tux_proto_t tux_proto_ftp = { + defer_accept: 0, + can_redirect: 0, + got_request: ftp_got_request, + parse_message: parse_ftp_message, + illegal_request: ftp_close, + request_timeout: ftp_timeout, + pre_log: ftp_pre_log, + check_req_err: ftp_check_req_err, + print_dir_line: ftp_print_dir_line, + name: "ftp", +}; + diff --git a/net/tux/proto_http.c b/net/tux/proto_http.c new file mode 100644 index 000000000..192dd4f08 --- /dev/null +++ b/net/tux/proto_http.c @@ -0,0 +1,2199 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * proto_http.c: HTTP application protocol support + * + * Right now we detect simple GET headers, anything more + * subtle gets redirected to secondary server port. + */ + +#include +#include "parser.h" + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +/* + * Parse the HTTP message and put results into the request structure. + * CISAPI extensions do not see the actual message buffer. + * + * Any perceived irregularity is honored with a redirect to the + * secondary server - which in most cases should be Apache. So + * if TUX gets confused by some strange request we fall back + * to Apache to be RFC-correct. + * + * The parser is 'optimistic', ie. it's optimized for the case where + * the whole message is available and correct. The parser is also + * supposed to be 'robust', ie. it can be called multiple times with + * an incomplete message, as new packets arrive. + */ + +static inline int TOHEX (char c) +{ + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + c = -1; + } + return c; +} + +/* + * This function determines whether the client supports + * gzip-type content-encoding. + */ +static int may_gzip (const char *str, int len) +{ + const char *tmp, *curr; + int i; + + if (len <= 4) + return 0; + tmp = str; + for (i = 0; i <= len-6; i++) { + Dprintk("gzip-checking: {%s}\n", tmp); + if (memcmp(tmp, " gzip", 5)) { + tmp++; + continue; + } + curr = tmp + 5; + + if (*curr == ',' || *curr == '\r') + return 1; + if (memcmp(curr, ";q=", 3)) + return 0; + curr += 3; + /* + * Every qvalue except explicitly zero is accepted. + * Zero values are "q=0.0", "q=0.00", "q=0.000". + * Parsing is optimized. + */ + if (*curr == '0') { + curr += 2; + if (*curr == '0') { + curr++; + if (*curr == ' ' || *curr == '\r') + return 0; + if (*curr == '0') { + curr++; + if (*curr == ' ' || *curr == '\r') + return 0; + if (*curr == '0') { + curr++; + if (*curr == ' ' || + *curr == '\r') + return 0; + } + } + } + } + return 1; + } + return 0; +} + +/* + * This function strips off 'strip_host_tail' number of hostname + * components from the tail of the hostname. + * + * Eg. with a value of '1', the "somesite.hosting.com" hostname gets + * transformed into the "somesite" string. + */ +static void strip_hostname(tux_req_t *req) +{ + int strip = strip_host_tail; + int left = req->host_len; + int component = 0; + + if (!strip || !left) + return; + + while (--left) { + if (req->host[left] != '.') + continue; + if (++component == strip) + break; + } + if (!left) + return; + req->host[left] = 0; + req->host_len = left; +} + +static void http_lookup_vhost (tux_req_t *req, int cachemiss); +static void http_process_message (tux_req_t *req, int cachemiss); + +int parse_http_message (tux_req_t *req, const int total_len) +{ + int hexhex = 0, hex_val_0 = 0, hex_val_1 = 0; + const char *curr, *uri, *message; + unsigned int objectname_len, left; + unsigned int have_r = 0; + char c; + + left = total_len; + message = req->headers; + Dprintk("parsing request:\n---\n%s\n---\n", message); +/* + * RFC 2616, 5.1: + * + * Request-Line = Method SP Request-URI SP HTTP-Version CRLF + */ + + if (!total_len) + TUX_BUG(); + + curr = message; + +#define GOTO_INCOMPLETE do { Dprintk("incomplete at %s:%d.\n", __FILE__, __LINE__); goto incomplete_message; } while (0) +#define GOTO_REDIR do { TDprintk("redirect secondary at %s:%d.\n", __FILE__, __LINE__); goto error; } while (0) + +#define PRINT_MESSAGE_LEFT \ + Dprintk("message left (%d) at %s:%d:\n--->{%s}<---\n", left, __FILE__, __LINE__, curr) + + switch (*curr) { + case 'G': + if (PARSE_METHOD(req,curr,GET,left)) + break; + GOTO_REDIR; + + case 'H': + if (PARSE_METHOD(req,curr,HEAD,left)) + break; + GOTO_REDIR; + + case 'P': + if (PARSE_METHOD(req,curr,POST,left)) + break; + if (PARSE_METHOD(req,curr,PUT,left)) + break; + GOTO_REDIR; + + default: + GOTO_REDIR; + } + + req->method_str = message; + req->method_len = curr-message-1; + + Dprintk("got method %d\n", req->method); + + PRINT_MESSAGE_LEFT; + + /* + * Ok, we got one of the methods we can handle, parse + * the URI: + */ + + { + // Do not allow leading "../" and intermediate "/../" + int dotdot = 1; + char *tmp = req->objectname; + int slashcheck = 1; + + req->uri_str = uri = curr; + + for (;;) { + c = get_c(curr,left); + if (slashcheck) { + if (c == '/') + continue; + slashcheck = 0; + } + + PRINT_MESSAGE_LEFT; + if (c == ' ' || ((c == '?') && (tux_ignore_query != 1)) || c == '\r' || c == '\n') + break; + if (c == '#') + GOTO_REDIR; + + Dprintk("hexhex: %d.\n", hexhex); + /* + * First handle HEX HEX encoding + */ + switch (hexhex) { + case 0: + if (c == '%') { + hexhex = 1; + goto continue_parsing; + } + break; + case 1: + hex_val_0 = TOHEX(c); + if (hex_val_0 < 0) + GOTO_REDIR; + hexhex = 2; + goto continue_parsing; + case 2: + hex_val_1 = TOHEX(c); + if (hex_val_1 < 0) + GOTO_REDIR; + c = (hex_val_0 << 4) | hex_val_1; + if (!c) + GOTO_REDIR; + hexhex = 0; + break; + default: + TUX_BUG(); + } + if (hexhex) + TUX_BUG(); + + switch (dotdot) { + case 0: + break; + case 1: + if (c == '.') + dotdot = 2; + else + dotdot = 0; + break; + case 2: + if (c == '.') + dotdot = 3; + else + dotdot = 0; + break; + case 3: + if (c == '/') + GOTO_REDIR; + else + dotdot = 0; + break; + default: + TUX_BUG(); + } + if (!dotdot && (c == '/')) + dotdot = 1; + + *(tmp++) = c; +continue_parsing: + if (curr - uri >= MAX_OBJECTNAME_LEN) + GOTO_REDIR; + } + PRINT_MESSAGE_LEFT; + *tmp = 0; + + // handle trailing "/.." + if (dotdot == 3) + GOTO_REDIR; + + objectname_len = tmp - req->objectname; + req->objectname_len = objectname_len; + } + Dprintk("got filename %s (%d)\n", req->objectname, req->objectname_len); + + PRINT_MESSAGE_LEFT; + + /* + * Parse optional query string. Copy until end-of-string or space. + */ + if (c == '?') { + int query_len; + const char *query; + + req->query_str = query = curr; + + for (;;) { + c = get_c(curr,left); + if (c == ' ') + break; + if (c == '#') + GOTO_REDIR; + } + if (unlikely(tux_ignore_query == 2)) + req->query_str = NULL; + else { + query_len = curr-query-1; + req->query_len = query_len; + } + } + if (req->query_len) + Dprintk("got query string %s (%d)\n", req->query_str, req->query_len); + req->uri_len = curr-uri-1; + if (!req->uri_len) + GOTO_REDIR; + Dprintk("got URI %s (%d)\n", req->uri_str, req->uri_len); + + PRINT_MESSAGE_LEFT; + /* + * Parse the HTTP version field: + */ + req->version_str = curr; + if (!PARSE_TOKEN(curr,"HTTP/1.",left)) + GOTO_REDIR; + + switch (get_c(curr,left)) { + case '0': + req->version = HTTP_1_0; + break; + case '1': + req->version = HTTP_1_1; + break; + default: + GOTO_REDIR; + } + /* + * We default to keepalive in the HTTP/1.1 case and default + * to non-keepalive in the HTTP/1.0 case. If max_keepalives + * is 0 then we do no keepalives. + */ + clear_keepalive(req); + if (tux_max_keepalives && (req->version == HTTP_1_1)) + req->keep_alive = 1; + req->version_len = curr - req->version_str; + + if (get_c(curr,left) != '\r') + GOTO_REDIR; + if (get_c(curr,left) != '\n') + GOTO_REDIR; + + Dprintk("got version %d [%d]\n", req->version, req->version_len); + PRINT_MESSAGE_LEFT; + + /* + * Now parse (optional) request header fields: + */ + for (;;) { + char c; + + c = get_c(curr,left); + switch (c) { + case '\r': + if (have_r) + GOTO_REDIR; + have_r = 1; + continue; + case '\n': + if (!have_r) + GOTO_REDIR; + goto out; + default: + if (have_r) + GOTO_REDIR; + } + +#define PARSE_STR_FIELD(char,field,str,len) \ + if (PARSE_TOKEN(curr,field,left)) { \ + req->str = curr; \ + SKIP_LINE(curr,left); \ + req->len = curr - req->str - 2; \ + Dprintk(char field "field: %s.\n", req->str); \ + break; \ + } + +#define ALLOW_UNKNOWN_FIELDS 1 +#ifdef ALLOW_UNKNOWN_FIELDS +# define UNKNOWN_FIELD { SKIP_LINE(curr,left); break; } +#else +# define UNKNOWN_FIELD GOTO_REDIR +#endif + + switch (c) { + case 'A': + PARSE_STR_FIELD("A","ccept: ", + accept_str,accept_len); + if (PARSE_TOKEN(curr,"ccept-Encoding: ",left)) { + const char *str = curr-1; + + req->accept_encoding_str = curr; + SKIP_LINE(curr,left); + req->accept_encoding_len = curr - req->accept_encoding_str - 2; + Dprintk("Accept-Encoding field: {%s}.\n", str); + + if (tux_compression && may_gzip(str,curr-str)) { + Dprintk("client accepts gzip!.\n"); + req->may_send_gzip = 1; + } + break; + } + PARSE_STR_FIELD("A","ccept-Charset: ", + accept_charset_str,accept_charset_len); + PARSE_STR_FIELD("A","ccept-Language: ", + accept_language_str,accept_language_len); + UNKNOWN_FIELD; + + case 'C': + if (PARSE_TOKEN(curr,"onnection: ",left)) { +next_token: + switch (get_c(curr,left)) { + case 'K': + if (!PARSE_TOKEN(curr,"eep-Alive",left)) + GOTO_REDIR; + if (tux_max_keepalives) + req->keep_alive = 1; + break; + + case 'C': + case 'c': + if (!PARSE_TOKEN(curr,"lose",left)) + GOTO_REDIR; + clear_keepalive(req); + break; + + case 'k': + if (!PARSE_TOKEN(curr,"eep-alive",left)) + GOTO_REDIR; + if (tux_max_keepalives) + req->keep_alive = 1; + break; + case 'T': + if (PARSE_TOKEN(curr,"E",left)) + break; + if (PARSE_TOKEN(curr,"railers",left)) + break; + if (PARSE_TOKEN(curr,"ransfer-Encoding",left)) + break; + GOTO_REDIR; + case 'P': + if (PARSE_TOKEN(curr,"roxy-Authenticate",left)) + break; + if (PARSE_TOKEN(curr,"roxy-Authorization",left)) + break; + GOTO_REDIR; + case 'U': + if (!PARSE_TOKEN(curr,"pgrade",left)) + GOTO_REDIR; + break; + case ' ': + PRINT_MESSAGE_LEFT; + goto next_token; + case ',': + PRINT_MESSAGE_LEFT; + goto next_token; + default: + GOTO_REDIR; + } + PRINT_MESSAGE_LEFT; + if (*curr != '\r') + goto next_token; + // allow other tokens. + SKIP_LINE(curr,left); + break; + } + + PARSE_STR_FIELD("C","ookie: ", + cookies_str,cookies_len); + PARSE_STR_FIELD("C","ontent-Type: ", + content_type_str,content_type_len); + + if (PARSE_TOKEN(curr,"ontent-Length: ",left) || + PARSE_TOKEN(curr,"ontent-length: ",left)) { + const char *tmp; + req->contentlen_str = curr; + SKIP_LINE(curr,left); + req->contentlen_len = curr - req->contentlen_str - 2; + if (req->contentlen_len) { + tmp = req->contentlen_str; + req->content_len = simple_strtoul(tmp, NULL, 10); + } + Dprintk("Content-Length field: %s [%d].\n", req->contentlen_str, req->contentlen_len); + Dprintk("Content-Length value: %d.\n", req->content_len); + break; + } + PARSE_STR_FIELD("C","ache-Control: ", + cache_control_str,cache_control_len); + UNKNOWN_FIELD; + + case 'H': + if (PARSE_TOKEN(curr,"ost: ",left)) { + const char *tmp = curr; + char *tmp2 = req->host; + + /* + * canonize the hostname: + * + * 1) strip off preceding 'www.' variants, + * 2) transform it to lowercase. + * 3) strip trailing dots + * 4) potentially strip off tail + */ + +#define is_w(n) ((curr[n] == 'w') || (curr[n] == 'W')) + + if ((left > 4) && is_w(0) && is_w(1) && + is_w(2) && curr[3] == '.') { + curr += 4; + left -= 4; + tmp = curr; + } + + COPY_LINE_TOLOWER(curr, tmp2, left, req->host+MAX_HOST_LEN-2); + req->host_len = curr - tmp - 2; + while (req->host[req->host_len] == '.') { + if (!req->host_len) + break; + req->host_len--; + } + req->host[req->host_len] = 0; + if (strip_host_tail) + strip_hostname(req); + Dprintk("Host field: %s [%d].\n", req->host, req->host_len); + break; + } + UNKNOWN_FIELD; + + case 'I': + PARSE_STR_FIELD("I","f-None-Match: ", + if_none_match_str,if_none_match_len); + PARSE_STR_FIELD("I","f-Modified-Since: ", + if_modified_since_str,if_modified_since_len); + PARSE_STR_FIELD("I","f-Range: ", + if_range_str,if_range_len); + UNKNOWN_FIELD; + + case 'N': + PARSE_STR_FIELD("N","egotiate: ", + negotiate_str,negotiate_len); + UNKNOWN_FIELD; + + case 'P': + PARSE_STR_FIELD("P","ragma: ", + pragma_str,pragma_len); + UNKNOWN_FIELD; + + case 'R': + + PARSE_STR_FIELD("R","eferer: ", + referer_str,referer_len); + if (!PARSE_TOKEN(curr,"ange: bytes=",left)) + UNKNOWN_FIELD; + { + const char *tmp = curr; + char *tmp2 = (char *)curr; + unsigned int offset_start = 0, offset_end = 0; + + if (*tmp2 != '-') + offset_start = simple_strtoul(tmp2, &tmp2, 10); + if (*tmp2 == '-') { + tmp2++; + if (*tmp2 != '\r') + offset_end = simple_strtoul(tmp2, &tmp2, 10) +1; + } + curr = tmp2; + left -= tmp2-tmp; + + req->offset_start = offset_start; + req->offset_end = offset_end; + + SKIP_LINE(curr,left); + Dprintk("Range field: %s [%d] (%d-%d).\n", tmp, curr-tmp, offset_start, offset_end); + break; + } + + case 'U': + PARSE_STR_FIELD("U","ser-Agent: ", + user_agent_str,user_agent_len); + UNKNOWN_FIELD; + + default: + UNKNOWN_FIELD; + } + PRINT_MESSAGE_LEFT; + } +out: + /* + * POST data. + */ + if ((req->method == METHOD_POST) && req->content_len) { + PRINT_MESSAGE_LEFT; + if (curr + req->content_len > message + total_len) + GOTO_INCOMPLETE; + req->post_data_str = curr; + req->post_data_len = req->content_len; + curr += req->content_len; + left -= req->content_len; + Dprintk("POST-ed data: {%s}\n", req->post_data_str); + } + + switch (req->method) { + default: + GOTO_REDIR; + case METHOD_GET: + case METHOD_HEAD: + case METHOD_POST: + case METHOD_PUT: + ; + } + +#define TUX_SCHEME "http://" +#define TUX_SCHEME_LEN (sizeof(TUX_SCHEME)-1) + + if (!memcmp(req->objectname, TUX_SCHEME, TUX_SCHEME_LEN)) { + + /* http://user:password@host:port/object */ + + const char *head, *tail, *end, *host, *port; + int host_len, objectname_len; + + head = req->objectname + TUX_SCHEME_LEN; + end = req->objectname + req->objectname_len; + + tail = memchr(head, '/', end - head); + if (!tail) + GOTO_REDIR; + host = memchr(head, '@', tail - head); + if (!host) + host = head; + else + host++; + if (!*host) + GOTO_REDIR; + port = memchr(host, ':', tail - host); + if (port) + host_len = port - host; + else + host_len = tail - host; + if (host_len >= MAX_HOST_LEN) + GOTO_REDIR; + memcpy(req->host, host, host_len); + req->host_len = host_len; + req->host[host_len] = 0; + + if (*tail != '/') + TUX_BUG(); + + req->uri_str = tail; + req->uri_len = end - tail; + + tail++; + while (*tail == '/') + tail++; + + objectname_len = end - tail; + memcpy(req->objectname, tail, objectname_len); + req->objectname_len = objectname_len; + req->objectname[objectname_len] = 0; + } else + if (req->uri_str[0] != '/') + GOTO_REDIR; + + if ((req->version == HTTP_1_1) && !req->host_len) + GOTO_REDIR; + if (req->objectname[0] == '/') + GOTO_REDIR; + /* + * Lets make sure nobody plays games with the host + * header in a virtual hosting environment: + */ + if (req->virtual && req->host_len) { + if (memchr(req->host, '/', req->host_len)) + GOTO_REDIR; + if (req->host[0] == '.') { + if (req->host_len == 1) + GOTO_REDIR; + if ((req->host_len == 2) && (req->host[0] == '.')) + GOTO_REDIR; + } + } + /* + * From this point on the request is for the main TUX engine: + */ + Dprintk("ok, request accepted.\n"); + + if (req->keep_alive) { + req->nr_keepalives++; + if (req->nr_keepalives == -1) + req->nr_keepalives--; + INC_STAT(nr_keepalive_reqs); + } else + INC_STAT(nr_nonkeepalive_reqs); + INC_STAT(keepalive_hist[req->nr_keepalives]); + + PRINT_MESSAGE_LEFT; + req->parsed_len = curr-message; + if (req->dentry) + TUX_BUG(); + req->virtual = tux_virtual_server; + if (req->virtual) + add_tux_atom(req, http_lookup_vhost); + else { + req->docroot_dentry = dget(req->proto->main_docroot.dentry); + req->docroot_mnt = mntget(req->proto->main_docroot.mnt); + add_tux_atom(req, http_process_message); + } + + return req->parsed_len; + +incomplete_message: + Dprintk("incomplete message!\n"); + PRINT_MESSAGE_LEFT; + + return 0; + +error: + if (total_len > 0) + req->parsed_len = total_len; + else + req->parsed_len = 0; + PRINT_MESSAGE_LEFT; + if (tux_TDprintk) { + TDprintk("redirecting message to secondary server.\n"); + print_req(req); + } + return -1; +} + +static int lookup_url (tux_req_t *req, const unsigned int flag) +{ + /* + * -1 : no previous checks made + * 0 : previous check failed, do not check farther, + * 1 : previous check successed, check farther + */ + int not_modified = -1; + int perm = 0, i; + struct dentry *dentry = NULL; + struct vfsmount *mnt = NULL; + struct inode *inode; + const char *filename; + + /* + * Do not do any etag or last_modified header checking + * if both unset. + */ + if (!tux_generate_etags && !tux_generate_last_mod) + not_modified = 0; + +repeat_lookup: + if (req->dentry) + TUX_BUG(); + + filename = req->objectname; + Dprintk("will look up {%s} (%d)\n", filename, req->objectname_len); + Dprintk("current->fsuid: %d, current->fsgid: %d, ngroups: %d\n", + current->fsuid, current->fsgid, current->group_info->ngroups); + for (i = 0; i < current->group_info->ngroups; i++) + Dprintk(".. group #%d: %d.\n", i, current->groups[i]); + + dentry = tux_lookup(req, filename, flag, &mnt); + +#define INDEX "/index.html" + + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) + goto cachemiss; + + if (tux_http_dir_indexing && (req->lookup_dir == 1)) { + // undo the index.html appending: + req->objectname_len -= sizeof(INDEX)-1; + req->objectname[req->objectname_len] = 0; + req->lookup_dir = 2; + goto repeat_lookup; + } + if (!req->lookup_404) { + int len = strlen(tux_404_page); + memcpy(req->objectname, tux_404_page, len); + req->objectname[len] = 0; + req->objectname_len = len; + req->lookup_404 = 1; + req->status = 404; + goto repeat_lookup; + } + TDprintk("abort - lookup error.\n"); + goto abort; + } + + Dprintk("SUCCESS, looked up {%s} == dentry %p (inode %p, count %d.)\n", filename, dentry, dentry->d_inode, atomic_read(&dentry->d_count)); + inode = dentry->d_inode; + + /* + * At this point we have a real, non-negative dentry. + */ + perm = tux_permission(inode); + + if ((perm < 0) || (!S_ISDIR(dentry->d_inode->i_mode) + && !S_ISREG(dentry->d_inode->i_mode))) { + Dprintk("FAILED trusted dentry %p permission %d.\n", dentry, perm); + req->status = 403; + goto abort; + } + if ((req->lookup_dir != 2) && S_ISDIR(dentry->d_inode->i_mode)) { + if (req->lookup_dir || (req->objectname_len + + sizeof(INDEX) >= MAX_OBJECTNAME_LEN)) { + req->status = 403; + goto abort; + } + if (req->objectname_len && (req->objectname[req->objectname_len-1] != '/')) { + dput(dentry); + mntput(mnt); + req->lookup_dir = 0; + return 2; + } + memcpy(req->objectname + req->objectname_len, + INDEX, sizeof(INDEX)); + req->objectname_len += sizeof(INDEX)-1; + req->lookup_dir = 1; + dput(dentry); + mntput(mnt); + mnt = NULL; + dentry = NULL; + goto repeat_lookup; + } + if (tux_max_object_size && (inode->i_size > tux_max_object_size)) { + TDprintk("too big object, %Ld bytes.\n", inode->i_size); + req->status = 403; + goto abort; + } + req->total_file_len = inode->i_size; + req->mtime = inode->i_mtime.tv_sec; + + { + loff_t num = req->total_file_len; + int nr_digits = 0; + unsigned long modulo; + char * etag_p = req->etag; + char digits [30]; + + do { + modulo = do_div(num, 10); + digits[nr_digits++] = '0' + modulo; + } while (num); + + req->lendigits = nr_digits; + req->etaglen = nr_digits; + + while (nr_digits) + *etag_p++ = digits[--nr_digits]; + + *etag_p++ = '-'; + num = req->mtime; + nr_digits = 0; + + do { + digits[nr_digits++] = 'a' + num % 16; + num /= 16; + } while (num); + req->etaglen += nr_digits+1; + while (nr_digits) + *etag_p++ = digits[--nr_digits]; + *etag_p = 0; + } + + if ((req->if_none_match_len >= req->etaglen) && (abs(not_modified) == 1)) { + + char * etag_p = req->etag; + const char * match_p = req->if_none_match_str; + int pos = req->etaglen - 1; + int matchpos = req->etaglen - 1; + + do { + while (etag_p[matchpos--] == match_p[pos--]) + if (matchpos < 0) + break; + if (matchpos < 0) + pos = req->if_none_match_len; + else { + if (match_p[pos+1] == ',') + pos += req->etaglen + 2; + else + pos += req->etaglen-matchpos; + matchpos = req->etaglen - 1; + } + } while (pos < req->if_none_match_len); + + if (matchpos < 0) { + not_modified = 1; + TDprintk("Etag matched.\n"); + } else + not_modified = 0; + } + + if ((req->if_modified_since_len >= 24) && (abs(not_modified) == 1)) { + if (parse_time(req->if_modified_since_str, req->if_modified_since_len) >= req->mtime ) { + not_modified = 1; + Dprintk("Last-Modified matched.\n"); + } else + not_modified = 0; + } + + if (not_modified == 1) { + req->status = 304; + goto abort; + } + + Dprintk("looked up cached dentry %p, (count %d.)\n", dentry, dentry ? atomic_read(&dentry->d_count) : -1 ); + + url_hist_hit(req->total_file_len); +out: + install_req_dentry(req, dentry, mnt); + req->lookup_dir = 0; + return 0; + +cachemiss: + return 1; + +abort: + if (dentry) { + if (!IS_ERR(dentry)) + dput(dentry); + dentry = NULL; + } + if (mnt) { + if (!IS_ERR(mnt)) + mntput(mnt); + mnt = NULL; + } +#if CONFIG_TUX_DEBUG + if (!not_modified) { + TDprintk("req %p has lookup errors!\n", req); + if (tux_TDprintk) + print_req(req); + } +#endif + req_err(req); + goto out; +} + +int handle_gzip_req (tux_req_t *req, unsigned int flags) +{ + char *curr = req->objectname + req->objectname_len; + struct dentry *dentry; + struct vfsmount *mnt = NULL; + struct inode *inode, *orig_inode; + loff_t size, orig_size; + + *curr++ = '.'; + *curr++ = 'g'; + *curr++ = 'z'; + *curr++ = 0; + req->objectname_len += 3; + + dentry = tux_lookup(req, req->objectname, flags, &mnt); + + req->objectname_len -= 3; + req->objectname[req->objectname_len] = 0; + + if (!dentry) + return 0; + if (IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + release_req_dentry(req); + return 1; + } + return 0; + } + + inode = dentry->d_inode; + size = inode->i_size; + orig_inode = req->dentry->d_inode; + orig_size = orig_inode->i_size; + + if (!tux_permission(inode) + && (size < orig_size) + && (inode->i_mtime.tv_sec >= orig_inode->i_mtime.tv_sec)) { + + release_req_dentry(req); + install_req_dentry(req, dentry, mnt); + req->total_file_len = req->output_len = size; + Dprintk("content WILL be gzipped!\n"); + req->content_gzipped = 1; + } else { + dput(dentry); + mntput(mnt); + } + + return 0; +} + +static spinlock_t mimetypes_lock = SPIN_LOCK_UNLOCKED; + +static LIST_HEAD(mimetypes_head); + +static mimetype_t default_mimetype = { type: "text/plain", type_len: 10, expire_str: "", expire_str_len: 0 }; + +#define MAX_MIMETYPE_LEN 128 +#define MAX_CACHE_CONTROL_AGE_LEN 30 + +void add_mimetype (char *new_ext, char *new_type, char *new_expire) +{ + int type_len = strlen(new_type); + int ext_len = strlen(new_ext); + int expire_len = strlen(new_expire); + mimetype_t *mime; + char *ext, *type, *expire; + + if (type_len > MAX_MIMETYPE_LEN) + type_len = MAX_MIMETYPE_LEN; + if (ext_len > MAX_URI_LEN) + ext_len = MAX_URI_LEN; + if (expire_len > MAX_CACHE_CONTROL_AGE_LEN) + expire_len = MAX_CACHE_CONTROL_AGE_LEN; + + mime = tux_kmalloc(sizeof(*mime)); + memset(mime, 0, sizeof(*mime)); + ext = tux_kmalloc(ext_len + 1); + type = tux_kmalloc(type_len + 1); + expire = tux_kmalloc(expire_len + 1); + + strncpy(ext, new_ext, ext_len); + strncpy(type, new_type, type_len); + strncpy(expire, new_expire, expire_len); + + // in case one of the above parameters was too long : + + ext[ext_len] = '\0'; + type[type_len] = '\0'; + expire[expire_len] = '\0'; + + mime->ext = ext; + mime->ext_len = ext_len; + + mime->type = type; + mime->type_len = type_len; + + mime->expire_str = expire; + mime->expire_str_len = expire_len; + + mime->special = NORMAL_MIME_TYPE; + if (!strcmp(type, "TUX/redirect")) + mime->special = MIME_TYPE_REDIRECT; + if (!strcmp(type, "TUX/CGI")) + mime->special = MIME_TYPE_CGI; + if (!strcmp(type, "TUX/module")) + mime->special = MIME_TYPE_MODULE; + + spin_lock(&mimetypes_lock); + list_add(&mime->list, &mimetypes_head); + spin_unlock(&mimetypes_lock); +} + +static inline int ext_matches (char *file, int len, char *ext, int extlen) +{ + int i; + char *tmp = file + len-1; + char *tmp2 = ext + extlen-1; + + if (len < extlen) + return 0; + + for (i = 0; i < extlen; i++) { + if (*tmp != *tmp2) + return 0; + tmp--; + tmp2--; + } + return 1; +} + +/* + * Overhead is not a problem, we cache the MIME type + * in the dentry. + */ +static mimetype_t * lookup_mimetype (tux_req_t *req) +{ + char *objectname = req->objectname; + int len = req->objectname_len; + mimetype_t *mime = NULL; + struct list_head *head, *tmp, *tmp1, *tmp2, *tmp3; + + if (!memchr(objectname, '.', len)) + goto out; + + spin_lock(&mimetypes_lock); + head = &mimetypes_head; + tmp = head->next; + + while (tmp != head) { + mime = list_entry(tmp, mimetype_t, list); + if (ext_matches(objectname, len, mime->ext, mime->ext_len)) { + /* + * Percolate often-used mimetypes up: + */ + if (tmp->prev != &mimetypes_head) { + tmp1 = tmp; + tmp2 = tmp->prev; + tmp3 = tmp->prev->prev; + list_del(tmp1); + list_del(tmp2); + list_add(tmp, tmp3); + list_add(tmp2, tmp); + } + break; + } else + mime = NULL; + tmp = tmp->next; + } + spin_unlock(&mimetypes_lock); + +out: + if (!mime) + mime = &default_mimetype; + return mime; +} + +void free_mimetypes (void) +{ + struct list_head *head, *tmp, *next; + mimetype_t *mime; + + spin_lock(&mimetypes_lock); + head = &mimetypes_head; + tmp = head->next; + + while (tmp != head) { + next = tmp->next; + mime = list_entry(tmp, mimetype_t, list); + list_del(tmp); + + kfree(mime->ext); + mime->ext = NULL; + kfree(mime->type); + mime->type = NULL; + kfree(mime); + + tmp = next; + } + spin_unlock(&mimetypes_lock); +} + +/* + * Various constant HTTP responses: + */ + +static const char forbidden[] = + "HTTP/1.1 403 Forbidden\r\n" + "Connection: Keep-Alive\r\n" \ + "Content-Length: 24\r\n\r\n" + " Forbidden "; + +static const char not_found[] = + "HTTP/1.1 404 Not Found\r\n" + "Connection: Keep-Alive\r\n" \ + "Content-Length: 29\r\n\r\n" + " Page Not Found "; + +#define NOTMODIFIED_1 \ + "HTTP/1.1 304 Not Modified\r\n" \ + "Connection: Keep-Alive\r\n" \ + "Date: " + +#define NOTMODIFIED_1_LEN (sizeof(NOTMODIFIED_1) - 1) + +#define NOTMODIFIED_2 \ + "\r\nETag: \"" + +#define NOTMODIFIED_2_LEN (sizeof(NOTMODIFIED_2) - 1) + +#define NOTMODIFIED_3 \ + "\"\r\n\r\n" + +#define NOTMODIFIED_3_LEN (sizeof(NOTMODIFIED_3) - 1) + +#define REDIRECT_1 \ + "HTTP/1.1 301 Moved Permanently\r\n" \ + "Location: http://" + +#define REDIRECT_1_LEN (sizeof(REDIRECT_1) - 1) + +#define REDIRECT_2 \ + "/\r\nContent-Length: 36\r\n" \ + "Connection: Keep-Alive\r\n" \ + "Content-Type: text/html\r\n\r\n" \ + " 301 Moved Permanently " + +#define REDIRECT_2_LEN (sizeof(REDIRECT_2) - 1) + +void send_async_err_forbidden (tux_req_t *req) +{ + send_async_message(req, forbidden, 403, 1); +} + +void send_async_err_not_found (tux_req_t *req) +{ + send_async_message(req, not_found, 404, 1); +} + +static void send_ret_notmodified (tux_req_t *req) +{ + char *buf; + int size; + + size = NOTMODIFIED_1_LEN + DATE_LEN - 1 + NOTMODIFIED_2_LEN + req->etaglen + NOTMODIFIED_3_LEN; + buf = get_abuf(req, size); + memcpy(buf, NOTMODIFIED_1, NOTMODIFIED_1_LEN); + buf += NOTMODIFIED_1_LEN; + memcpy(buf, tux_date, DATE_LEN-1); + buf += DATE_LEN-1; + memcpy(buf, NOTMODIFIED_2, NOTMODIFIED_2_LEN); + buf += NOTMODIFIED_2_LEN; + memcpy(buf, &req->etag, req->etaglen); + buf += req->etaglen; + memcpy(buf, NOTMODIFIED_3, NOTMODIFIED_3_LEN); + buf += NOTMODIFIED_3_LEN; + + req->status = 304; + send_abuf(req, size, MSG_DONTWAIT); + add_req_to_workqueue(req); +} + +static void send_ret_redirect (tux_req_t *req, int cachemiss) +{ + char *buf; + unsigned int size; + unsigned int uts_len = 0; + + size = REDIRECT_1_LEN; + if (req->host_len) + size += req->host_len; + else { + down_read(&uts_sem); + uts_len = strlen(system_utsname.nodename); + size += uts_len; + } + if (req->objectname[0] != '/') + size++; + size += req->objectname_len; + size += REDIRECT_2_LEN; + + if (size > PAGE_SIZE) { + req->error = TUX_ERROR_CONN_CLOSE; + zap_request(req, cachemiss); + return; + } + + buf = get_abuf(req, size); + + memcpy(buf, REDIRECT_1, REDIRECT_1_LEN); + buf += REDIRECT_1_LEN; + + Dprintk("req %p, host: %s, host_len: %d.\n", req, req->host, req->host_len); + if (req->host_len) { + memcpy(buf, req->host, req->host_len); + buf += req->host_len; + } else { + memcpy(buf, system_utsname.nodename, uts_len); + up_read(&uts_sem); + buf += uts_len; + } + if (req->objectname[0] != '/') { + buf[0] = '/'; + buf++; + } + + memcpy(buf, req->objectname, req->objectname_len); + buf += req->objectname_len; + + memcpy(buf, REDIRECT_2, REDIRECT_2_LEN); + buf += REDIRECT_2_LEN; + + req->status = 301; + send_abuf(req, size, MSG_DONTWAIT); + add_req_to_workqueue(req); +} + +static void http_got_request (tux_req_t *req) +{ + req->host[0] = 0; + req->host_len = 0; + add_tux_atom(req, parse_request); + add_req_to_workqueue(req); +} + + +tux_attribute_t * lookup_tux_attribute (tux_req_t *req) +{ + tux_attribute_t *attr; + struct inode *inode; + mimetype_t *mime; + + attr = tux_kmalloc(sizeof(*attr)); + memset(attr, 0, sizeof(*attr)); + + mime = lookup_mimetype(req); + + inode = req->dentry->d_inode; + if (!inode->i_uid && !inode->i_gid) { + if (mime->special == MIME_TYPE_MODULE) { + attr->tcapi = lookup_tuxmodule(req->objectname); + if (!attr->tcapi) { + req_err(req); + mime = &default_mimetype; + } + } + } else { + if (mime->special && (mime->special != MIME_TYPE_REDIRECT)) + mime = &default_mimetype; + } + attr->mime = mime; + + return attr; +} + +static void handle_range(tux_req_t *req) +{ + if (req->if_range_len) { + time_t range_time; + + range_time = parse_time(req->if_range_str, req->if_range_len); + + /* + * If the file is newer then we send the whole file. + */ + if (range_time < req->mtime ) + goto out_no_range; + } + /* if no offset_end was specified then default to 'end of file': */ + if (!req->offset_end) + req->offset_end = req->total_file_len; + /* + * Sanity checks: + * + * - is the range between 0...file_len-1 ? + * - is offset_end after offset_start? + * + * (note that offset_end is higher by 1) + */ + if ((req->offset_end > req->total_file_len) || + (req->offset_start >= req->total_file_len) || + (req->offset_end <= req->offset_start)) + goto out_no_range; + /* + * If the range is 0...file_len-1 then send the whole file: + */ + if (!req->offset_start && (req->offset_end == req->total_file_len)) + goto out_no_range; + + /* ok, the range is valid, use it: */ + + req->output_len = req->offset_end - req->offset_start; + req->in_file.f_pos = req->offset_start; + return; + +out_no_range: + req->offset_start = 0; + req->offset_end = 0; +} + +static void http_pre_header (tux_req_t *req, int push); +static void http_post_header (tux_req_t *req, int cachemiss); +static void http_send_body (tux_req_t *req, int cachemiss); + +#define DIRLIST_HEAD_1 "\ +\ +Index of %s\ +

Index of %s


\n%s" + +#define DIRLIST_HEAD_2 "\ + Parent Directory\n" + +#define DIRLIST_HEAD_SIZE (sizeof(DIRLIST_HEAD_1) + sizeof(DIRLIST_HEAD_2)) + +static void http_dirlist_head (tux_req_t *req, int cachemiss) +{ + char *buf1, *buf2, *path; + int len; + + buf1 = (char *)__get_free_page(GFP_KERNEL); + buf2 = (char *)__get_free_page(GFP_KERNEL); + if (!buf1 || !buf2) + goto out; + path = tux_print_path(req, req->dentry, req->mnt, buf1, PAGE_SIZE); + if (path[0] == '/' && path[1] == '/' && !path[3]) + path = "/"; + if (2*strlen(path) + DIRLIST_HEAD_SIZE >= PAGE_SIZE) + goto out; + len = sprintf(buf2, DIRLIST_HEAD_1, path, path, req->dentry == req->docroot_dentry ? "" : DIRLIST_HEAD_2); + __send_async_message(req, buf2, 200, len, 0); + +out: + if (buf1) + free_page((unsigned long)buf1); + if (buf2) + free_page((unsigned long)buf2); +} + +#define DIRLIST_TAIL "\ +

Powered by Linux/TUX 3.0
\n" + +static void http_dirlist_tail (tux_req_t *req, int cachemiss) +{ + __send_async_message(req, DIRLIST_TAIL, 200, sizeof(DIRLIST_TAIL)-1, 1); +} + +static void http_dirlist (tux_req_t *req, int cachemiss) +{ + int head = (req->method == METHOD_HEAD); + + req->lookup_dir = 3; + clear_keepalive(req); + if (!head) { + add_tux_atom(req, http_dirlist_tail); + add_tux_atom(req, list_directory); + add_tux_atom(req, http_dirlist_head); + } + http_pre_header(req, head); + add_req_to_workqueue(req); +} + +static char *host_path_hash(tux_req_t *req, char *tmp) +{ + if (req->host_len < 2) + return NULL; + + switch (mass_hosting_hash) { + default: + case 0: + return req->host; + case 1: + + // www.ABCDEFG.com => A/ABCDEFG.com + + tmp[0] = req->host[0]; + tmp[1] = '/'; + memcpy(tmp + 2, req->host, req->host_len); + tmp[req->host_len + 2] = 0; + + return tmp; + case 2: + // www.ABCDEFG.com => A/AB/ABCDEFG.com + + tmp[0] = req->host[0]; + tmp[1] = '/'; + tmp[2] = req->host[0]; + tmp[3] = req->host[1]; + tmp[4] = '/'; + memcpy(tmp + 5, req->host, req->host_len); + tmp[req->host_len + 5] = 0; + + return tmp; + case 3: + // www.ABCDEFG.com => A/AB/ABC/ABCDEFG.com + + tmp[0] = req->host[0]; + tmp[1] = '/'; + tmp[2] = req->host[0]; + tmp[3] = req->host[1]; + tmp[4] = '/'; + tmp[5] = req->host[0]; + tmp[6] = req->host[1]; + tmp[7] = req->host[2]; + tmp[8] = '/'; + memcpy(tmp + 9, req->host, req->host_len); + tmp[req->host_len + 9] = 0; + + return tmp; + } +} + +static struct dentry * vhost_lookup (tux_req_t *req, struct nameidata* base, struct vfsmount **mnt) +{ + struct dentry *dentry = NULL; + // 255.255.255.255 + char ip [3+1+3+1+3+1+3 + 2]; + + if (req->virtual >= TUX_VHOST_IP) { + sprintf(ip, "%d.%d.%d.%d", + NIPQUAD(inet_sk(req->sock->sk)->rcv_saddr)); + dentry = __tux_lookup (req, ip, base, mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) + return dentry; + base->dentry = dget(req->proto->main_docroot.dentry); + base->mnt = mntget(req->proto->main_docroot.mnt); + goto lookup_default; + } + if (req->virtual == TUX_VHOST_IP) + goto done; + + // fall through in mixed mode: + } + + if (!req->host_len) { +lookup_default: + *mnt = NULL; + dentry = __tux_lookup (req, tux_default_vhost, base, mnt); + } else { + char tmp [MAX_HOST_LEN*2]; + char *host_path; + + host_path = host_path_hash(req, tmp); + Dprintk("host path hash returned: {%s}\n", host_path); + + dentry = NULL; + if (host_path) { + *mnt = NULL; + dentry = __tux_lookup (req, host_path, base, mnt); + } + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) + return dentry; + base->dentry = dget(req->proto->main_docroot.dentry); + base->mnt = mntget(req->proto->main_docroot.mnt); + if (req->virtual >= TUX_VHOST_IP) { + *mnt = NULL; + dentry = __tux_lookup (req, ip, base, mnt); + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) + return dentry; + base->dentry = dget(req->proto->main_docroot.dentry); + base->mnt = mntget(req->proto->main_docroot.mnt); + } + } + goto lookup_default; + } + } +done: + return dentry; +} + +static void http_lookup_vhost (tux_req_t *req, int cachemiss) +{ + struct dentry *dentry; + struct nameidata base; + struct vfsmount *mnt = NULL; + unsigned int flag = cachemiss ? 0 : LOOKUP_ATOMIC; + + Dprintk("http_lookup_vhost(%p, %d, virtual: %d, host: %s (%d).)\n", req, flag, req->virtual, req->host, req->host_len); + + base.flags = LOOKUP_FOLLOW|flag; + base.last_type = LAST_ROOT; + base.dentry = dget(req->proto->main_docroot.dentry); + base.mnt = mntget(req->proto->main_docroot.mnt); + + dentry = vhost_lookup(req, &base, &mnt); + + Dprintk("looked up dentry %p.\n", dentry); + + if (dentry && !IS_ERR(dentry) && !dentry->d_inode) + TUX_BUG(); + + if (!dentry || IS_ERR(dentry)) { + if (PTR_ERR(dentry) == -EWOULDBLOCKIO) { + add_tux_atom(req, http_lookup_vhost); + queue_cachemiss(req); + return; + } + goto abort; + } + + req->docroot_dentry = dentry; + req->docroot_mnt = mnt; + + add_tux_atom(req, http_process_message); + add_req_to_workqueue(req); + return; +abort: + if (dentry) { + if (!IS_ERR(dentry)) + dput(dentry); + dentry = NULL; + } + if (mnt) { + if (!IS_ERR(mnt)) + mntput(mnt); + mnt = NULL; + } + req_err(req); + add_req_to_workqueue(req); +} + +static void http_process_message (tux_req_t *req, int cachemiss) +{ + tux_attribute_t *attr; + int missed; + unsigned int lookup_flag = cachemiss ? 0 : LOOKUP_ATOMIC; + + Dprintk("handling req %p, cachemiss: %d.\n", req, cachemiss); + + /* + * URL redirection support - redirect all valid requests + * to the first userspace module. + */ + if (tux_all_userspace) { + tcapi_template_t *tcapi = get_first_usermodule(); + if (tcapi) { + req->usermode = 1; + req->usermodule_idx = tcapi->userspace_id; + goto usermode; + } + } + missed = lookup_url(req, lookup_flag); + if (missed == 2) { + if (req->query_str) { + req->error = TUX_ERROR_REDIRECT; + goto error; + } + send_ret_redirect(req, cachemiss); + return; + } + if (req->error) + goto error; + if (missed) { +cachemiss: + if (cachemiss) + TUX_BUG(); + Dprintk("uncached request.\n"); + INC_STAT(static_lookup_cachemisses); + if (req->dentry) + TUX_BUG(); + add_tux_atom(req, http_process_message); + queue_cachemiss(req); + return; + } + /* + * HTML directory indexing. + */ + if (S_ISDIR(req->dentry->d_inode->i_mode)) + return http_dirlist(req, cachemiss); + if (!S_ISREG(req->dentry->d_inode->i_mode)) + TUX_BUG(); + + + attr = req->dentry->d_extra_attributes; + if (!attr) { + attr = lookup_tux_attribute(req); + if (!attr) + TUX_BUG(); + req->dentry->d_extra_attributes = attr; + } + if (attr->mime) + Dprintk("using MIME type %s:%s, %d.\n", attr->mime->type, attr->mime->ext, attr->mime->special); + if (attr->tcapi) { + req->usermode = 1; + req->usermodule_idx = attr->tcapi->userspace_id; + if (req->module_dentry) + TUX_BUG(); + req->module_dentry = dget(req->dentry); + release_req_dentry(req); + goto usermode; + } + + switch (attr->mime->special) { + case MIME_TYPE_MODULE: + req->usermode = 1; + goto usermode; + + case MIME_TYPE_REDIRECT: + req->error = TUX_ERROR_REDIRECT; + goto error; + + case MIME_TYPE_CGI: +#if CONFIG_TUX_EXTCGI + Dprintk("CGI request %p.\n", req); + query_extcgi(req); + return; +#endif + + default: + if (req->query_str) { + req->error = TUX_ERROR_REDIRECT; + goto error; + } + } + req->attr = attr; + switch (req->method) { + case METHOD_GET: + case METHOD_HEAD: + break; + default: + req->error = TUX_ERROR_REDIRECT; + goto error; + } + if (req->usermode) + TUX_BUG(); + + req->output_len = req->total_file_len; + /* + * Do range calculations. + */ + if (req->offset_end || req->offset_start) + handle_range(req); + + if (req->may_send_gzip && !req->offset_start && !req->offset_end) { + if (handle_gzip_req(req, lookup_flag)) + goto cachemiss; + if ((tux_compression >= 2) && !req->content_gzipped) + req->content_gzipped = 2; + } + if (req->parsed_len) + trunc_headers(req); + + if (req->error) + goto error; + + add_tux_atom(req, http_send_body); + add_tux_atom(req, http_post_header); + + http_pre_header(req, req->method == METHOD_HEAD); + + add_req_to_workqueue(req); + return; + +error: + if (req->error) + zap_request(req, cachemiss); + return; + +usermode: + add_req_to_workqueue(req); +} + +static void http_post_header (tux_req_t *req, int cachemiss) +{ +#if CONFIG_TUX_DEBUG + req->bytes_expected = req->output_len; +#endif + req->bytes_sent = 0; // data comes now. + + add_req_to_workqueue(req); +} + +static void http_send_body (tux_req_t *req, int cachemiss) +{ + int ret; + + Dprintk("SEND req %p <%p> (sock %p, sk %p) (keepalive: %d, status: %d)\n", req, __builtin_return_address(0), req->sock, req->sock->sk, req->keep_alive, req->status); + + SET_TIMESTAMP(req->output_timestamp); + + if (req->error) { +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + req->in_file.f_pos = 0; + /* + * We are in the middle of a file transfer, + * zap it immediately: + */ + TDprintk("req->error = TUX_ERROR_CONN_CLOSE.\n"); + req->error = TUX_ERROR_CONN_CLOSE; + zap_request(req, cachemiss); + return; + } + +repeat: + ret = 0; + if (!req->status) + req->status = 200; + if (req->method != METHOD_HEAD) { + ret = generic_send_file(req, req->sock, cachemiss); + Dprintk("body send-file returned: %d.\n", ret); + } else { +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + } + + switch (ret) { + case -5: + add_tux_atom(req, http_send_body); + output_timeout(req); + break; + case -4: + add_tux_atom(req, http_send_body); + if (add_output_space_event(req, req->sock)) { + del_tux_atom(req); + goto repeat; + } + break; + case -3: + INC_STAT(static_sendfile_cachemisses); + add_tux_atom(req, http_send_body); + queue_cachemiss(req); + break; + case -1: + break; + default: + req->in_file.f_pos = 0; + add_req_to_workqueue(req); + break; + } +} + +#define DEFAULT_DATE "Wed, 01 Jan 1970 00:00:01 GMT" + +char tux_date [DATE_LEN] = DEFAULT_DATE; + +/* + * HTTP header + */ + +#define HEADER_PART1A \ + "HTTP/1.1 200 OK\r\n" \ + "Content-Type: " + +#define HEADER_PART1B \ + "HTTP/1.1 200 OK" + +#define HEADER_PART1AP \ + "HTTP/1.1 206 Partial Content\r\n" \ + "Content-Type: " + +#define HEADER_PART1BP \ + "HTTP/1.1 206 Partial Content" + +#define HEADER_PART1C \ + "HTTP/1.1 404 Page Not Found\r\n" \ + "Content-Type: " + +#define HEADER_PART1D \ + "HTTP/1.1 200 OK\r\n" \ + "Content-Type: text/html\r\n" \ + "Connection: close\r\n" + +#define HEADER_PART2_keepalive "\r\nConnection: Keep-Alive\r\nDate: " + +#define HEADER_PART2_close "\r\nConnection: close\r\nDate: " + +#define HEADER_PART2_none "\r\nDate: " + +// date "%s" + +#define HEADER_PART3A "\r\nContent-Encoding: gzip" +#define HEADER_PART3BX "\r\nContent-Length: " + +/* + * Please acknowledge our hard work by not changing this define, or + * at least please acknowledge us by leaving "TUX/2.0 (Linux)" in + * the ID string. Thanks! :-) + */ +#define HEADER_PART3BY "\r\nServer: TUX/2.0 (Linux)\r\nContent-Length: " +#define HEADER_PART3C "\r\nETag: \"" +#define HEADER_PART3ACC "\r\nAccept-Ranges: bytes" +#define HEADER_PART3L "\r\nLast-Modified: " +#define HEADER_PART3P "\r\nContent-Range: bytes " +#define HEADER_PART3CA "\r\nCache-Control: max-age=" +#define HEADER_PART4 "\r\n\r\n" + +#define MAX_OUT_HEADER_LEN (sizeof(HEADER_PART1AP) + MAX_MIMETYPE_LEN + \ + sizeof(HEADER_PART2_keepalive) + DATE_LEN + \ + sizeof(HEADER_PART3A) + sizeof(HEADER_PART3BY) + \ + 12 + sizeof(HEADER_PART3C) + 21 + sizeof(HEADER_PART3L) + \ + sizeof(HEADER_PART3P) + 32 + \ + DATE_LEN + sizeof(HEADER_PART4) + sizeof(tux_extra_html_header) \ + + sizeof(HEADER_PART3CA) + MAX_CACHE_CONTROL_AGE_LEN) + +static void http_pre_header (tux_req_t *req, int head) +{ + int partial = req->offset_start | req->offset_end; + unsigned long flags; + char *buf, *curr; + mimetype_t *mime = NULL; + int size; + + + if (MAX_OUT_HEADER_LEN > PAGE_SIZE) + TUX_BUG(); + if ((req->attr && req->attr->tcapi) || req->usermode) + TUX_BUG(); + +#define COPY_STATIC_PART(nr,curr) \ + do { \ + memcpy(curr, HEADER_PART##nr, sizeof(HEADER_PART##nr)-1); \ + curr += sizeof(HEADER_PART##nr)-1; \ + } while (0) + + buf = curr = get_abuf(req, MAX_OUT_HEADER_LEN); + + if (req->lookup_dir) { + COPY_STATIC_PART(1D, curr); + goto dir_next; + } + mime = req->attr->mime; + if (!mime) + TUX_BUG(); + + if (req->status == 404) { + COPY_STATIC_PART(1C, curr); + memcpy(curr, mime->type, mime->type_len); + curr += mime->type_len; + } else { + if (tux_noid && (mime == &default_mimetype)) { + if (partial) + COPY_STATIC_PART(1BP, curr); + else + COPY_STATIC_PART(1B, curr); + } else { + if (partial) + COPY_STATIC_PART(1AP, curr); + else + COPY_STATIC_PART(1A, curr); + memcpy(curr, mime->type, mime->type_len); + curr += mime->type_len; + } + } + + if (tux_generate_cache_control && mime->expire_str_len) { + COPY_STATIC_PART(3CA, curr); + memcpy(curr, mime->expire_str, mime->expire_str_len); + curr += mime->expire_str_len; + } + + if (req->keep_alive /* && (req->version == HTTP_1_0) */) + COPY_STATIC_PART(2_keepalive, curr); + else if (!req->keep_alive && (req->version == HTTP_1_1)) + COPY_STATIC_PART(2_close, curr); + else + // HTTP/1.0 default means close + COPY_STATIC_PART(2_none, curr); + +dir_next: + memcpy(curr, tux_date, DATE_LEN-1); + curr += DATE_LEN-1; + + if (req->content_gzipped) + COPY_STATIC_PART(3A, curr); + + /* + * Content-Length: + */ + if (!req->lookup_dir) { + if (tux_noid) + COPY_STATIC_PART(3BX, curr); + else + COPY_STATIC_PART(3BY, curr); + + if (partial) + curr += sprintf(curr, "%Ld", req->output_len); + else { + if (req->content_gzipped) + curr += sprintf(curr, "%Ld", + req->total_file_len); + else { + memcpy(curr, &req->etag, req->lendigits); + curr += req->lendigits; + } + } + if (tux_generate_etags && (req->status != 404)) { + COPY_STATIC_PART(3C, curr); + memcpy(curr, &req->etag, req->etaglen); + curr += req->etaglen; + curr[0] = '"'; + curr++; + } + if (tux_generate_last_mod || tux_generate_etags) + COPY_STATIC_PART(3ACC, curr); + } + if (tux_generate_last_mod && (req->status != 404)) { + COPY_STATIC_PART(3L, curr); + last_mod_time(curr, req->mtime); + curr += DATE_LEN-1; + } + if (partial) { + COPY_STATIC_PART(3P, curr); + curr += sprintf(curr, "%Ld-%Ld/%Ld", req->offset_start, + req->offset_end-1, req->total_file_len); + } + COPY_STATIC_PART(4, curr); + /* + * Possibly add an extra HTML header: + */ + if (tux_extra_html_header_size && mime && !strcmp(mime->type, "text/html")) { + unsigned int len = tux_extra_html_header_size; + + memcpy(curr, tux_extra_html_header, len); + curr += len; + } + + size = curr-buf; + +#if CONFIG_TUX_DEBUG + *curr = 0; + Dprintk("{%s} [%d/%d]\n", buf, size, strlen(buf)); +#endif + + flags = MSG_DONTWAIT; + if (!head) + flags |= MSG_MORE; + send_abuf(req, size, flags); +} + +void http_illegal_request (tux_req_t *req, int cachemiss) +{ + if (req->status == 304) + send_ret_notmodified(req); + else { + if (req->status == 403) + send_async_err_forbidden(req); + else + send_async_err_not_found(req); + } +} + +static int http_check_req_err (tux_req_t *req, int cachemiss) +{ + if ((req->sock->sk->sk_state <= TCP_SYN_RECV) && + !tcp_sk(req->sock->sk)->urg_data) + return 0; + Dprintk("http_check_req_err(%p,%d): 1 (state: %d, urg: %d)\n", + req, cachemiss, req->sock->sk->sk_state, + tcp_sk(req->sock->sk)->urg_data); +#if CONFIG_TUX_DEBUG + req->bytes_expected = 0; +#endif + req->in_file.f_pos = 0; + req->error = TUX_ERROR_CONN_CLOSE; + zap_request(req, cachemiss); + + return 1; +} + +#define COPY_STR(str) \ + do { memcpy(tmp, str, sizeof(str)-1); \ + tmp += sizeof(str)-1; } while (0) + +static char * http_print_dir_line (tux_req_t *req, char *tmp, char *d_name, int d_len, int d_type, struct dentry *dentry, struct inode *inode) +{ + int len, spaces; + loff_t size; + + switch (d_type) { + case DT_DIR: + COPY_STR("\"[DIR]\""); + break; + case DT_REG: + if ((d_len >= 3) && + (d_name[d_len-3] == '.') && + (d_name[d_len-2] == 'g') && + (d_name[d_len-1] == 'z')) + COPY_STR("\"["); + else + if ((d_len >= 4) && + (d_name[d_len-4] == '.') && + (d_name[d_len-3] == 't') && + (d_name[d_len-2] == 'g') && + (d_name[d_len-1] == 'z')) + COPY_STR("\"["); + else + if ((d_len >= 4) && + (d_name[d_len-4] == '.') && + (d_name[d_len-3] == 't') && + (d_name[d_len-2] == 'x') && + (d_name[d_len-1] == 't')) + COPY_STR("\"["); + else + if ((d_len >= 4) && + (d_name[d_len-4] == '.') && + (d_name[d_len-3] == 'b') && + (d_name[d_len-2] == 'z') && + (d_name[d_len-1] == '2')) + COPY_STR("\"["); + else + if ((d_len >= 4) && + (d_name[d_len-4] == '.') && + (d_name[d_len-3] == 'z') && + (d_name[d_len-2] == 'i') && + (d_name[d_len-1] == 'p')) + COPY_STR("\"["); + else + COPY_STR("\"["); + break; + case DT_LNK: + COPY_STR("\"[LNK]\""); + break; + default: + if (tux_hide_unreadable) + goto out_dput; + COPY_STR("\"["); + break; + } + +#define LIST_1 " " +#define LIST_2_DIR "/\">" +#define LIST_3 " " + + COPY_STR(LIST_1); + memcpy(tmp, d_name, d_len); + tmp += d_len; + if (d_type == DT_DIR) + COPY_STR(LIST_2_DIR); + else + COPY_STR(LIST_2); + spaces = 0; + len = d_len; + + if (len > 25) + len = 25; + memcpy(tmp, d_name, len); + tmp += len; + if (len != d_len) { + *tmp++ = '.'; + *tmp++ = '.'; + } else { + if (d_type == DT_DIR) + *tmp++ = '/'; + else + spaces++; + spaces++; + } + COPY_STR(LIST_3); + while (spaces) { + *tmp++ = ' '; + spaces--; + } +#define FILL 25 + if (d_len < FILL) { + memset(tmp, ' ', FILL-d_len); + tmp += FILL-d_len; + } + + tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp); + *tmp++ = ' '; + + if (d_type != DT_REG) { + COPY_STR(" - "); + goto out_size; + } + size = inode->i_size >> 10; + if (size < 1024) { + tmp += sprintf(tmp, "%8Lik ", size); + goto out_size; + } + size >>= 10; + if (size < 1024) { + tmp += sprintf(tmp, "%8LiM ", size); + goto out_size; + } + size >>= 10; + if (size < 1024) { + tmp += sprintf(tmp, "%8LiG ", size); + goto out_size; + } + size >>= 10; + if (size < 1024) { + tmp += sprintf(tmp, "%8LiT ", size); + goto out_size; + } + size >>= 10; + tmp += sprintf(tmp, "%8LiT ", size); + +out_size: + *tmp++ = '\n'; + *tmp = 0; + + return tmp; +out_dput: + return NULL; +} + +tux_proto_t tux_proto_http = { + defer_accept: 1, + can_redirect: 1, + got_request: http_got_request, + parse_message: parse_http_message, + illegal_request: http_illegal_request, + check_req_err: http_check_req_err, + print_dir_line: http_print_dir_line, + name: "http", +}; + diff --git a/net/tux/redirect.c b/net/tux/redirect.c new file mode 100644 index 000000000..86b5300fb --- /dev/null +++ b/net/tux/redirect.c @@ -0,0 +1,154 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * redirect.c: redirect requests to other server sockets (such as Apache). + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +static void dummy_destructor(struct open_request *req) +{ +} + +static struct or_calltable dummy = +{ + 0, + NULL, + NULL, + &dummy_destructor, + NULL +}; + +static int redirect_sock (tux_req_t *req, const int port) +{ + struct socket *sock = req->sock; + struct open_request *tcpreq; + struct sock *sk, *oldsk; + int err = -1; + + /* + * Look up (optional) listening user-space socket. + */ + local_bh_disable(); + sk = tcp_v4_lookup_listener(INADDR_ANY, port, 0); + /* + * Look up localhost listeners as well. + */ + if (!sk) { + u32 daddr; + ((unsigned char *)&daddr)[0] = 127; + ((unsigned char *)&daddr)[1] = 0; + ((unsigned char *)&daddr)[2] = 0; + ((unsigned char *)&daddr)[3] = 1; + sk = tcp_v4_lookup_listener(daddr, port, 0); + } + local_bh_enable(); + + /* No secondary server found */ + if (!sk) + goto out; + + /* + * Requeue the 'old' socket as an accept-socket of + * the listening socket. This way we can shuffle + * a socket around. Since we've read the input data + * via the non-destructive MSG_PEEK, the secondary + * server can be used transparently. + */ + oldsk = sock->sk; + lock_sock(sk); + + if (sk->sk_state != TCP_LISTEN) + goto out_unlock; + + tcpreq = tcp_openreq_alloc(); + if (!tcpreq) + goto out_unlock; + + unlink_tux_socket(req); + + sock->sk = NULL; + sock->state = SS_UNCONNECTED; + + tcpreq->class = &dummy; + write_lock_irq(&oldsk->sk_callback_lock); + oldsk->sk_socket = NULL; + oldsk->sk_sleep = NULL; + write_unlock_irq(&oldsk->sk_callback_lock); + + tcp_sk(oldsk)->nonagle = 0; + + tcp_acceptq_queue(sk, tcpreq, oldsk); + + sk->sk_data_ready(sk, 0); + + /* + * It's now completely up to the secondary + * server to handle this request. + */ + sock_release(req->sock); + req->sock = NULL; + req->parsed_len = 0; + err = 0; + Dprintk("req %p redirected to secondary server!\n", req); + +out_unlock: + release_sock(sk); + sock_put(sk); +out: + if (err) + Dprintk("NO secondary server for req %p!\n", req); + return err; +} + +void redirect_request (tux_req_t *req, int cachemiss) +{ + if (tux_TDprintk && (req->status != 304)) { + TDprintk("trying to redirect req %p, req->error: %d, req->status: %d.\n", req, req->error, req->status); + print_req(req); + } + + if (cachemiss) + TUX_BUG(); + if (req->error == TUX_ERROR_CONN_CLOSE) + goto out_flush; + if (!req->sock) + TUX_BUG(); + + if (!req->status) + req->status = -1; + if (!req->proto->can_redirect || (req->status == 304) || redirect_sock(req, tux_clientport)) { + if (req->parsed_len) + trunc_headers(req); + req->proto->illegal_request(req, cachemiss); + return; + } else { + if (req->data_sock) + BUG(); + } +out_flush: + clear_keepalive(req); + if (!tux_redirect_logging) + req->status = 0; + flush_request(req, cachemiss); +} + diff --git a/net/tux/times.c b/net/tux/times.c new file mode 100644 index 000000000..3388f6387 --- /dev/null +++ b/net/tux/times.c @@ -0,0 +1,392 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * times.c: time conversion routines. + * + * Original time convserion code Copyright (C) 1999 by Arjan van de Ven + */ + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#include +#include +#include +#include + + +#include "times.h" + +char *dayName[7] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char *monthName[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +char itoa_h[60]={'0','0','0','0','0','0','0','0','0','0', + '1','1','1','1','1','1','1','1','1','1', + '2','2','2','2','2','2','2','2','2','2', + '3','3','3','3','3','3','3','3','3','3', + '4','4','4','4','4','4','4','4','4','4', + '5','5','5','5','5','5','5','5','5','5'}; + +char itoa_l[60]={'0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9'}; + +int time_unix2ls(time_t zulu, char *buf) +{ + int Y=0,M=0,D=0; + int H=0,Min=0,S=0,WD=0; + int I,I2; + time_t rest, delta; + + if (zulu > xtime.tv_sec) + zulu = xtime.tv_sec; + + I=0; + while (Izulu) + break; + I++; + } + + Y=--I; + if (I<0) { + Y=0; + goto BuildYear; + } + I2=0; + while (I2<=12) { + if (TimeDays[I][I2]>zulu) + break; + I2++; + } + + M=I2-1; + + rest=zulu - TimeDays[Y][M]; + WD=WeekDays[Y][M]; + D=rest/86400; + rest=rest%86400; + WD+=D; + WD=WD%7; + H=rest/3600; + rest=rest%3600; + Min=rest/60; + rest=rest%60; + S=rest; + +BuildYear: + Y+=TUX_YEAROFFSET; + + + /* Format: Day, 01 Mon 1999 01:01:01 GMT */ + + delta = xtime.tv_sec - zulu; + if (delta > 6*30*24*60) + // "May 23 2000" + return sprintf( buf, "%s %02i %04i", monthName[M], D+1, Y); + else + // "May 23 10:14" + return sprintf( buf, "%s %02i %02i:%02i", + monthName[M], D+1, H, Min); +} + +static int MonthHash[32] = + {0,0,7,0,0,0,0,0,0,0,0,3,0,0,0,2,6,0,5,0,9,8,4,0,0,11,1,10,0,0,0,0}; + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static inline int skip_atoi(char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +time_t mimetime_to_unixtime(char *Q) +{ + int Y,M,D,H,Min,S; + unsigned int Hash; + time_t Temp; + char *s,**s2; + + s=Q; + s2=&s; + + if (strlen(s)<30) return 0; + if (s[3]!=',') return 0; + if (s[19]!=':') return 0; + + s+=5; /* Skip day of week */ + D = skip_atoi(s2); /* Day of month */ + s++; + Hash = (char)s[0]+(char)s[2]; + Hash = (Hash<<1) + (char)s[1]; + Hash = (Hash&63)>>1; + M = MonthHash[Hash]; + s+=4; + Y = skip_atoi(s2); /* Year */ + s++; + H = skip_atoi(s2); /* Hour */ + s++; + Min = skip_atoi(s2); /* Minutes */ + s++; + S = skip_atoi(s2); /* Seconds */ + s++; + if ((s[0]!='G')||(s[1]!='M')||(s[2]!='T')) + { + return 0; /* No GMT */ + } + + if (YTUX_YEAROFFSET+9) Y = TUX_YEAROFFSET+9; + + Temp = TimeDays[Y-TUX_YEAROFFSET][M]; + Temp += D*86400+H*3600+Min*60+S; + + return Temp; +} + +// writes the full http date, corresponding to time_t received + +void last_mod_time(char * curr, const time_t t) +{ + int day, tod, year, wday, mon, hour, min, sec; + + tod = t % 86400; + day = t / 86400; + if (tod < 0) { + tod += 86400; + --day; + } + + hour = tod / 3600; + tod %= 3600; + min = tod / 60; + sec = tod % 60; + + wday = (day + 4) % 7; + if (wday < 0) + wday += 7; + + day -= 11017; + /* day 0 is march 1, 2000 */ + year = 5 + day / 146097; + day = day % 146097; + if (day < 0) { + day += 146097; + --year; + } + /* from now on, day is nonnegative */ + year *= 4; + if (day == 146096) { + year += 3; + day = 36524; + } else { + year += day / 36524; + day %= 36524; + } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + if (day == 1460) { + year += 3; + day = 365; + } else { + year += day / 365; + day %= 365; + } + + day *= 10; + mon = (day + 5) / 306; + day = day + 5 - 306 * mon; + day /= 10; + if (mon >= 10) { + ++year; + mon -= 10; + } else + mon += 2; + + sprintf(curr, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", dayName[wday], + day+1, monthName[mon], year, hour, min, sec); +} + +// writes the full date in ISO8601 format, +// corresponding to time_t received +// example: 20011126224910 + +int mdtm_time(char * curr, const time_t t) +{ + int day, tod, year, wday, mon, hour, min, sec; + + tod = t % 86400; + day = t / 86400; + if (tod < 0) { + tod += 86400; + --day; + } + + hour = tod / 3600; + tod %= 3600; + min = tod / 60; + sec = tod % 60; + + wday = (day + 4) % 7; + if (wday < 0) + wday += 7; + + day -= 11017; + /* day 0 is march 1, 2000 */ + year = 5 + day / 146097; + day = day % 146097; + if (day < 0) { + day += 146097; + --year; + } + /* from now on, day is nonnegative */ + year *= 4; + if (day == 146096) { + year += 3; + day = 36524; + } else { + year += day / 36524; + day %= 36524; + } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + if (day == 1460) { + year += 3; + day = 365; + } else { + year += day / 365; + day %= 365; + } + + day *= 10; + mon = (day + 5) / 306; + day = day + 5 - 306 * mon; + day /= 10; + if (mon >= 10) { + ++year; + mon -= 10; + } else + mon += 2; + + return sprintf(curr, "213 %.4d%.2d%.2d%.2d%.2d%.2d\r\n", + year, mon+1, day+1, hour, min, sec); +} + +static inline int make_num(const char *s) +{ + if (*s >= '0' && *s <= '9') + return 10 * (*s - '0') + *(s + 1) - '0'; + else + return *(s + 1) - '0'; +} + +static inline int make_month(const char *s) +{ + int i; + + for (i = 0; i < 12; i++) + if (!strncmp(monthName[i], s, 3)) + return i+1; + return 0; +} + +time_t parse_time(const char *str, const int str_len) +{ + int hour; + int min; + int sec; + int mday; + int mon; + int year; + + if (str[3] == ',') { + /* Thu, 09 Jan 1993 01:29:59 GMT */ + + if (str_len < 29) + return -1; + + mday = make_num(str+5); + mon = make_month(str + 8); + year = 100 * make_num(str + 12) + make_num(str + 14); + hour = make_num(str + 17); + min = make_num(str + 20); + sec = make_num(str + 23); + } + else { + const char *s; + s = strchr(str, ','); + if (!s || (str_len - (s - str) < 24)) { + /* Wed Jun 9 01:29:59 1993 */ + + if (str_len < 24) + return -1; + + mon = make_month(str+4); + mday = make_num(str+8); + hour = make_num(str+11); + min = make_num(str+14); + sec = make_num(str+17); + year = make_num(str+20)*100 + make_num(str+22); + } + else { + /* Thursday, 10-Jun-93 01:29:59 GMT */ + + mday = make_num(s + 2); + mon = make_month(s + 5); + year = make_num(s + 9) + 1900; + if (year < 1970) + year += 100; + hour = make_num(s + 12); + min = make_num(s + 15); + sec = make_num(s + 18); + } + } + + if (sec < 0 || sec > 59) + return -1; + if (min < 0 || min > 59) + return -1; + if (hour < 0 || hour > 23) + return -1; + if (mday < 1 || mday > 31) + return -1; + if (mon < 1 || mon > 12) + return -1; + if (year < 1970 || year > 2020) + return -1; + + return mktime(year, mon, mday, hour, min, sec); +} diff --git a/net/tux/times.h b/net/tux/times.h new file mode 100644 index 000000000..09c389f92 --- /dev/null +++ b/net/tux/times.h @@ -0,0 +1,26 @@ +static time_t TimeDays[10][13] = { + { 852073200, 854751600, 857170800, 859849200, 862441200, 865119600, 867711600, 870390000, 873068400, 875660400, 878338800, 880930800, 883609200 } , + { 883609200, 886287600, 888706800, 891385200, 893977200, 896655600, 899247600, 901926000, 904604400, 907196400, 909874800, 912466800, 915145200 } , + { 915145200, 917823600, 920242800, 922921200, 925513200, 928191600, 930783600, 933462000, 936140400, 938732400, 941410800, 944002800, 946681200 } , + { 946681200, 949359600, 951865200, 954543600, 957135600, 959814000, 962406000, 965084400, 967762800, 970354800, 973033200, 975625200, 978303600 } , + { 978303600, 980982000, 983401200, 986079600, 988671600, 991350000, 993942000, 996620400, 999298800, 1001890800, 1004569200, 1007161200, 1009839600 } , + { 1009839600, 1012518000, 1014937200, 1017615600, 1020207600, 1022886000, 1025478000, 1028156400, 1030834800, 1033426800, 1036105200, 1038697200, 1041375600 } , + { 1041375600, 1044054000, 1046473200, 1049151600, 1051743600, 1054422000, 1057014000, 1059692400, 1062370800, 1064962800, 1067641200, 1070233200, 1072911600 } , + { 1072911600, 1075590000, 1078095600, 1080774000, 1083366000, 1086044400, 1088636400, 1091314800, 1093993200, 1096585200, 1099263600, 1101855600, 1104534000 } , + { 1104534000, 1107212400, 1109631600, 1112310000, 1114902000, 1117580400, 1120172400, 1122850800, 1125529200, 1128121200, 1130799600, 1133391600, 1136070000 } , + { 1136070000, 1138748400, 1141167600, 1143846000, 1146438000, 1149116400, 1151708400, 1154386800, 1157065200, 1159657200, 1162335600, 1164927600, 1167606000 } +}; +static int WeekDays[10][13] = { + { 3, 6, 6, 2, 4, 0, 2, 5, 1, 3, 6, 1, 4 } , + { 4, 0, 0, 3, 5, 1, 3, 6, 2, 4, 0, 2, 5 } , + { 5, 1, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3, 6 } , + { 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5, 1 } , + { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6, 2 } , + { 2, 5, 5, 1, 3, 6, 1, 4, 0, 2, 5, 0, 3 } , + { 3, 6, 6, 2, 4, 0, 2, 5, 1, 3, 6, 1, 4 } , + { 4, 0, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3, 6 } , + { 6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4, 0 } , + { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5, 1 } +}; +#define TUX_YEAROFFSET 1997 +#define TUX_NUMYEARS 10 diff --git a/net/tux/userspace.c b/net/tux/userspace.c new file mode 100644 index 000000000..effd45d3a --- /dev/null +++ b/net/tux/userspace.c @@ -0,0 +1,27 @@ +/* + * TUX - Integrated Application Protocols Layer and Object Cache + * + * Copyright (C) 2000, 2001, Ingo Molnar + * + * userspace.c: handle userspace-module requests + */ + +#include + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index e19475e6a..349343927 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -405,6 +405,8 @@ static int unix_release_sock (struct sock *sk, int embrion) mntput(mnt); } + clr_vx_info(&sk->sk_vx_info); + clr_nx_info(&sk->sk_nx_info); sock_put(sk); /* ---- Socket is dead now and most probably destroyed ---- */ @@ -559,6 +561,10 @@ static struct sock * unix_create1(struct socket *sock) sock_init_data(sock,sk); sk_set_owner(sk, THIS_MODULE); + set_vx_info(&sk->sk_vx_info, current->vx_info); + set_nx_info(&sk->sk_nx_info, current->nx_info); + sk->sk_xid = vx_current_xid(); + sk->sk_write_space = unix_write_space; sk->sk_max_ack_backlog = sysctl_unix_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; @@ -870,7 +876,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, goto out; alen = err; - if (sock->passcred && !unix_sk(sk)->addr && + if (test_bit(SOCK_PASS_CRED, &sock->flags) && !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0) goto out; @@ -961,7 +967,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, goto out; addr_len = err; - if (sock->passcred && !u->addr && (err = unix_autobind(sock)) != 0) + if (test_bit(SOCK_PASS_CRED, &sock->flags) + && !u->addr && (err = unix_autobind(sock)) != 0) goto out; timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); @@ -1295,7 +1302,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } - if (sock->passcred && !u->addr && (err = unix_autobind(sock)) != 0) + if (test_bit(SOCK_PASS_CRED, &sock->flags) + && !u->addr && (err = unix_autobind(sock)) != 0) goto out; err = -EMSGSIZE; diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 4776ec1ea..d8ee5edfc 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -552,7 +552,7 @@ static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_state != WANSOCK_CONNECTED) return -ENOTCONN; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (msg->msg_flags&~MSG_DONTWAIT) return(-EINVAL); /* it was <=, now one can send diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 17d20343a..9863ccd84 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -922,7 +922,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, size_t size; int qbit = 0, rc = -EINVAL; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR)) goto out; /* we currently don't support segmented records at the user interface */ @@ -1180,7 +1180,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; struct x25_opt *x25 = x25_sk(sk); - void __user *argp = (void __user *)arg; int rc; switch (cmd) { @@ -1189,7 +1188,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - rc = put_user(amount, (unsigned int __user *)argp); + rc = put_user(amount, (unsigned int *)arg); break; } @@ -1202,7 +1201,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - rc = put_user(amount, (unsigned int __user *)argp); + rc = put_user(amount, (unsigned int *)arg); break; } @@ -1210,7 +1209,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -EINVAL; if (sk) rc = sock_get_timestamp(sk, - (struct timeval __user *)argp); + (struct timeval __user *)arg); break; case SIOCGIFADDR: case SIOCSIFADDR: @@ -1229,20 +1228,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; - rc = x25_route_ioctl(cmd, argp); + rc = x25_route_ioctl(cmd, (void *)arg); break; case SIOCX25GSUBSCRIP: - rc = x25_subscr_ioctl(cmd, argp); + rc = x25_subscr_ioctl(cmd, (void *)arg); break; case SIOCX25SSUBSCRIP: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; - rc = x25_subscr_ioctl(cmd, argp); + rc = x25_subscr_ioctl(cmd, (void *)arg); break; case SIOCX25GFACILITIES: { struct x25_facilities fac = x25->facilities; - rc = copy_to_user(argp, &fac, + rc = copy_to_user((void *)arg, &fac, sizeof(fac)) ? -EFAULT : 0; break; } @@ -1250,7 +1249,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCX25SFACILITIES: { struct x25_facilities facilities; rc = -EFAULT; - if (copy_from_user(&facilities, argp, + if (copy_from_user(&facilities, (void *)arg, sizeof(facilities))) break; rc = -EINVAL; @@ -1278,7 +1277,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCX25GCALLUSERDATA: { struct x25_calluserdata cud = x25->calluserdata; - rc = copy_to_user(argp, &cud, + rc = copy_to_user((void *)arg, &cud, sizeof(cud)) ? -EFAULT : 0; break; } @@ -1287,7 +1286,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct x25_calluserdata calluserdata; rc = -EFAULT; - if (copy_from_user(&calluserdata, argp, + if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata))) break; rc = -EINVAL; @@ -1301,13 +1300,13 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCX25GCAUSEDIAG: { struct x25_causediag causediag; causediag = x25->causediag; - rc = copy_to_user(argp, &causediag, + rc = copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; break; } default: - rc = dev_ioctl(cmd, argp); + rc = dev_ioctl(cmd, (void __user *)arg); break; } diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index df85c66ca..073704ef6 100644 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -23,6 +23,7 @@ # $1 (first bracket) matches the size of the stack growth # # use anything else and feel the pain ;) +my (@stack, $re, $x, $xs); { my $arch = shift; if ($arch eq "") { @@ -31,25 +32,25 @@ $x = "[0-9a-f]"; # hex character $xs = "[0-9a-f ]"; # hex character or space - if ($arch =~ /^arm$/) { + if ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; } elsif ($arch =~ /^i[3456]86$/) { #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; - } elsif ($arch =~ /^ia64$/) { + } elsif ($arch eq 'ia64') { #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; - } elsif ($arch =~ /^mips64$/) { + } elsif ($arch eq 'mips64') { #8800402c: 67bdfff0 daddiu sp,sp,-16 $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch =~ /^mips$/) { + } elsif ($arch eq 'mips') { #88003254: 27bdffe0 addiu sp,sp,-32 $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch =~ /^ppc$/) { + } elsif ($arch eq 'ppc') { #c00029f4: 94 21 ff 30 stwu r1,-208(r1) $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch =~ /^ppc64$/) { + } elsif ($arch eq 'ppc64') { #XXX $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; } elsif ($arch =~ /^s390x?$/) { @@ -62,6 +63,7 @@ } sub bysize($) { + my ($asize, $bsize); ($asize = $a) =~ s/.* +(.*)$/$1/; ($bsize = $b) =~ s/.* +(.*)$/$1/; $bsize <=> $asize @@ -70,8 +72,9 @@ sub bysize($) { # # main() # -$funcre = qr/^$x* \<(.*)\>:$/; -while ($line = ) { +my $funcre = qr/^$x* <(.*)>:$/; +my $func; +while (my $line = ) { if ($line =~ m/$funcre/) { $func = $1; } @@ -85,7 +88,7 @@ while ($line = ) { $size += 0x80000000; } - $line =~ m/^($xs*).*/; + next if $line !~ m/^($xs*)/; my $addr = $1; $addr =~ s/ /0/g; $addr = "0x$addr"; @@ -97,12 +100,8 @@ while ($line = ) { $padlen -= 8; } next if ($size < 100); - $stack[@stack] = "$intro$size\n"; + push @stack, "$intro$size\n"; } } -@sortedstack = sort bysize @stack; - -foreach $i (@sortedstack) { - print("$i"); -} +print sort bysize @stack; diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 89b986abd..99aceccf7 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -23,6 +23,10 @@ oldconfig: $(obj)/conf silentoldconfig: $(obj)/conf $< -s arch/$(ARCH)/Kconfig +nonint_oldconfig: scripts/kconfig/conf + ./scripts/kconfig/conf -b arch/$(ARCH)/Kconfig + + .PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig randconfig: $(obj)/conf @@ -68,7 +72,7 @@ help: libkconfig-objs := zconf.tab.o host-progs := conf mconf qconf gconf -conf-objs := conf.o libkconfig.so +conf-objs := conf.o mconf-objs := mconf.o libkconfig.so ifeq ($(MAKECMDGOALS),xconfig) @@ -95,13 +99,15 @@ clean-files := libkconfig.so lkc_defs.h qconf.moc .tmp_qtcheck \ HOSTCFLAGS_lex.zconf.o := -I$(src) HOSTCFLAGS_zconf.tab.o := -I$(src) +HOSTLOADLIBES_conf = -Wl,-rpath,\$$ORIGIN -Lscripts/kconfig -lkconfig + HOSTLOADLIBES_qconf = -L$(QTLIBPATH) -Wl,-rpath,$(QTLIBPATH) -l$(QTLIB) -ldl HOSTCXXFLAGS_qconf.o = -I$(QTDIR)/include HOSTLOADLIBES_gconf = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --libs` HOSTCFLAGS_gconf.o = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --cflags` -$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o: $(obj)/zconf.tab.h +$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o: $(obj)/zconf.tab.h $(obj)/libkconfig.so $(obj)/qconf.o: $(obj)/.tmp_qtcheck @@ -112,7 +118,7 @@ QTLIBPATH = $(QTDIR)/lib # QT needs some extra effort... $(obj)/.tmp_qtcheck: - @set -e; for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ + @set -e; for d in $$QTDIR /usr/share/qt* /usr/lib/qt* /usr/lib64/qt* ; do \ if [ -f $$d/include/qconfig.h ]; then DIR=$$d; break; fi; \ done; \ if [ -z "$$DIR" ]; then \ diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index cdc72014d..a1032aa73 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -20,6 +20,7 @@ enum { ask_all, ask_new, ask_silent, + dont_ask, set_default, set_yes, set_mod, @@ -36,6 +37,8 @@ static struct menu *rootEntry; static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; +static int return_value = 0; + static void strip(char *str) { char *p = str; @@ -93,6 +96,12 @@ static void conf_askvalue(struct symbol *sym, const char *def) fflush(stdout); fgets(line, 128, stdin); return; + case dont_ask: + if (!sym_has_value(sym)) { + fprintf(stderr,"CONFIG_%s\n",sym->name); + return_value++; + } + return; case set_default: printf("%s\n", def); return; @@ -337,6 +346,10 @@ static int conf_choice(struct menu *menu) printf("?"); printf("]: "); switch (input_mode) { + case dont_ask: + cnt = def; + printf("%d\n", cnt); + break; case ask_new: case ask_silent: if (!is_new) { @@ -472,7 +485,10 @@ static void check_conf(struct menu *menu) if (!conf_cnt++) printf("*\n* Restart config...\n*\n"); rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); + if (input_mode == dont_ask) + fprintf(stderr,"CONFIG_%s\n",sym->name); + else + conf(rootEntry); } if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod) return; @@ -493,6 +509,9 @@ int main(int ac, char **av) case 'o': input_mode = ask_new; break; + case 'b': + input_mode = dont_ask; + break; case 's': input_mode = ask_silent; valid_stdin = isatty(0) && isatty(1) && isatty(2); @@ -557,6 +576,7 @@ int main(int ac, char **av) } case ask_all: case ask_new: + case dont_ask: conf_read(NULL); break; default: @@ -574,10 +594,10 @@ int main(int ac, char **av) do { conf_cnt = 0; check_conf(&rootmenu); - } while (conf_cnt); + } while ((conf_cnt) && (input_mode != dont_ask)); if (conf_write(NULL)) { fprintf(stderr, "\n*** Error during writing of the kernel configuration.\n\n"); return 1; } - return 0; + return return_value; } diff --git a/scripts/reference_discarded.pl b/scripts/reference_discarded.pl index 8f80364fc..9d01ec5f3 100644 --- a/scripts/reference_discarded.pl +++ b/scripts/reference_discarded.pl @@ -106,4 +106,4 @@ foreach $object (keys(%object)) { } # printf("Done\n"); -exit(0); +exit($errorcount); diff --git a/security/commoncap.c b/security/commoncap.c index 289569304..5f629be72 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -120,7 +120,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) /* Derived from fs/exec.c:compute_creds. */ kernel_cap_t new_permitted, working; - new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); + new_permitted = cap_intersect (bprm->cap_permitted, vx_current_bcaps()); working = cap_intersect (bprm->cap_inheritable, current->cap_inheritable); new_permitted = cap_combine (new_permitted, working); diff --git a/security/dummy.c b/security/dummy.c index 3e768e050..27fa13b5e 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -688,7 +688,7 @@ static int dummy_shm_shmctl (struct shmid_kernel *shp, int cmd) return 0; } -static int dummy_shm_shmat (struct shmid_kernel *shp, char __user *shmaddr, +static int dummy_shm_shmat (struct shmid_kernel *shp, char *shmaddr, int shmflg) { return 0; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c447232c6..35d779a21 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1380,7 +1380,7 @@ static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effecti if (error) return; - secondary_ops->capset_set(target, effective, inheritable, permitted); + return secondary_ops->capset_set(target, effective, inheritable, permitted); } static int selinux_capable(struct task_struct *tsk, int cap) @@ -3174,12 +3174,12 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) char *addrp; int len, err = 0; u32 netif_perm, node_perm, node_sid, recv_perm = 0; + u32 sock_sid = 0; + u16 sock_class = 0; struct socket *sock; - struct inode *inode; struct net_device *dev; struct sel_netif *netif; struct netif_security_struct *nsec; - struct inode_security_struct *isec; struct avc_audit_data ad; family = sk->sk_family; @@ -3190,15 +3190,21 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) family = PF_INET; - sock = sk->sk_socket; - - /* TCP control messages don't always have a socket. */ - if (!sock) - goto out; - - inode = SOCK_INODE(sock); - if (!inode) - goto out; + read_lock_bh(&sk->sk_callback_lock); + sock = sk->sk_socket; + if (sock) { + struct inode *inode; + inode = SOCK_INODE(sock); + if (inode) { + struct inode_security_struct *isec; + isec = inode->i_security; + sock_sid = isec->sid; + sock_class = isec->sclass; + } + } + read_unlock_bh(&sk->sk_callback_lock); + if (!sock_sid) + goto out; dev = skb->dev; if (!dev) @@ -3211,9 +3217,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) } nsec = &netif->nsec; - isec = inode->i_security; - switch (isec->sclass) { + switch (sock_class) { case SECCLASS_UDP_SOCKET: netif_perm = NETIF__UDP_RECV; node_perm = NODE__UDP_RECV; @@ -3242,7 +3247,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) goto out; } - err = avc_has_perm(isec->sid, nsec->if_sid, SECCLASS_NETIF, + err = avc_has_perm(sock_sid, nsec->if_sid, SECCLASS_NETIF, netif_perm, &nsec->avcr, &ad); sel_netif_put(netif); if (err) @@ -3253,7 +3258,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (err) goto out; - err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad); + err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad); if (err) goto out; @@ -3267,7 +3272,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (err) goto out; - err = avc_has_perm(isec->sid, port_sid, isec->sclass, + err = avc_has_perm(sock_sid, port_sid, sock_class, recv_perm, NULL, &ad); } out: @@ -3545,7 +3550,7 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg) static void selinux_msg_msg_free_security(struct msg_msg *msg) { - msg_msg_free_security(msg); + return msg_msg_free_security(msg); } /* message queue security operations */ @@ -3781,7 +3786,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) } static int selinux_shm_shmat(struct shmid_kernel *shp, - char __user *shmaddr, int shmflg) + char *shmaddr, int shmflg) { u32 perms; diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c new file mode 100644 index 000000000..08f159cfc --- /dev/null +++ b/security/selinux/nlmsgtab.c @@ -0,0 +1,153 @@ +/* + * Netlink message type permission tables, for user generated messages. + * + * Author: James Morris + * + * Copyright (C) 2004 Red Hat, Inc., James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flask.h" +#include "av_permissions.h" + +struct nlmsg_perm +{ + u16 nlmsg_type; + u32 perm; +}; + +static struct nlmsg_perm nlmsg_route_perms[] = +{ + { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, +}; + +static struct nlmsg_perm nlmsg_firewall_perms[] = +{ + { IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, + { IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, +}; + +static struct nlmsg_perm nlmsg_tcpdiag_perms[] = +{ + { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, +}; + +static struct nlmsg_perm nlmsg_xfrm_perms[] = +{ + { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, +}; + +static struct nlmsg_perm nlmsg_audit_perms[] = +{ + { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_LOGIN, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, +}; + + +static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize) +{ + int i, err = -EINVAL; + + for (i = 0; i < tabsize/sizeof(struct nlmsg_perm); i++) + if (nlmsg_type == tab[i].nlmsg_type) { + *perm = tab[i].perm; + err = 0; + break; + } + + return err; +} + +int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) +{ + int err = 0; + + switch (sclass) { + case SECCLASS_NETLINK_ROUTE_SOCKET: + err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, + sizeof(nlmsg_route_perms)); + break; + + case SECCLASS_NETLINK_FIREWALL_SOCKET: + case NETLINK_IP6_FW: + err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms, + sizeof(nlmsg_firewall_perms)); + break; + + case SECCLASS_NETLINK_TCPDIAG_SOCKET: + err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, + sizeof(nlmsg_tcpdiag_perms)); + break; + + case SECCLASS_NETLINK_XFRM_SOCKET: + err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, + sizeof(nlmsg_xfrm_perms)); + break; + + case SECCLASS_NETLINK_AUDIT_SOCKET: + err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms, + sizeof(nlmsg_audit_perms)); + break; + + /* No messaging from userspace, or class unknown/unhandled */ + default: + err = -ENOENT; + break; + } + + return err; +} diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 975a17708..274275a61 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -68,7 +68,7 @@ enum sel_inos { SEL_DISABLE /* disable SELinux until next reboot */ }; -static ssize_t sel_read_enforce(struct file *filp, char __user *buf, +static ssize_t sel_read_enforce(struct file *filp, char *buf, size_t count, loff_t *ppos) { char *page; @@ -105,7 +105,7 @@ out: } #ifdef CONFIG_SECURITY_SELINUX_DEVELOP -static ssize_t sel_write_enforce(struct file * file, const char __user * buf, +static ssize_t sel_write_enforce(struct file * file, const char * buf, size_t count, loff_t *ppos) { @@ -155,7 +155,7 @@ static struct file_operations sel_enforce_ops = { }; #ifdef CONFIG_SECURITY_SELINUX_DISABLE -static ssize_t sel_write_disable(struct file * file, const char __user * buf, +static ssize_t sel_write_disable(struct file * file, const char * buf, size_t count, loff_t *ppos) { @@ -201,7 +201,7 @@ static struct file_operations sel_disable_ops = { .write = sel_write_disable, }; -static ssize_t sel_read_policyvers(struct file *filp, char __user *buf, +static ssize_t sel_read_policyvers(struct file *filp, char *buf, size_t count, loff_t *ppos) { char *page; @@ -244,7 +244,7 @@ static struct file_operations sel_policyvers_ops = { /* declaration for sel_write_load */ static int sel_make_bools(void); -static ssize_t sel_read_mls(struct file *filp, char __user *buf, +static ssize_t sel_read_mls(struct file *filp, char *buf, size_t count, loff_t *ppos) { char *page; @@ -284,7 +284,7 @@ static struct file_operations sel_mls_ops = { .read = sel_read_mls, }; -static ssize_t sel_write_load(struct file * file, const char __user * buf, +static ssize_t sel_write_load(struct file * file, const char * buf, size_t count, loff_t *ppos) { @@ -334,7 +334,7 @@ static struct file_operations sel_load_ops = { }; -static ssize_t sel_write_context(struct file * file, const char __user * buf, +static ssize_t sel_write_context(struct file * file, const char * buf, size_t count, loff_t *ppos) { @@ -406,7 +406,7 @@ struct argresp { * possibly a read which collects the result - which is stored in a * file-local buffer. */ -static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) +static ssize_t TA_write(struct file *file, const char *buf, size_t size, loff_t *pos) { ino_t ino = file->f_dentry->d_inode->i_ino; struct argresp *ar; @@ -445,7 +445,7 @@ static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, return rv; } -static ssize_t TA_read(struct file *file, char __user *buf, size_t size, loff_t *pos) +static ssize_t TA_read(struct file *file, char *buf, size_t size, loff_t *pos) { struct argresp *ar; ssize_t rv = 0; @@ -744,7 +744,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode) #define BOOL_INO_OFFSET 30 -static ssize_t sel_read_bool(struct file *filep, char __user *buf, +static ssize_t sel_read_bool(struct file *filep, char *buf, size_t count, loff_t *ppos) { char *page = NULL; @@ -806,7 +806,7 @@ out: return ret; } -static ssize_t sel_write_bool(struct file *filep, const char __user *buf, +static ssize_t sel_write_bool(struct file *filep, const char *buf, size_t count, loff_t *ppos) { char *page = NULL; @@ -865,8 +865,7 @@ static struct file_operations sel_bool_ops = { .write = sel_write_bool, }; -static ssize_t sel_commit_bools_write(struct file *filep, - const char __user *buf, +static ssize_t sel_commit_bools_write(struct file *filep, const char *buf, size_t count, loff_t *ppos) { char *page = NULL; diff --git a/sound/core/control.c b/sound/core/control.c index 7cc19394d..95e84dfe1 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -512,7 +512,7 @@ snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id) } static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl, - unsigned int cmd, void __user *arg) + unsigned int cmd, unsigned long arg) { snd_ctl_card_info_t info; @@ -526,12 +526,12 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl, strlcpy(info.mixername, card->mixername, sizeof(info.mixername)); strlcpy(info.components, card->components, sizeof(info.components)); up_read(&snd_ioctl_rwsem); - if (copy_to_user(arg, &info, sizeof(snd_ctl_card_info_t))) + if (copy_to_user((void *) arg, &info, sizeof(snd_ctl_card_info_t))) return -EFAULT; return 0; } -static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list) +static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t *_list) { struct list_head *plist; snd_ctl_elem_list_t list; @@ -593,7 +593,7 @@ static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list return 0; } -static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info) +static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *_info) { snd_card_t *card = ctl->card; snd_ctl_elem_info_t info; @@ -636,7 +636,7 @@ static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_i return result; } -static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_control) +static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control) { snd_ctl_elem_value_t *control; snd_kcontrol_t *kctl; @@ -676,7 +676,7 @@ static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_con return result; } -static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control) +static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *_control) { snd_card_t *card = file->card; snd_ctl_elem_value_t *control; @@ -726,7 +726,7 @@ static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user return result; } -static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id) +static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id) { snd_card_t *card = file->card; snd_ctl_elem_id_t id; @@ -754,7 +754,7 @@ static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id return result; } -static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id) +static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id) { snd_card_t *card = file->card; snd_ctl_elem_id_t id; @@ -840,7 +840,7 @@ static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol) kfree(kcontrol->private_data); } -static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace) +static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, int replace) { snd_card_t *card = file->card; snd_ctl_elem_info_t info; @@ -965,7 +965,7 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_i return 0; } -static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id) +static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id) { snd_ctl_elem_id_t id; @@ -974,7 +974,7 @@ static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_ return snd_ctl_remove_unlocked_id(file, &id); } -static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr) +static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr) { int subscribe; if (get_user(subscribe, ptr)) @@ -1029,8 +1029,6 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file, snd_card_t *card; struct list_head *list; snd_kctl_ioctl_t *p; - void __user *argp = (void __user *)arg; - int __user *ip = argp; int err; ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); @@ -1038,31 +1036,31 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file, snd_assert(card != NULL, return -ENXIO); switch (cmd) { case SNDRV_CTL_IOCTL_PVERSION: - return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0; + return put_user(SNDRV_CTL_VERSION, (int *)arg) ? -EFAULT : 0; case SNDRV_CTL_IOCTL_CARD_INFO: - return snd_ctl_card_info(card, ctl, cmd, argp); + return snd_ctl_card_info(card, ctl, cmd, arg); case SNDRV_CTL_IOCTL_ELEM_LIST: - return snd_ctl_elem_list(ctl->card, argp); + return snd_ctl_elem_list(ctl->card, (snd_ctl_elem_list_t *) arg); case SNDRV_CTL_IOCTL_ELEM_INFO: - return snd_ctl_elem_info(ctl, argp); + return snd_ctl_elem_info(ctl, (snd_ctl_elem_info_t *) arg); case SNDRV_CTL_IOCTL_ELEM_READ: - return snd_ctl_elem_read(ctl->card, argp); + return snd_ctl_elem_read(ctl->card, (snd_ctl_elem_value_t *) arg); case SNDRV_CTL_IOCTL_ELEM_WRITE: - return snd_ctl_elem_write(ctl, argp); + return snd_ctl_elem_write(ctl, (snd_ctl_elem_value_t *) arg); case SNDRV_CTL_IOCTL_ELEM_LOCK: - return snd_ctl_elem_lock(ctl, argp); + return snd_ctl_elem_lock(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_ELEM_UNLOCK: - return snd_ctl_elem_unlock(ctl, argp); + return snd_ctl_elem_unlock(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_ELEM_ADD: - return snd_ctl_elem_add(ctl, argp, 0); + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 0); case SNDRV_CTL_IOCTL_ELEM_REPLACE: - return snd_ctl_elem_add(ctl, argp, 1); + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 1); case SNDRV_CTL_IOCTL_ELEM_REMOVE: - return snd_ctl_elem_remove(ctl, argp); + return snd_ctl_elem_remove(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: - return snd_ctl_subscribe_events(ctl, ip); + return snd_ctl_subscribe_events(ctl, (int *) arg); case SNDRV_CTL_IOCTL_POWER: - if (get_user(err, ip)) + if (get_user(err, (int *)arg)) return -EFAULT; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1077,9 +1075,9 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file, return err; case SNDRV_CTL_IOCTL_POWER_STATE: #ifdef CONFIG_PM - return put_user(card->power_state, ip) ? -EFAULT : 0; + return put_user(card->power_state, (int *)arg) ? -EFAULT : 0; #else - return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; + return put_user(SNDRV_CTL_POWER_D0, (int *)arg) ? -EFAULT : 0; #endif } down_read(&snd_ioctl_rwsem); @@ -1096,7 +1094,7 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file, return -ENOTTY; } -static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset) +static ssize_t snd_ctl_read(struct file *file, char *buffer, size_t count, loff_t * offset) { snd_ctl_file_t *ctl; int err = 0; diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile index e6d5a045b..714b1a6d8 100644 --- a/sound/core/oss/Makefile +++ b/sound/core/oss/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 1999 by Jaroslav Kysela # +CFLAGS_pcm_plugin.o += -g0 snd-mixer-oss-objs := mixer_oss.o snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \ diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 65b5017e4..75cea7e24 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -806,7 +806,7 @@ static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *bu return bytes; } -static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __user *buf, size_t bytes) +static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char *buf, size_t bytes) { size_t xfer = 0; ssize_t tmp; @@ -883,7 +883,7 @@ static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size return bytes; } -static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *buf, size_t bytes) +static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char *buf, size_t bytes) { size_t xfer = 0; ssize_t tmp; @@ -1067,9 +1067,9 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file) snd_pcm_lib_write(substream, runtime->oss.buffer, size1); } } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { - void __user *buffers[runtime->channels]; + void *buffers[runtime->channels]; memset(buffers, 0, runtime->channels * sizeof(void *)); - snd_pcm_lib_writev(substream, buffers, size); + snd_pcm_lib_writev(substream, (void **)buffers, size); } } /* @@ -1468,7 +1468,7 @@ static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file) return snd_pcm_oss_bytes(substream, delay); } -static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct count_info __user * _info) +static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct count_info * _info) { snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; @@ -1530,7 +1530,7 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str return 0; } -static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct audio_buf_info __user *_info) +static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct audio_buf_info *_info) { snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; @@ -1589,7 +1589,7 @@ static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, s return 0; } -static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc __user * _info) +static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc * _info) { // it won't be probably implemented // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n"); @@ -1912,14 +1912,13 @@ static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { snd_pcm_oss_file_t *pcm_oss_file; - int __user *p = (int __user *)arg; int res; pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); if (cmd == OSS_GETVERSION) - return put_user(SNDRV_OSS_VERSION, p); + return put_user(SNDRV_OSS_VERSION, (int *)arg); if (cmd == OSS_ALSAEMULVER) - return put_user(1, p); + return put_user(1, (int *)arg); #if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE)) if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ snd_pcm_substream_t *substream; @@ -1944,93 +1943,93 @@ static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_SYNC: return snd_pcm_oss_sync(pcm_oss_file); case SNDCTL_DSP_SPEED: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SOUND_PCM_READ_RATE: res = snd_pcm_oss_get_rate(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_STEREO: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; res = res > 0 ? 2 : 1; if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) return res; - return put_user(--res, p); + return put_user(--res, (int *)arg); case SNDCTL_DSP_GETBLKSIZE: res = snd_pcm_oss_get_block_size(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_SETFMT: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_format(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SOUND_PCM_READ_BITS: res = snd_pcm_oss_get_format(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_CHANNELS: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SOUND_PCM_READ_CHANNELS: res = snd_pcm_oss_get_channels(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EIO; case SNDCTL_DSP_POST: return snd_pcm_oss_post(pcm_oss_file); case SNDCTL_DSP_SUBDIVIDE: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; return snd_pcm_oss_set_fragment(pcm_oss_file, res); case SNDCTL_DSP_GETFMTS: res = snd_pcm_oss_get_formats(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: return snd_pcm_oss_get_space(pcm_oss_file, cmd == SNDCTL_DSP_GETISPACE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct audio_buf_info __user *) arg); + (struct audio_buf_info *) arg); case SNDCTL_DSP_NONBLOCK: return snd_pcm_oss_nonblock(file); case SNDCTL_DSP_GETCAPS: res = snd_pcm_oss_get_caps(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_GETTRIGGER: res = snd_pcm_oss_get_trigger(pcm_oss_file); if (res < 0) return res; - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - if (get_user(res, p)) + if (get_user(res, (int *)arg)) return -EFAULT; return snd_pcm_oss_set_trigger(pcm_oss_file, res); case SNDCTL_DSP_GETIPTR: @@ -2038,13 +2037,13 @@ static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, return snd_pcm_oss_get_ptr(pcm_oss_file, cmd == SNDCTL_DSP_GETIPTR ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct count_info __user *) arg); + (struct count_info *) arg); case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: return snd_pcm_oss_get_mapbuf(pcm_oss_file, cmd == SNDCTL_DSP_MAPINBUF ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct buffmem_desc __user *) arg); + (struct buffmem_desc *) arg); case SNDCTL_DSP_SETSYNCRO: /* stop DMA now.. */ return 0; @@ -2056,10 +2055,10 @@ static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, res = snd_pcm_oss_get_odelay(pcm_oss_file); if (res < 0) { /* it's for sure, some broken apps don't check for error codes */ - put_user(0, p); + put_user(0, (int *)arg); return res; } - return put_user(res, p); + return put_user(res, (int *)arg); case SNDCTL_DSP_PROFILE: return 0; /* silently ignore */ default: @@ -2068,7 +2067,7 @@ static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file, return -EINVAL; } -static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +static ssize_t snd_pcm_oss_read(struct file *file, char *buf, size_t count, loff_t *offset) { snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; @@ -2088,7 +2087,7 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun #endif } -static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +static ssize_t snd_pcm_oss_write(struct file *file, const char *buf, size_t count, loff_t *offset) { snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 15ed2b9b3..38d564186 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -56,8 +56,8 @@ struct sndrv_pcm_hw_params_old { #define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) #define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) -static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams); -static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams); +static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams); +static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams); /* * @@ -108,7 +108,7 @@ int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info) return 0; } -int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _info) +int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t * _info) { snd_pcm_info_t info; int err = snd_pcm_info(substream, &info); @@ -302,7 +302,7 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream, return 0; } -static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) +static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * _params) { snd_pcm_hw_params_t params; int err; @@ -406,7 +406,7 @@ static int snd_pcm_hw_params(snd_pcm_substream_t *substream, return err; } -static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) +static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * _params) { snd_pcm_hw_params_t params; int err; @@ -494,7 +494,7 @@ static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_ return 0; } -static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_params_t __user * _params) +static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_params_t * _params) { snd_pcm_sw_params_t params; int err; @@ -550,7 +550,7 @@ int snd_pcm_status(snd_pcm_substream_t *substream, return 0; } -static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t __user * _status) +static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t * _status) { snd_pcm_status_t status; snd_pcm_runtime_t *runtime; @@ -567,7 +567,7 @@ static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t return 0; } -static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info) +static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * _info) { snd_pcm_channel_info_t info; snd_pcm_runtime_t *runtime; @@ -2297,7 +2297,7 @@ static int snd_pcm_hwsync(snd_pcm_substream_t *substream) return err; } -static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res) +static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res) { snd_pcm_runtime_t *runtime = substream->runtime; int err; @@ -2335,7 +2335,7 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __use return err; } -static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr __user *_sync_ptr) +static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr *_sync_ptr) { snd_pcm_runtime_t *runtime = substream->runtime; struct sndrv_pcm_sync_ptr sync_ptr; @@ -2344,7 +2344,7 @@ static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_syn int err; memset(&sync_ptr, 0, sizeof(sync_ptr)); - if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) + if (get_user(sync_ptr.flags, (unsigned int *) &(_sync_ptr->flags))) return -EFAULT; if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct sndrv_pcm_mmap_control))) return -EFAULT; @@ -2375,40 +2375,40 @@ static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_syn } static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, - unsigned int cmd, void __user *arg); + unsigned int cmd, void *arg); static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, - unsigned int cmd, void __user *arg); + unsigned int cmd, void *arg); static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, - unsigned int cmd, void __user *arg) + unsigned int cmd, void *arg) { snd_assert(substream != NULL, return -ENXIO); switch (cmd) { case SNDRV_PCM_IOCTL_PVERSION: - return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; + return put_user(SNDRV_PCM_VERSION, (int *)arg) ? -EFAULT : 0; case SNDRV_PCM_IOCTL_INFO: - return snd_pcm_info_user(substream, arg); + return snd_pcm_info_user(substream, (snd_pcm_info_t *) arg); case SNDRV_PCM_IOCTL_TSTAMP: { int xarg; - if (get_user(xarg, (int __user *)arg)) + if (get_user(xarg, (int *) arg)) return -EFAULT; substream->runtime->tstamp_timespec = xarg ? 1 : 0; return 0; } case SNDRV_PCM_IOCTL_HW_REFINE: - return snd_pcm_hw_refine_user(substream, arg); + return snd_pcm_hw_refine_user(substream, (snd_pcm_hw_params_t *) arg); case SNDRV_PCM_IOCTL_HW_PARAMS: - return snd_pcm_hw_params_user(substream, arg); + return snd_pcm_hw_params_user(substream, (snd_pcm_hw_params_t *) arg); case SNDRV_PCM_IOCTL_HW_FREE: return snd_pcm_hw_free(substream); case SNDRV_PCM_IOCTL_SW_PARAMS: - return snd_pcm_sw_params_user(substream, arg); + return snd_pcm_sw_params_user(substream, (snd_pcm_sw_params_t *) arg); case SNDRV_PCM_IOCTL_STATUS: - return snd_pcm_status_user(substream, arg); + return snd_pcm_status_user(substream, (snd_pcm_status_t *) arg); case SNDRV_PCM_IOCTL_CHANNEL_INFO: - return snd_pcm_channel_info(substream, arg); + return snd_pcm_channel_info(substream, (snd_pcm_channel_info_t *) arg); case SNDRV_PCM_IOCTL_PREPARE: return snd_pcm_prepare(substream); case SNDRV_PCM_IOCTL_RESET: @@ -2416,7 +2416,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, case SNDRV_PCM_IOCTL_START: return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, 0, 0); case SNDRV_PCM_IOCTL_LINK: - return snd_pcm_link(substream, (int)(unsigned long) arg); + return snd_pcm_link(substream, (long) arg); case SNDRV_PCM_IOCTL_UNLINK: return snd_pcm_unlink(substream); case SNDRV_PCM_IOCTL_RESUME: @@ -2426,28 +2426,27 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, case SNDRV_PCM_IOCTL_HWSYNC: return snd_pcm_hwsync(substream); case SNDRV_PCM_IOCTL_DELAY: - return snd_pcm_delay(substream, arg); + return snd_pcm_delay(substream, (snd_pcm_sframes_t *) arg); case SNDRV_PCM_IOCTL_SYNC_PTR: - return snd_pcm_sync_ptr(substream, arg); + return snd_pcm_sync_ptr(substream, (struct sndrv_pcm_sync_ptr *) arg); case SNDRV_PCM_IOCTL_HW_REFINE_OLD: - return snd_pcm_hw_refine_old_user(substream, arg); + return snd_pcm_hw_refine_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg); case SNDRV_PCM_IOCTL_HW_PARAMS_OLD: - return snd_pcm_hw_params_old_user(substream, arg); + return snd_pcm_hw_params_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg); } snd_printd("unknown ioctl = 0x%x\n", cmd); return -ENOTTY; } static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, - unsigned int cmd, void __user *arg) + unsigned int cmd, void *arg) { snd_assert(substream != NULL, return -ENXIO); snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL); switch (cmd) { case SNDRV_PCM_IOCTL_WRITEI_FRAMES: { - snd_xferi_t xferi; - snd_xferi_t __user *_xferi = arg; + snd_xferi_t xferi, *_xferi = arg; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t result; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) @@ -2462,10 +2461,9 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_WRITEN_FRAMES: { - snd_xfern_t xfern; - snd_xfern_t __user *_xfern = arg; + snd_xfern_t xfern, *_xfern = arg; snd_pcm_runtime_t *runtime = substream->runtime; - void __user **bufs; + void *bufs; snd_pcm_sframes_t result; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2489,8 +2487,7 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_REWIND: { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_uframes_t frames, *_frames = arg; snd_pcm_sframes_t result; if (get_user(frames, _frames)) return -EFAULT; @@ -2502,8 +2499,7 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_FORWARD: { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_uframes_t frames, *_frames = arg; snd_pcm_sframes_t result; if (get_user(frames, _frames)) return -EFAULT; @@ -2517,7 +2513,7 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, { int res; snd_pcm_stream_lock_irq(substream); - res = snd_pcm_pause(substream, (int)(unsigned long)arg); + res = snd_pcm_pause(substream, (long) arg); snd_pcm_stream_unlock_irq(substream); return res; } @@ -2530,15 +2526,14 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, } static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, - unsigned int cmd, void __user *arg) + unsigned int cmd, void *arg) { snd_assert(substream != NULL, return -ENXIO); snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL); switch (cmd) { case SNDRV_PCM_IOCTL_READI_FRAMES: { - snd_xferi_t xferi; - snd_xferi_t __user *_xferi = arg; + snd_xferi_t xferi, *_xferi = arg; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t result; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) @@ -2553,8 +2548,7 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_READN_FRAMES: { - snd_xfern_t xfern; - snd_xfern_t __user *_xfern = arg; + snd_xfern_t xfern, *_xfern = arg; snd_pcm_runtime_t *runtime = substream->runtime; void *bufs; snd_pcm_sframes_t result; @@ -2580,8 +2574,7 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_REWIND: { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_uframes_t frames, *_frames = arg; snd_pcm_sframes_t result; if (get_user(frames, _frames)) return -EFAULT; @@ -2593,8 +2586,7 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, } case SNDRV_PCM_IOCTL_FORWARD: { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_uframes_t frames, *_frames = arg; snd_pcm_sframes_t result; if (get_user(frames, _frames)) return -EFAULT; @@ -2622,7 +2614,7 @@ static int snd_pcm_playback_ioctl(struct inode *inode, struct file *file, if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; - return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); + return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void *) arg); } static int snd_pcm_capture_ioctl(struct inode *inode, struct file *file, @@ -2635,7 +2627,7 @@ static int snd_pcm_capture_ioctl(struct inode *inode, struct file *file, if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; - return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); + return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void *) arg); } int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream, @@ -2675,7 +2667,7 @@ int snd_pcm_kernel_ioctl(snd_pcm_substream_t *substream, } } -static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t * offset) +static ssize_t snd_pcm_read(struct file *file, char *buf, size_t count, loff_t * offset) { snd_pcm_file_t *pcm_file; snd_pcm_substream_t *substream; @@ -2697,7 +2689,7 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, l return result; } -static ssize_t snd_pcm_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) +static ssize_t snd_pcm_write(struct file *file, const char *buf, size_t count, loff_t * offset) { snd_pcm_file_t *pcm_file; snd_pcm_substream_t *substream; @@ -2733,7 +2725,7 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, snd_pcm_runtime_t *runtime; snd_pcm_sframes_t result; unsigned long i; - void __user **bufs; + void **bufs; snd_pcm_uframes_t frames; pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); @@ -2767,7 +2759,7 @@ static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector, snd_pcm_runtime_t *runtime; snd_pcm_sframes_t result; unsigned long i; - void __user **bufs; + void **bufs; snd_pcm_uframes_t frames; pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end); @@ -3131,7 +3123,7 @@ static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *opa oparams->fifo_size = params->fifo_size; } -static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) +static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams) { snd_pcm_hw_params_t params; struct sndrv_pcm_hw_params_old oparams; @@ -3146,7 +3138,7 @@ static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sn return err; } -static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) +static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams) { snd_pcm_hw_params_t params; struct sndrv_pcm_hw_params_old oparams; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index df904d18d..abc2221d7 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -543,7 +543,7 @@ int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *inf return 0; } -static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t __user * _info) +static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t * _info) { snd_rawmidi_info_t info; int err; @@ -579,7 +579,7 @@ int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info) } static int snd_rawmidi_info_select_user(snd_card_t *card, - snd_rawmidi_info_t __user *_info) + snd_rawmidi_info_t *_info) { int err; snd_rawmidi_info_t info; @@ -679,18 +679,17 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { snd_rawmidi_file_t *rfile; - void __user *argp = (void __user *)arg; rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); if (((cmd >> 8) & 0xff) != 'W') return -ENOTTY; switch (cmd) { case SNDRV_RAWMIDI_IOCTL_PVERSION: - return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0; + return put_user(SNDRV_RAWMIDI_VERSION, (int *)arg) ? -EFAULT : 0; case SNDRV_RAWMIDI_IOCTL_INFO: { snd_rawmidi_stream_t stream; - snd_rawmidi_info_t __user *info = argp; + snd_rawmidi_info_t *info = (snd_rawmidi_info_t *) arg; if (get_user(stream, &info->stream)) return -EFAULT; switch (stream) { @@ -705,7 +704,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, case SNDRV_RAWMIDI_IOCTL_PARAMS: { snd_rawmidi_params_t params; - if (copy_from_user(¶ms, argp, sizeof(snd_rawmidi_params_t))) + if (copy_from_user(¶ms, (snd_rawmidi_params_t *) arg, sizeof(snd_rawmidi_params_t))) return -EFAULT; switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: @@ -724,7 +723,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, { int err = 0; snd_rawmidi_status_t status; - if (copy_from_user(&status, argp, sizeof(snd_rawmidi_status_t))) + if (copy_from_user(&status, (snd_rawmidi_status_t *) arg, sizeof(snd_rawmidi_status_t))) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: @@ -742,14 +741,14 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, } if (err < 0) return err; - if (copy_to_user(argp, &status, sizeof(snd_rawmidi_status_t))) + if (copy_to_user((snd_rawmidi_status_t *) arg, &status, sizeof(snd_rawmidi_status_t))) return -EFAULT; return 0; } case SNDRV_RAWMIDI_IOCTL_DROP: { int val; - if (get_user(val, (long __user *) argp)) + if (get_user(val, (long *) arg)) return -EFAULT; switch (val) { case SNDRV_RAWMIDI_STREAM_OUTPUT: @@ -763,7 +762,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, case SNDRV_RAWMIDI_IOCTL_DRAIN: { int val; - if (get_user(val, (long __user *) argp)) + if (get_user(val, (long *) arg)) return -EFAULT; switch (val) { case SNDRV_RAWMIDI_STREAM_OUTPUT: @@ -789,7 +788,6 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file, int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, unsigned int cmd, unsigned long arg) { - void __user *argp = (void __user *)arg; unsigned int tmp; tmp = card->number * SNDRV_RAWMIDI_DEVICES; @@ -798,7 +796,7 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, { int device; - if (get_user(device, (int __user *)argp)) + if (get_user(device, (int *)arg)) return -EFAULT; device = device < 0 ? 0 : device + 1; while (device < SNDRV_RAWMIDI_DEVICES) { @@ -808,7 +806,7 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, } if (device == SNDRV_RAWMIDI_DEVICES) device = -1; - if (put_user(device, (int __user *)argp)) + if (put_user(device, (int *)arg)) return -EFAULT; return 0; } @@ -816,13 +814,13 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, { int val; - if (get_user(val, (int __user *)argp)) + if (get_user(val, (int *)arg)) return -EFAULT; control->prefer_rawmidi_subdevice = val; return 0; } case SNDRV_CTL_IOCTL_RAWMIDI_INFO: - return snd_rawmidi_info_select_user(card, argp); + return snd_rawmidi_info_select_user(card, (snd_rawmidi_info_t *)arg); } return -ENOIOCTLCMD; } @@ -936,7 +934,7 @@ long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char * return snd_rawmidi_kernel_read1(substream, buf, count, 1); } -static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +static ssize_t snd_rawmidi_read(struct file *file, char *buf, size_t count, loff_t *offset) { long result; int count1; @@ -1168,7 +1166,7 @@ long snd_rawmidi_kernel_write(snd_rawmidi_substream_t * substream, const unsigne return snd_rawmidi_kernel_write1(substream, buf, count, 1); } -static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +static ssize_t snd_rawmidi_write(struct file *file, const char *buf, size_t count, loff_t *offset) { long result, timeout; int count1; diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 5681563fa..50a3740bf 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -57,8 +57,8 @@ static void unregister_proc(void); static int odev_open(struct inode *inode, struct file *file); static int odev_release(struct inode *inode, struct file *file); -static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset); -static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset); +static ssize_t odev_read(struct file *file, char *buf, size_t count, loff_t *offset); +static ssize_t odev_write(struct file *file, const char *buf, size_t count, loff_t *offset); static int odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static unsigned int odev_poll(struct file *file, poll_table * wait); #ifdef CONFIG_PROC_FS @@ -155,7 +155,7 @@ odev_release(struct inode *inode, struct file *file) } static ssize_t -odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +odev_read(struct file *file, char *buf, size_t count, loff_t *offset) { seq_oss_devinfo_t *dp; dp = file->private_data; @@ -165,7 +165,7 @@ odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) static ssize_t -odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +odev_write(struct file *file, const char *buf, size_t count, loff_t *offset) { seq_oss_devinfo_t *dp; dp = file->private_data; diff --git a/sound/core/timer.c b/sound/core/timer.c index 6f6d89c43..956ea2a16 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1253,7 +1253,7 @@ static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer) id->subdevice = timer->tmr_subdevice; } -static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) +static int snd_timer_user_next_device(snd_timer_id_t *_tid) { snd_timer_id_t id; snd_timer_t *timer; @@ -1344,7 +1344,7 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) return 0; } -static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo) +static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo) { snd_timer_ginfo_t ginfo; snd_timer_id_t tid; @@ -1382,7 +1382,7 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_gi return err; } -static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams) +static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gparams) { snd_timer_gparams_t gparams; snd_timer_t *t; @@ -1408,7 +1408,7 @@ static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user return err; } -static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus) +static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstatus) { snd_timer_gstatus_t gstatus; snd_timer_id_t tid; @@ -1437,12 +1437,12 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user err = -ENODEV; } up(®ister_mutex); - if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) + if (err >= 0 && copy_from_user(_gstatus, &gstatus, sizeof(gstatus))) err = -EFAULT; return err; } -static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect) +static int snd_timer_user_tselect(struct file *file, snd_timer_select_t *_tselect) { snd_timer_user_t *tu; snd_timer_select_t tselect; @@ -1489,7 +1489,7 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * return 0; } -static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) +static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info) { snd_timer_user_t *tu; snd_timer_info_t info; @@ -1511,7 +1511,7 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info return 0; } -static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params) +static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params) { snd_timer_user_t *tu; snd_timer_params_t params; @@ -1603,7 +1603,7 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ return err; } -static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status) +static int snd_timer_user_status(struct file *file, snd_timer_status_t *_status) { snd_timer_user_t *tu; snd_timer_status_t status; @@ -1661,40 +1661,38 @@ static int snd_timer_user_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; - void __user *argp = (void __user *)arg; - int __user *p = argp; tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); switch (cmd) { case SNDRV_TIMER_IOCTL_PVERSION: - return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; + return put_user(SNDRV_TIMER_VERSION, (int *)arg) ? -EFAULT : 0; case SNDRV_TIMER_IOCTL_NEXT_DEVICE: - return snd_timer_user_next_device(argp); + return snd_timer_user_next_device((snd_timer_id_t *)arg); case SNDRV_TIMER_IOCTL_TREAD: { int xarg; if (tu->timeri) /* too late */ return -EBUSY; - if (get_user(xarg, p)) + if (get_user(xarg, (int *) arg)) return -EFAULT; tu->tread = xarg ? 1 : 0; return 0; } case SNDRV_TIMER_IOCTL_GINFO: - return snd_timer_user_ginfo(file, argp); + return snd_timer_user_ginfo(file, (snd_timer_ginfo_t *)arg); case SNDRV_TIMER_IOCTL_GPARAMS: - return snd_timer_user_gparams(file, argp); + return snd_timer_user_gparams(file, (snd_timer_gparams_t *)arg); case SNDRV_TIMER_IOCTL_GSTATUS: - return snd_timer_user_gstatus(file, argp); + return snd_timer_user_gstatus(file, (snd_timer_gstatus_t *)arg); case SNDRV_TIMER_IOCTL_SELECT: - return snd_timer_user_tselect(file, argp); + return snd_timer_user_tselect(file, (snd_timer_select_t *)arg); case SNDRV_TIMER_IOCTL_INFO: - return snd_timer_user_info(file, argp); + return snd_timer_user_info(file, (snd_timer_info_t *)arg); case SNDRV_TIMER_IOCTL_PARAMS: - return snd_timer_user_params(file, argp); + return snd_timer_user_params(file, (snd_timer_params_t *)arg); case SNDRV_TIMER_IOCTL_STATUS: - return snd_timer_user_status(file, argp); + return snd_timer_user_status(file, (snd_timer_status_t *)arg); case SNDRV_TIMER_IOCTL_START: return snd_timer_user_start(file); case SNDRV_TIMER_IOCTL_STOP: @@ -1717,7 +1715,7 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on) return 0; } -static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) +static ssize_t snd_timer_user_read(struct file *file, char *buffer, size_t count, loff_t *offset) { snd_timer_user_t *tu; long result = 0, unit; diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 9ecd53c21..2590ababc 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -87,14 +87,14 @@ read_word(const void __user *buf, int offset, int mode) unsigned short c; if (mode & SNDRV_SFNT_SAMPLE_8BITS) { unsigned char cc; - get_user(cc, (unsigned char __user *)buf + offset); + get_user(cc, (unsigned char*)buf + offset); c = cc << 8; /* convert 8bit -> 16bit */ } else { #ifdef SNDRV_LITTLE_ENDIAN - get_user(c, (unsigned short __user *)buf + offset); + get_user(c, (unsigned short*)buf + offset); #else unsigned short cc; - get_user(cc, (unsigned short __user *)buf + offset); + get_user(cc, (unsigned short*)buf + offset); c = swab16(cc); #endif } diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index c45061308..29e9df772 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -455,7 +455,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) * Upload a byte-stream into the SoundScape using DMA channel A. */ static int upload_dma_data(struct soundscape *s, - const unsigned char __user *data, + const unsigned char *data, size_t size) { unsigned long flags; @@ -569,7 +569,7 @@ static int upload_dma_data(struct soundscape *s, * However, we have already verified its memory * addresses by the time we get here. */ -static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb) +static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock *bb) { unsigned long flags; int data = 0; @@ -604,10 +604,10 @@ static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_boot * SPACE, and save ourselves from copying it at all. */ static int sscape_upload_microcode(struct soundscape *sscape, - const struct sscape_microcode __user *mc) + const struct sscape_microcode *mc) { unsigned long flags; - char __user *code; + char *code; int err, ret; /* @@ -683,7 +683,7 @@ static int sscape_hw_ioctl(snd_hwdep_t * hw, struct file *file, switch (cmd) { case SND_SSCAPE_LOAD_BOOTB: { - register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg; + register struct sscape_bootblock *bb = (struct sscape_bootblock *) arg; /* * We are going to have to copy this data into a special @@ -705,7 +705,7 @@ static int sscape_hw_ioctl(snd_hwdep_t * hw, struct file *file, case SND_SSCAPE_LOAD_MCODE: { - register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg; + register const struct sscape_microcode *mc = (const struct sscape_microcode *) arg; err = sscape_upload_microcode(sscape, mc); } diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 9b65db0b1..af561df2a 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -861,7 +861,7 @@ wavefront_freemem (snd_wavefront_t *dev) static int wavefront_send_sample (snd_wavefront_t *dev, wavefront_patch_info *header, - u16 __user *dataptr, + u16 *dataptr, int data_is_unsigned) { @@ -876,7 +876,7 @@ wavefront_send_sample (snd_wavefront_t *dev, u16 sample_short; u32 length; - u16 __user *data_end = 0; + u16 *data_end = 0; unsigned int i; const unsigned int max_blksize = 4096/2; unsigned int written; @@ -1355,7 +1355,7 @@ wavefront_find_free_patch (snd_wavefront_t *dev) #endif static int -wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) +wavefront_load_patch (snd_wavefront_t *dev, const char *addr) { wavefront_patch_info header; @@ -1377,7 +1377,8 @@ wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) switch (header.subkey) { case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ - if (copy_from_user (&header.hdr.s, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.s, + (unsigned char *) header.hdrptr, sizeof (wavefront_sample))) return -EFAULT; @@ -1385,7 +1386,8 @@ wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) case WF_ST_MULTISAMPLE: - if (copy_from_user (&header.hdr.s, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.s, + (unsigned char *) header.hdrptr, sizeof (wavefront_multisample))) return -EFAULT; @@ -1394,28 +1396,32 @@ wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) case WF_ST_ALIAS: - if (copy_from_user (&header.hdr.a, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.a, + (unsigned char *) header.hdrptr, sizeof (wavefront_alias))) return -EFAULT; return wavefront_send_alias (dev, &header); case WF_ST_DRUM: - if (copy_from_user (&header.hdr.d, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.d, + (unsigned char *) header.hdrptr, sizeof (wavefront_drum))) return -EFAULT; return wavefront_send_drum (dev, &header); case WF_ST_PATCH: - if (copy_from_user (&header.hdr.p, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.p, + (unsigned char *) header.hdrptr, sizeof (wavefront_patch))) return -EFAULT; return wavefront_send_patch (dev, &header); case WF_ST_PROGRAM: - if (copy_from_user (&header.hdr.pr, header.hdrptr, + if (copy_from_user ((unsigned char *) &header.hdr.pr, + (unsigned char *) header.hdrptr, sizeof (wavefront_program))) return -EFAULT; @@ -1621,7 +1627,6 @@ snd_wavefront_synth_ioctl (snd_hwdep_t *hw, struct file *file, snd_wavefront_t *dev; snd_wavefront_card_t *acard; wavefront_control wc; - void __user *argp = (void __user *)arg; card = (snd_card_t *) hw->card; @@ -1634,18 +1639,18 @@ snd_wavefront_synth_ioctl (snd_hwdep_t *hw, struct file *file, switch (cmd) { case WFCTL_LOAD_SPP: - if (wavefront_load_patch (dev, argp) != 0) { + if (wavefront_load_patch (dev, (char *) arg) != 0) { return -EIO; } break; case WFCTL_WFCMD: - if (copy_from_user (&wc, argp, sizeof (wc))) + if (copy_from_user (&wc, (void *) arg, sizeof (wc))) return -EFAULT; if (wavefront_synth_control (acard, &wc) < 0) { return -EIO; } - if (copy_to_user (argp, &wc, sizeof (wc))) + if (copy_to_user ((void *) arg, &wc, sizeof (wc))) return -EFAULT; break; diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c index f49a2dee4..e53bd2629 100644 --- a/sound/oss/awe_wave.c +++ b/sound/oss/awe_wave.c @@ -3344,10 +3344,10 @@ readbuf_word(int pos) /* read from user buffer */ if (readbuf_flags & AWE_SAMPLE_8BITS) { unsigned char cc; - get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos)); + get_user(cc, (unsigned __user char*)(readbuf_addr + readbuf_offs + pos)); c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */ } else { - get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2)); + get_user(c, (unsigned __user short*)(readbuf_addr + readbuf_offs + pos * 2)); } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) c ^= 0x8000; /* unsigned -> signed */ diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c index a7d067c2d..42c904136 100644 --- a/sound/oss/cmpci.c +++ b/sound/oss/cmpci.c @@ -980,13 +980,13 @@ static void set_ac3(struct cm_state *s, unsigned rate) spin_unlock_irqrestore(&s->lock, flags); } -static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size) +static int trans_ac3(struct cm_state *s, void *dest, const char *source, int size) { int i = size / 2; unsigned long data; unsigned short data16; unsigned long *dst = (unsigned long *) dest; - unsigned short __user *src = (unsigned short __user *)source; + unsigned short *src = (unsigned short *)source; int err; do { @@ -1639,8 +1639,6 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) unsigned long flags; int i, val, j; unsigned char l, r, rl, rr; - void __user *argp = (void __user *)arg; - int __user *p = argp; VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { @@ -1649,7 +1647,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) strlcpy(info.id, "cmpci", sizeof(info.id)); strlcpy(info.name, "C-Media PCI", sizeof(info.name)); info.modify_counter = s->mix.modcnt; - if (copy_to_user(argp, &info, sizeof(info))) + if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } @@ -1658,50 +1656,50 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) memset(&info, 0, sizeof(info)); strlcpy(info.id, "cmpci", sizeof(info.id)); strlcpy(info.name, "C-Media cmpci", sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) + if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); + return put_user(SOUND_VERSION, (int *)arg); if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) return -EINVAL; if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ val = mixer_recmask(s); - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ val = mixer_outmask(s); - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].type) val |= 1 << i; - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].rec) val |= 1 << i; - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].play) val |= 1 << i; - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) val |= 1 << i; - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: - return put_user(0, p); + return put_user(0, (int *)arg); default: i = _IOC_NR(cmd); @@ -1709,7 +1707,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) return -EINVAL; if (!volidx[i]) return -EINVAL; - return put_user(s->mix.vol[volidx[i]-1], p); + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); } } if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) @@ -1717,7 +1715,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) s->mix.modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; i = generic_hweight32(val); for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { @@ -1736,7 +1734,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) return 0; case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) @@ -1756,7 +1754,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; l = val & 0xff; r = (val >> 8) & 0xff; @@ -1831,7 +1829,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) if (!volidx[i]) return -EINVAL; s->mix.vol[volidx[i]-1] = val; - return put_user(s->mix.vol[volidx[i]-1], p); + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); } } @@ -1916,7 +1914,7 @@ static int drain_dac(struct cm_state *s, int nonblock) /* --------------------------------------------------------------------- */ -static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -1977,11 +1975,11 @@ static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, lof } if (s->status & DO_BIGENDIAN_R) { int i, err; - unsigned char *src; - char __user *dst = buffer; + unsigned char *src, *dst; unsigned char data[2]; src = (unsigned char *) (s->dma_adc.rawbuf + swptr); + dst = (unsigned char *) buffer; // copy left/right sample at one time for (i = 0; i < cnt / 2; i++) { data[0] = src[1]; @@ -2018,7 +2016,7 @@ out: return ret; } -static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t cm_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -2118,10 +2116,10 @@ static ssize_t cm_write(struct file *file, const char __user *buffer, size_t cou swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) { int i, err; - const char __user *src = buffer; - unsigned char *dst0, *dst1; + unsigned char *src, *dst0, *dst1; unsigned char data[8]; + src = (unsigned char *) buffer; dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr); dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time @@ -2172,9 +2170,9 @@ static ssize_t cm_write(struct file *file, const char __user *buffer, size_t cou swptr = (swptr + cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { int i, err; - unsigned long __user *src = (unsigned long __user *) buffer; - unsigned long *dst0, *dst1; + unsigned long *src, *dst0, *dst1; + src = (unsigned long *) buffer; dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr); dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time @@ -2191,10 +2189,10 @@ static ssize_t cm_write(struct file *file, const char __user *buffer, size_t cou swptr = (swptr + cnt) % s->dma_dac.dmasize; } else if (s->status & DO_BIGENDIAN_W) { int i, err; - const char __user *src = buffer; - unsigned char *dst; + unsigned char *src, *dst; unsigned char data[2]; + src = (unsigned char *) buffer; dst = (unsigned char *) (s->dma_dac.rawbuf + swptr); // swap hi/lo bytes for each sample for (i = 0; i < cnt / 2; i++) { @@ -2332,15 +2330,13 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un count_info cinfo; int val, mapped, ret; unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); switch (cmd) { case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); + return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_SYNC: if (file->f_mode & FMODE_WRITE) @@ -2351,7 +2347,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un return 0; case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p); + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, (int *)arg); case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { @@ -2369,7 +2365,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un return 0; case SNDCTL_DSP_SPEED: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { @@ -2387,10 +2383,10 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un set_dac_rate(s, val); } } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; fmtd = 0; fmtm = ~0; @@ -2421,7 +2417,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un return 0; case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val != 0) { fmtd = 0; @@ -2453,18 +2449,18 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if ((s->capability & CAN_MULTI_CH) && (file->f_mode & FMODE_WRITE)) { val = set_dac_channels(s, val); - return put_user(val, p); + return put_user(val, (int *)arg); } } return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) - : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p); + : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8| - ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p); + ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val != AFMT_QUERY) { fmtd = 0; @@ -2507,9 +2503,9 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } set_fmt(s, fmtm, fmtd); } - if (s->status & DO_AC3) return put_user(AFMT_AC3, p); + if (s->status & DO_AC3) return put_user(AFMT_AC3, (int *)arg); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) - : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p); + : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, (int *)arg); case SNDCTL_DSP_POST: return 0; @@ -2521,16 +2517,16 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un (s->enable & ENDAC) && (s->enable & ENADC)) val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); + return put_user(val, (int *)arg); } if (file->f_mode & FMODE_READ && s->enable & ENADC) val |= PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE && s->enable & ENDAC) val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { @@ -2572,7 +2568,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) @@ -2586,7 +2582,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; @@ -2599,7 +2595,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un cm_update_ptr(s); val = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -2612,7 +2608,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) @@ -2629,7 +2625,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un s->dma_adc.count &= s->dma_adc.fragsize-1; } spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { @@ -2638,16 +2634,16 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if (s->status & DO_DUAL_DAC) { if ((val = prog_dmabuf(s, 1))) return val; - return put_user(2 * s->dma_dac.fragsize, p); + return put_user(2 * s->dma_dac.fragsize, (int *)arg); } - return put_user(s->dma_dac.fragsize, p); + return put_user(s->dma_dac.fragsize, (int *)arg); } if ((val = prog_dmabuf(s, 1))) return val; - return put_user(s->dma_adc.fragsize, p); + return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; @@ -2679,7 +2675,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; @@ -2693,22 +2689,22 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un return 0; case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p); + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg); case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p); + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, (int *)arg); case SOUND_PCM_READ_FILTER: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_GETCHANNELMASK: - return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p); + return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, (int *)arg); case SNDCTL_DSP_BIND_CHANNEL: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val == DSP_BIND_QUERY) { val = DSP_BIND_FRONT; @@ -2761,7 +2757,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } } } - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SNDCTL_DSP_MAPINBUF: @@ -2769,47 +2765,47 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un case SNDCTL_DSP_SETSYNCRO: return -EINVAL; case SNDCTL_SPDIF_COPYRIGHT: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdif_copyright(s, val); return 0; case SNDCTL_SPDIF_LOOP: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdif_loop(s, val); return 0; case SNDCTL_SPDIF_MONITOR: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdif_monitor(s, val); return 0; case SNDCTL_SPDIF_LEVEL: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifout_level(s, val); return 0; case SNDCTL_SPDIF_INV: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifin_inverse(s, val); return 0; case SNDCTL_SPDIF_SEL2: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifin_channel2(s, val); return 0; case SNDCTL_SPDIF_VALID: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifin_valid(s, val); return 0; case SNDCTL_SPDIFOUT: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifout(s, val ? s->ratedac : 0); return 0; case SNDCTL_SPDIFIN: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; set_spdifin(s, val ? s->rateadc : 0); return 0; diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index e4f8542b3..c817b39ea 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -1393,7 +1393,7 @@ static irqreturn_t i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) waiting to be copied to the user's buffer. It is filled by the dma machine and drained by this loop. */ -static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct i810_state *state = (struct i810_state *)file->private_data; struct i810_card *card=state ? state->card : 0; @@ -1533,7 +1533,7 @@ static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, l /* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to the soundcard. it is drained by the dma machine and filled by this loop. */ -static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t i810_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct i810_state *state = (struct i810_state *)file->private_data; struct i810_card *card=state ? state->card : 0; @@ -1755,11 +1755,9 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int i_glob_cnt; int val = 0, ret; struct ac97_codec *codec = state->card->ac97_codec[0]; - void __user *argp = (void __user *)arg; - int __user *p = argp; #ifdef DEBUG - printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0); + printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0); #endif switch (cmd) @@ -1768,7 +1766,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, #ifdef DEBUG printk("OSS_GETVERSION\n"); #endif - return put_user(SOUND_VERSION, p); + return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: #ifdef DEBUG @@ -1815,7 +1813,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, #ifdef DEBUG printk("SNDCTL_DSP_SPEED\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_WRITE) { @@ -1853,7 +1851,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, spin_unlock_irqrestore(&state->card->lock, flags); } } - return put_user(dmabuf->rate, p); + return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ #ifdef DEBUG @@ -1865,7 +1863,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); } - return put_user(1, p); + return put_user(1, (int *)arg); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { @@ -1879,25 +1877,25 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, #ifdef DEBUG printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize); #endif - return put_user(dmabuf->userfragsize, p); + return put_user(dmabuf->userfragsize, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ #ifdef DEBUG printk("SNDCTL_DSP_GETFMTS\n"); #endif - return put_user(AFMT_S16_LE, p); + return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ #ifdef DEBUG printk("SNDCTL_DSP_SETFMT\n"); #endif - return put_user(AFMT_S16_LE, p); + return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_CHANNELS: #ifdef DEBUG printk("SNDCTL_DSP_CHANNELS\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val > 0) { @@ -1908,13 +1906,13 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, stop_adc(state); } } else { - return put_user(state->card->channels, p); + return put_user(state->card->channels, (int *)arg); } /* ICH and ICH0 only support 2 channels */ if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5 || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) - return put_user(2, p); + return put_user(2, (int *)arg); /* Multi-channel support was added with ICH2. Bits in */ /* Global Status and Global Control register are now */ @@ -1959,7 +1957,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, break; } - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ /* we update the swptr to the end of the last sg segment then return */ @@ -1978,7 +1976,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) return -EINVAL; - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; @@ -1990,7 +1988,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return 0; case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; dmabuf->ossfragsize = 1<<(val & 0xffff); @@ -2063,7 +2061,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes, abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); #endif - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) @@ -2085,7 +2083,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, cinfo.blocks, cinfo.ptr, dmabuf->count); #endif - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) @@ -2102,7 +2100,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes, abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); #endif - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) @@ -2124,7 +2122,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, cinfo.blocks, cinfo.ptr, dmabuf->count); #endif - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: #ifdef DEBUG @@ -2138,17 +2136,17 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, printk("SNDCTL_DSP_GETCAPS\n"); #endif return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, - p); + (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0; #ifdef DEBUG printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); #endif - return put_user(dmabuf->trigger, p); + return put_user(dmabuf->trigger, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; #if defined(DEBUG) || defined(DEBUG_MMAP) printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); @@ -2225,31 +2223,31 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, #ifdef DEBUG printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); #endif - return put_user(val, p); + return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE: #ifdef DEBUG printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); #endif - return put_user(dmabuf->rate, p); + return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: #ifdef DEBUG printk("SOUND_PCM_READ_CHANNELS\n"); #endif - return put_user(2, p); + return put_user(2, (int *)arg); case SOUND_PCM_READ_BITS: #ifdef DEBUG printk("SOUND_PCM_READ_BITS\n"); #endif - return put_user(AFMT_S16_LE, p); + return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */ #ifdef DEBUG printk("SNDCTL_DSP_SETSPDIF\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; /* Check to make sure the codec supports S/PDIF transmitter */ @@ -2272,13 +2270,13 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, else printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n"); #endif - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */ #ifdef DEBUG printk("SNDCTL_DSP_GETSPDIF\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; /* Check to make sure the codec supports S/PDIF transmitter */ @@ -2291,14 +2289,14 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } else { val = i810_ac97_get(codec, AC97_SPDIF_CONTROL); } - //return put_user((val & 0xcfff), p); - return put_user(val, p); + //return put_user((val & 0xcfff), (int *)arg); + return put_user(val, (int *)arg); case SNDCTL_DSP_GETCHANNELMASK: #ifdef DEBUG printk("SNDCTL_DSP_GETCHANNELMASK\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; /* Based on AC'97 DAC support, not ICH hardware */ @@ -2311,13 +2309,13 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if ( state->card->ac97_features & 0x0140 ) val |= DSP_BIND_CENTER_LFE; - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_BIND_CHANNEL: #ifdef DEBUG printk("SNDCTL_DSP_BIND_CHANNEL\n"); #endif - if (get_user(val, p)) + if (get_user(val, (int *)arg)) return -EFAULT; if ( val == DSP_BIND_QUERY ) { val = DSP_BIND_FRONT; /* Always report this as being enabled */ @@ -2385,7 +2383,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, val &= ~DSP_BIND_CENTER_LFE; } } - return put_user(val, p); + return put_user(val, (int *)arg); case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c index 6ccdd096f..3fdbaf5f2 100644 --- a/sound/oss/msnd.c +++ b/sound/oss/msnd.c @@ -139,10 +139,13 @@ void msnd_fifo_make_empty(msnd_fifo *f) f->len = f->tail = f->head = 0; } -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) +int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) { int count = 0; + if (f->len == f->n) + return 0; + while ((count < len) && (f->len != f->n)) { int nwritten; @@ -158,7 +161,11 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) nwritten = len - count; } - isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten); + if (user) { + if (copy_from_user(f->data + f->tail, buf, nwritten)) + return -EFAULT; + } else + isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten); count += nwritten; buf += nwritten; @@ -170,10 +177,13 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) return count; } -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) +int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) { int count = 0; + if (f->len == 0) + return f->len; + while ((count < len) && (f->len > 0)) { int nread; @@ -189,7 +199,11 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) nread = len - count; } - isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread); + if (user) { + if (copy_to_user(buf, f->data + f->head, nread)) + return -EFAULT; + } else + isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread); count += nread; buf += nread; diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 9789c5ab2..c69c135a9 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -822,7 +822,7 @@ static void opl3_hw_control(int dev, unsigned char *event) { } -static int opl3_load_patch(int dev, int format, const char __user *addr, +static int opl3_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct sbi_instrument ins; @@ -833,11 +833,7 @@ static int opl3_load_patch(int dev, int format, const char __user *addr, return -EINVAL; } - /* - * What the fuck is going on here? We leave junk in the beginning - * of ins and then check the field pretty close to that beginning? - */ - if(copy_from_user(&((char *) &ins)[offs], addr + offs, sizeof(ins) - offs)) + if(copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs)) return -EFAULT; if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) diff --git a/sound/oss/trident.c b/sound/oss/trident.c index ed04f4007..e5e14cf5c 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -497,8 +497,7 @@ static void ali_setup_spdif_in(struct trident_card *card); static void ali_disable_spdif_in(struct trident_card *card); static void ali_disable_special_channel(struct trident_card *card, int ch); static void ali_setup_spdif_out(struct trident_card *card, int flag); -static int ali_write_5_1(struct trident_state *state, - const char __user *buffer, +static int ali_write_5_1(struct trident_state *state, const char *buffer, int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt); static int ali_allocate_other_states_resources(struct trident_state *state, @@ -1862,7 +1861,7 @@ trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* to be copied to the user's buffer. it is filled by the dma machine and */ /* drained by this loop. */ static ssize_t -trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos) +trident_read(struct file *file, char *buffer, size_t count, loff_t * ppos) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; @@ -1977,7 +1976,7 @@ out: the soundcard. it is drained by the dma machine and filled by this loop. */ static ssize_t -trident_write(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) +trident_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; @@ -2248,9 +2247,8 @@ trident_ioctl(struct inode *inode, struct file *file, audio_buf_info abinfo; count_info cinfo; int val, mapped, ret = 0; + struct trident_card *card = state->card; - void __user *argp = (void __user *)arg; - int __user *p = argp; VALIDATE_STATE(state); @@ -2258,11 +2256,11 @@ trident_ioctl(struct inode *inode, struct file *file, mapped = ((file->f_mode & (FMODE_WRITE | FMODE_READ)) && dmabuf->mapped); pr_debug("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", - _IOC_NR(cmd), arg ? *p : 0); + _IOC_NR(cmd), arg ? *(int *) arg : 0); switch (cmd) { case OSS_GETVERSION: - ret = put_user(SOUND_VERSION, p); + ret = put_user(SOUND_VERSION, (int *) arg); break; case SNDCTL_DSP_RESET: @@ -2289,7 +2287,7 @@ trident_ioctl(struct inode *inode, struct file *file, break; case SNDCTL_DSP_SPEED: /* set smaple rate */ - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2309,11 +2307,11 @@ trident_ioctl(struct inode *inode, struct file *file, spin_unlock_irqrestore(&state->card->lock, flags); } } - ret = put_user(dmabuf->rate, p); + ret = put_user(dmabuf->rate, (int *) arg); break; case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2344,14 +2342,14 @@ trident_ioctl(struct inode *inode, struct file *file, if ((val = prog_dmabuf_playback(state))) ret = val; else - ret = put_user(dmabuf->fragsize, p); + ret = put_user(dmabuf->fragsize, (int *) arg); break; } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf_record(state))) ret = val; else - ret = put_user(dmabuf->fragsize, p); + ret = put_user(dmabuf->fragsize, (int *) arg); break; } /* neither READ nor WRITE? is this even possible? */ @@ -2361,11 +2359,11 @@ trident_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */ ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8, p); + AFMT_U8, (int *) arg); break; case SNDCTL_DSP_SETFMT: /* Select sample format */ - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2392,11 +2390,11 @@ trident_ioctl(struct inode *inode, struct file *file, } unlock_set_fmt(state); ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE : - AFMT_U8, p); + AFMT_U8, (int *) arg); break; case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2460,7 +2458,7 @@ trident_ioctl(struct inode *inode, struct file *file, } unlock_set_fmt(state); } - ret = put_user(val, p); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_POST: @@ -2472,7 +2470,7 @@ trident_ioctl(struct inode *inode, struct file *file, ret = -EINVAL; break; } - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2484,7 +2482,7 @@ trident_ioctl(struct inode *inode, struct file *file, break; case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2516,7 +2514,7 @@ trident_ioctl(struct inode *inode, struct file *file, abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ? + ret = copy_to_user((void *) arg, &abinfo, sizeof (abinfo)) ? -EFAULT : 0; break; @@ -2536,7 +2534,7 @@ trident_ioctl(struct inode *inode, struct file *file, abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ? + ret = copy_to_user((void *) arg, &abinfo, sizeof (abinfo)) ? -EFAULT : 0; break; @@ -2546,7 +2544,7 @@ trident_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_GETCAPS: ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | - DSP_CAP_MMAP | DSP_CAP_BIND, p); + DSP_CAP_MMAP | DSP_CAP_BIND, (int *) arg); break; case SNDCTL_DSP_GETTRIGGER: @@ -2555,11 +2553,11 @@ trident_ioctl(struct inode *inode, struct file *file, val |= PCM_ENABLE_INPUT; if ((file->f_mode & FMODE_WRITE) && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; - ret = put_user(val, p); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2601,7 +2599,7 @@ trident_ioctl(struct inode *inode, struct file *file, if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize - 1; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ? + ret = copy_to_user((void *) arg, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; break; @@ -2624,7 +2622,7 @@ trident_ioctl(struct inode *inode, struct file *file, if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize - 1; spin_unlock_irqrestore(&state->card->lock, flags); - ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ? + ret = copy_to_user((void *) arg, &cinfo, sizeof (cinfo)) ? -EFAULT : 0; break; @@ -2645,26 +2643,26 @@ trident_ioctl(struct inode *inode, struct file *file, trident_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); - ret = put_user(val, p); + ret = put_user(val, (int *) arg); break; case SOUND_PCM_READ_RATE: - ret = put_user(dmabuf->rate, p); + ret = put_user(dmabuf->rate, (int *) arg); break; case SOUND_PCM_READ_CHANNELS: ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - p); + (int *) arg); break; case SOUND_PCM_READ_BITS: ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE : - AFMT_U8, p); + AFMT_U8, (int *) arg); break; case SNDCTL_DSP_GETCHANNELMASK: ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR | - DSP_BIND_CENTER_LFE, p); + DSP_BIND_CENTER_LFE, (int *) arg); break; case SNDCTL_DSP_BIND_CHANNEL: @@ -2673,7 +2671,7 @@ trident_ioctl(struct inode *inode, struct file *file, break; } - if (get_user(val, p)) { + if (get_user(val, (int *) arg)) { ret = -EFAULT; break; } @@ -2690,7 +2688,7 @@ trident_ioctl(struct inode *inode, struct file *file, SRC_ENABLE); dmabuf->channel->attribute |= mask2attr[ffs(val)]; } - ret = put_user(val, p); + ret = put_user(val, (int *) arg); break; case SNDCTL_DSP_MAPINBUF: @@ -3880,14 +3878,14 @@ depend on a master state's DMA, and changing the counters of the master state DMA is protected by a spinlock. */ static int -ali_write_5_1(struct trident_state *state, const char __user *buf, +ali_write_5_1(struct trident_state *state, const char *buf, int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt) { struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf_temp; - const char __user *buffer = buf; + const char *buffer = buf; unsigned swptr, other_dma_nums, sample_s; unsigned int i, loop; @@ -4020,7 +4018,7 @@ ali_free_other_states_resources(struct trident_state *state) struct proc_dir_entry *res; static int -ali_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) +ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { struct trident_card *card = (struct trident_card *) data; unsigned long flags; diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c index e7932229e..df6ff556a 100644 --- a/sound/oss/wavfront.c +++ b/sound/oss/wavfront.c @@ -1011,7 +1011,7 @@ wavefront_send_sample (wavefront_patch_info *header, UINT16 sample_short; UINT32 length; - UINT16 __user *data_end = 0; + UINT16 *data_end = 0; unsigned int i; const int max_blksize = 4096/2; unsigned int written; @@ -1024,11 +1024,11 @@ wavefront_send_sample (wavefront_patch_info *header, int initial_skip = 0; DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " - "type %d, %d bytes from %p\n", + "type %d, %d bytes from 0x%x\n", header->size ? "" : "header ", header->number, header->subkey, header->size, - header->dataptr); + (int) header->dataptr); if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { int x; @@ -1688,7 +1688,8 @@ wavefront_load_patch (const char __user *addr) case WF_ST_MULTISAMPLE: - if (copy_from_user(&header.hdr.s, header.hdrptr, + if (copy_from_user((unsigned char *) &header.hdr.s, + (unsigned char *) header.hdrptr, sizeof(wavefront_multisample))) return -EFAULT; @@ -1697,28 +1698,32 @@ wavefront_load_patch (const char __user *addr) case WF_ST_ALIAS: - if (copy_from_user(&header.hdr.a, header.hdrptr, + if (copy_from_user((unsigned char *) &header.hdr.a, + (unsigned char *) header.hdrptr, sizeof (wavefront_alias))) return -EFAULT; return wavefront_send_alias (&header); case WF_ST_DRUM: - if (copy_from_user(&header.hdr.d, header.hdrptr, + if (copy_from_user((unsigned char *) &header.hdr.d, + (unsigned char *) header.hdrptr, sizeof (wavefront_drum))) return -EFAULT; return wavefront_send_drum (&header); case WF_ST_PATCH: - if (copy_from_user(&header.hdr.p, header.hdrptr, + if (copy_from_user((unsigned char *) &header.hdr.p, + (unsigned char *) header.hdrptr, sizeof (wavefront_patch))) return -EFAULT; return wavefront_send_patch (&header); case WF_ST_PROGRAM: - if (copy_from_user(&header.hdr.pr, header.hdrptr, + if (copy_from_user((unsigned char *) &header.hdr.pr, + (unsigned char *) header.hdrptr, sizeof (wavefront_program))) return -EFAULT; @@ -2997,7 +3002,7 @@ wffx_ioctl (wavefront_fx_info *r) return -(EINVAL); } if (copy_from_user(page_data, - (unsigned char __user *)r->data[3], + (unsigned char *)r->data[3], r->data[2])) return -EFAULT; pd = page_data; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 91a60417e..287b7d4e9 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1185,7 +1185,7 @@ static void snd_cs4281_proc_read(snd_info_entry_t *entry, } static long snd_cs4281_BA0_read(snd_info_entry_t *entry, void *file_private_data, - struct file *file, char __user *buf, long count) + struct file *file, char *buf, long count) { long size; cs4281_t *chip = snd_magic_cast(cs4281_t, entry->private_data, return -ENXIO); @@ -1202,7 +1202,7 @@ static long snd_cs4281_BA0_read(snd_info_entry_t *entry, void *file_private_data } static long snd_cs4281_BA1_read(snd_info_entry_t *entry, void *file_private_data, - struct file *file, char __user *buf, long count) + struct file *file, char *buf, long count) { long size; cs4281_t *chip = snd_magic_cast(cs4281_t, entry->private_data, return -ENXIO); diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 9a1758396..29861bb0e 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2866,7 +2866,7 @@ void __devinit snd_cs46xx_gameport(cs46xx_t *chip) */ static long snd_cs46xx_io_read(snd_info_entry_t *entry, void *file_private_data, - struct file *file, char __user *buf, long count) + struct file *file, char *buf, long count) { long size; snd_cs46xx_region_t *region = (snd_cs46xx_region_t *)entry->private_data; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index c4f763000..22eb444a0 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -898,10 +898,8 @@ static snd_emu10k1_fx8010_ctl_t *snd_emu10k1_look_for_ctl(emu10k1_t *emu, snd_ct static int snd_emu10k1_verify_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) { unsigned int i; - snd_ctl_elem_id_t __user *_id; - snd_ctl_elem_id_t id; - emu10k1_fx8010_control_gpr_t __user *_gctl; - emu10k1_fx8010_control_gpr_t gctl; + snd_ctl_elem_id_t *_id, id; + emu10k1_fx8010_control_gpr_t *_gctl, gctl; for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { @@ -948,8 +946,7 @@ static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl) static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) { unsigned int i, j; - emu10k1_fx8010_control_gpr_t __user *_gctl; - emu10k1_fx8010_control_gpr_t gctl; + emu10k1_fx8010_control_gpr_t *_gctl, gctl; snd_emu10k1_fx8010_ctl_t *ctl, nctl; snd_kcontrol_new_t knew; snd_kcontrol_t *kctl; @@ -1015,8 +1012,7 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) { unsigned int i; - snd_ctl_elem_id_t id; - snd_ctl_elem_id_t __user *_id; + snd_ctl_elem_id_t *_id, id; snd_emu10k1_fx8010_ctl_t *ctl; snd_card_t *card = emu->card; @@ -1035,8 +1031,7 @@ static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod { unsigned int i = 0, j; unsigned int total = 0; - emu10k1_fx8010_control_gpr_t gctl; - emu10k1_fx8010_control_gpr_t __user *_gctl; + emu10k1_fx8010_control_gpr_t *_gctl, gctl; snd_emu10k1_fx8010_ctl_t *ctl; snd_ctl_elem_id_t *id; struct list_head *list; @@ -2302,7 +2297,6 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne emu10k1_fx8010_code_t *icode; emu10k1_fx8010_pcm_t *ipcm; unsigned int addr; - void __user *argp = (void __user *)arg; int res; switch (cmd) { @@ -2314,7 +2308,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne kfree(info); return res; } - if (copy_to_user(argp, info, sizeof(*info))) { + if (copy_to_user((void *)arg, info, sizeof(*info))) { kfree(info); return -EFAULT; } @@ -2326,7 +2320,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne icode = (emu10k1_fx8010_code_t *)kmalloc(sizeof(*icode), GFP_KERNEL); if (icode == NULL) return -ENOMEM; - if (copy_from_user(icode, argp, sizeof(*icode))) { + if (copy_from_user(icode, (void *)arg, sizeof(*icode))) { kfree(icode); return -EFAULT; } @@ -2337,12 +2331,12 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne icode = (emu10k1_fx8010_code_t *)kmalloc(sizeof(*icode), GFP_KERNEL); if (icode == NULL) return -ENOMEM; - if (copy_from_user(icode, argp, sizeof(*icode))) { + if (copy_from_user(icode, (void *)arg, sizeof(*icode))) { kfree(icode); return -EFAULT; } res = snd_emu10k1_icode_peek(emu, icode); - if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) { + if (res == 0 && copy_to_user((void *)arg, icode, sizeof(*icode))) { kfree(icode); return -EFAULT; } @@ -2354,7 +2348,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne ipcm = (emu10k1_fx8010_pcm_t *)kmalloc(sizeof(*ipcm), GFP_KERNEL); if (ipcm == NULL) return -ENOMEM; - if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { + if (copy_from_user(ipcm, (void *)arg, sizeof(*ipcm))) { kfree(ipcm); return -EFAULT; } @@ -2367,12 +2361,12 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne ipcm = (emu10k1_fx8010_pcm_t *)snd_kcalloc(sizeof(*ipcm), GFP_KERNEL); if (ipcm == NULL) return -ENOMEM; - if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { + if (copy_from_user(ipcm, (void *)arg, sizeof(*ipcm))) { kfree(ipcm); return -EFAULT; } res = snd_emu10k1_ipcm_peek(emu, ipcm); - if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) { + if (res == 0 && copy_to_user((void *)arg, ipcm, sizeof(*ipcm))) { kfree(ipcm); return -EFAULT; } @@ -2383,7 +2377,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (get_user(addr, (unsigned int __user *)argp)) + if (get_user(addr, (unsigned int *)arg)) return -EFAULT; down(&emu->fx8010.lock); res = snd_emu10k1_fx8010_tram_setup(emu, addr); @@ -2421,7 +2415,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne case SNDRV_EMU10K1_IOCTL_SINGLE_STEP: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (get_user(addr, (unsigned int __user *)argp)) + if (get_user(addr, (unsigned int *)arg)) return -EFAULT; if (addr > 0x1ff) return -EINVAL; @@ -2440,7 +2434,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne addr = snd_emu10k1_ptr_read(emu, A_DBG, 0); else addr = snd_emu10k1_ptr_read(emu, DBG, 0); - if (put_user(addr, (unsigned int __user *)argp)) + if (put_user(addr, (unsigned int *)arg)) return -EFAULT; return 0; } diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 87afa49a0..7924508ac 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -822,7 +822,7 @@ static snd_pcm_uframes_t snd_es1938_playback_pointer(snd_pcm_substream_t *substr static int snd_es1938_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, - void __user *dst, + void *dst, snd_pcm_uframes_t count) { snd_pcm_runtime_t *runtime = substream->runtime; @@ -836,7 +836,7 @@ static int snd_es1938_capture_copy(snd_pcm_substream_t *substream, } else { if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1)) return -EFAULT; - if (put_user(runtime->dma_area[0], ((unsigned char __user *)dst) + count - 1)) + if (put_user(runtime->dma_area[0], ((unsigned char *)dst) + count - 1)) return -EFAULT; } return 0; diff --git a/sound/pci/ice1712/prodigy.c b/sound/pci/ice1712/prodigy.c deleted file mode 100644 index eee13e644..000000000 --- a/sound/pci/ice1712/prodigy.c +++ /dev/null @@ -1,663 +0,0 @@ -/* - * ALSA driver for ICEnsemble VT1724 (Envy24HT) - * - * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards - * Copyright (c) 2003 Dimitromanolakis Apostolos - * based on the aureon.c code (c) 2003 by Takashi Iwai - * - * version 0.82: Stable / not all features work yet (no communication with AC97 secondary) - * added 64x/128x oversampling switch (should be 64x only for 96khz) - * fixed some recording labels (still need to check the rest) - * recording is working probably thanks to correct wm8770 initialization - * - * version 0.5: Initial release: - * working: analog output, mixer, headphone amplifier switch - * not working: prety much everything else, at least i could verify that - * we have no digital output, no capture, pretty bad clicks and poops - * on mixer switch and other coll stuff. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * NOTES: - * - * - * - * - we reuse the akm4xxx_t record for storing the wm8770 codec data. - * both wm and akm codecs are pretty similar, so we can integrate - * both controls in the future, once if wm codecs are reused in - * many boards. - * - * - writing over SPI is implemented but reading is not yet. - * the SPDIF-in channel status, etc. can be read from CS chip. - * - * - DAC digital volumes are not implemented in the mixer. - * if they show better response than DAC analog volumes, we can use them - * instead. - * - * - Prodigy boards are equipped with AC97 STAC9744 chip , too. it's used to do - * the analog mixing but not easily controllable (it's not connected - * directly from envy24ht chip). so let's leave it as it is. - * - */ - -#define REVISION 0.82b - -#include -#include -#include -#include -#include -#include -#include - -#include "ice1712.h" -#include "envy24ht.h" -#include "prodigy.h" - - -static int prodigy_set_headphone_amp(ice1712_t *ice, int enable) -{ - unsigned int tmp, tmp2; - - tmp2 = tmp = snd_ice1712_gpio_read(ice); - if (enable) - tmp |= PRODIGY_HP_AMP_EN; - else - tmp &= ~ PRODIGY_HP_AMP_EN; - if (tmp != tmp2) { - snd_ice1712_gpio_write(ice, tmp); - return 1; - } - return 0; -} - - -static int prodigy_get_headphone_amp(ice1712_t *ice) -{ - unsigned int tmp = snd_ice1712_gpio_read(ice); - - return ( tmp & PRODIGY_HP_AMP_EN )!= 0; -} - - -/* - * write data in the SPI mode - */ -static void prodigy_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) -{ - unsigned int tmp; - int i; - - tmp = snd_ice1712_gpio_read(ice); - - snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_WM_RW|PRODIGY_WM_DATA|PRODIGY_WM_CLK| - PRODIGY_WM_CS|PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN)); - tmp |= PRODIGY_WM_RW; - tmp &= ~cs; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - - for (i = bits - 1; i >= 0; i--) { - tmp &= ~PRODIGY_WM_CLK; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - if (data & (1 << i)) - tmp |= PRODIGY_WM_DATA; - else - tmp &= ~PRODIGY_WM_DATA; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - tmp |= PRODIGY_WM_CLK; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - } - - tmp &= ~PRODIGY_WM_CLK; - tmp |= cs; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - tmp |= PRODIGY_WM_CLK; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); -} - - -/* - * get the current register value of WM codec - */ -static unsigned short wm_get(ice1712_t *ice, int reg) -{ - reg <<= 1; - return ((unsigned short)ice->akm[0].images[reg] << 8) | - ice->akm[0].images[reg + 1]; -} - -/* - * set the register value of WM codec and remember it - */ -static void wm_put(ice1712_t *ice, int reg, unsigned short val) -{ - prodigy_spi_write(ice, PRODIGY_WM_CS, (reg << 9) | (val & 0x1ff), 16); - reg <<= 1; - ice->akm[0].images[reg] = val >> 8; - ice->akm[0].images[reg + 1] = val; -} - - -/********************************* - ********* Controls section ****** - *********************************/ - -#define PRODIGY_CON_HPAMP \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Headphone Amplifier", \ - .info = prodigy_hpamp_info, \ - .get = prodigy_hpamp_get, \ - .put = prodigy_hpamp_put \ - } - -static int prodigy_hpamp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) -{ - static char *texts[2] = { - "Off", "On" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - - return 0; -} - - -static int prodigy_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = prodigy_get_headphone_amp(ice); - return 0; -} - - -static int prodigy_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - - return prodigy_set_headphone_amp(ice,ucontrol->value.integer.value[0]); -} - - - -#define PRODIGY_CON_DEEMP \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "DAC De-emphasis", \ - .info = prodigy_deemp_info, \ - .get = prodigy_deemp_get, \ - .put = prodigy_deemp_put \ - } - -static int prodigy_deemp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) -{ - static char *texts[2] = { "Off", "On" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int prodigy_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (wm_get(ice, 0x15) & 0xf) == 0xf; - return 0; -} - -static int prodigy_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int temp, temp2; - temp2 = temp = wm_get(ice, 0x15); - temp = (temp & ~0xf) | ((ucontrol->value.integer.value[0])*0xf); - if (temp != temp2) { - wm_put(ice,0x15,temp); - return 1; - } - return 0; -} - - -#define PRODIGY_CON_OVERSAMPLING \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "ADC Oversampling", \ - .info = prodigy_oversampling_info, \ - .get = prodigy_oversampling_get, \ - .put = prodigy_oversampling_put \ - } - -static int prodigy_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) -{ - static char *texts[2] = { "128x", "64x" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int prodigy_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (wm_get(ice, 0x17) & 0x8) == 0x8; - return 0; -} - -static int prodigy_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - int temp, temp2; - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - - temp2 = temp = wm_get(ice, 0x17); - - if( ucontrol->value.integer.value[0] ) { - temp |= 0x8; - } else { - temp &= ~0x8; - } - - if (temp != temp2) { - wm_put(ice,0x17,temp); - return 1; - } - return 0; -} - - - - -/* - * DAC volume attenuation mixer control - */ -static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; /* mute */ - uinfo->value.integer.max = 101; /* 0dB */ - return 0; -} - -static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx; - unsigned short vol; - - down(&ice->gpio_mutex); - if (kcontrol->private_value) - idx = WM_DAC_MASTER_ATTEN; - else - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; - vol = wm_get(ice, idx) & 0x7f; - if (vol <= 0x1a) - ucontrol->value.integer.value[0] = 0; - else - ucontrol->value.integer.value[0] = vol - 0x1a; - up(&ice->gpio_mutex); - - return 0; -} - -static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx; - unsigned short ovol, nvol; - int change; - - snd_ice1712_save_gpio_status(ice); - if (kcontrol->private_value) - idx = WM_DAC_MASTER_ATTEN; - else - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; - nvol = ucontrol->value.integer.value[0] + 0x1a; - ovol = wm_get(ice, idx) & 0x7f; - change = (ovol != nvol); - if (change) { - if (nvol <= 0x1a && ovol <= 0x1a) - change = 0; - else - wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ - } - snd_ice1712_restore_gpio_status(ice); - return change; -} - -/* - * ADC gain mixer control - */ -static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; /* -12dB */ - uinfo->value.integer.max = 0x1f; /* 19dB */ - return 0; -} - -static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx; - unsigned short vol; - - down(&ice->gpio_mutex); - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; - vol = wm_get(ice, idx) & 0x1f; - ucontrol->value.integer.value[0] = vol; - up(&ice->gpio_mutex); - return 0; -} - -static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx; - unsigned short ovol, nvol; - int change; - - snd_ice1712_save_gpio_status(ice); - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; - nvol = ucontrol->value.integer.value[0]; - ovol = wm_get(ice, idx) & 0x1f; - change = (ovol != nvol); - if (change) - wm_put(ice, idx, nvol); - snd_ice1712_restore_gpio_status(ice); - return change; -} - -/* - * ADC input mux mixer control - */ -static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - static char *texts[] = { - "CD Left", - "CD Right", - "Line Left", - "Line Right", - "Aux Left", - "Aux Right", - "Mic Left", - "Mic Right", - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - unsigned short val; - - down(&ice->gpio_mutex); - val = wm_get(ice, WM_ADC_MUX); - ucontrol->value.integer.value[0] = val & 7; - ucontrol->value.integer.value[1] = (val >> 4) & 7; - up(&ice->gpio_mutex); - return 0; -} - -static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ice1712_t *ice = snd_kcontrol_chip(kcontrol); - unsigned short oval, nval; - int change; - - snd_ice1712_save_gpio_status(ice); - oval = wm_get(ice, WM_ADC_MUX); - nval = oval & ~0x77; - nval |= ucontrol->value.integer.value[0] & 7; - nval |= (ucontrol->value.integer.value[1] & 7) << 4; - change = (oval != nval); - if (change) - wm_put(ice, WM_ADC_MUX, nval); - snd_ice1712_restore_gpio_status(ice); - return 0; -} - -/* - * mixers - */ - -static snd_kcontrol_new_t prodigy71_dac_control __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DAC Volume", - .count = 8, - .info = wm_dac_vol_info, - .get = wm_dac_vol_get, - .put = wm_dac_vol_put, -}; - -static snd_kcontrol_new_t wm_controls[] __devinitdata = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = wm_dac_vol_info, - .get = wm_dac_vol_get, - .put = wm_dac_vol_put, - .private_value = 1, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "ADC Volume", - .count = 2, - .info = wm_adc_vol_info, - .get = wm_adc_vol_get, - .put = wm_adc_vol_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Route", - .info = wm_adc_mux_info, - .get = wm_adc_mux_get, - .put = wm_adc_mux_put, - }, - PRODIGY_CON_HPAMP , - PRODIGY_CON_DEEMP , - PRODIGY_CON_OVERSAMPLING -}; - - -static int __devinit prodigy_add_controls(ice1712_t *ice) -{ - unsigned int i; - int err; - - err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy71_dac_control, ice)); - if (err < 0) - return err; - - for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { - err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); - if (err < 0) - return err; - } - return 0; -} - - -/* - * initialize the chip - */ -static int __devinit prodigy_init(ice1712_t *ice) -{ - static unsigned short wm_inits[] = { - - /* These come first to reduce init pop noise */ - 0x1b, 0x000, /* ADC Mux */ - 0x1c, 0x009, /* Out Mux1 */ - 0x1d, 0x009, /* Out Mux2 */ - - 0x18, 0x000, /* All power-up */ - - 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */ - 0x17, 0x006, /* 128fs, slave mode */ - - 0x00, 0, /* DAC1 analog mute */ - 0x01, 0, /* DAC2 analog mute */ - 0x02, 0, /* DAC3 analog mute */ - 0x03, 0, /* DAC4 analog mute */ - 0x04, 0, /* DAC5 analog mute */ - 0x05, 0, /* DAC6 analog mute */ - 0x06, 0, /* DAC7 analog mute */ - 0x07, 0, /* DAC8 analog mute */ - 0x08, 0x100, /* master analog mute */ - - 0x09, 0x7f, /* DAC1 digital full */ - 0x0a, 0x7f, /* DAC2 digital full */ - 0x0b, 0x7f, /* DAC3 digital full */ - 0x0c, 0x7f, /* DAC4 digital full */ - 0x0d, 0x7f, /* DAC5 digital full */ - 0x0e, 0x7f, /* DAC6 digital full */ - 0x0f, 0x7f, /* DAC7 digital full */ - 0x10, 0x7f, /* DAC8 digital full */ - 0x11, 0x1FF, /* master digital full */ - - 0x12, 0x000, /* phase normal */ - 0x13, 0x090, /* unmute DAC L/R */ - 0x14, 0x000, /* all unmute */ - 0x15, 0x000, /* no deemphasis, no ZFLG */ - - 0x19, 0x000, /* -12dB ADC/L */ - 0x1a, 0x000 /* -12dB ADC/R */ - - }; - - static unsigned short cs_inits[] = { - 0x0441, /* RUN */ - 0x0100, /* no mute */ - 0x0200, /* */ - 0x0600, /* slave, 24bit */ - }; - - unsigned int tmp; - unsigned int i; - - printk(KERN_INFO "ice1724: AudioTrak Prodigy 7.1 driver rev. 0.82b\n"); - printk(KERN_INFO "ice1724: This driver is in beta stage. Forsuccess/failure reporting contact\n"); - printk(KERN_INFO "ice1724: Apostolos Dimitromanolakis \n"); - - ice->num_total_dacs = 8; - ice->num_total_adcs = 8; - - /* to remeber the register values */ - ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); - if (! ice->akm) - return -ENOMEM; - ice->akm_codecs = 1; - - snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */ - - /* reset the wm codec as the SPI mode */ - snd_ice1712_save_gpio_status(ice); - snd_ice1712_gpio_set_mask(ice,~( PRODIGY_WM_RESET|PRODIGY_WM_CS| - PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN )); - - tmp = snd_ice1712_gpio_read(ice); - tmp &= ~PRODIGY_WM_RESET; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - tmp |= PRODIGY_WM_CS | PRODIGY_CS8415_CS; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - tmp |= PRODIGY_WM_RESET; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - - /* initialize WM8770 codec */ - for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) - wm_put(ice, wm_inits[i], wm_inits[i+1]); - - /* initialize CS8415A codec */ - for (i = 0; i < ARRAY_SIZE(cs_inits); i++) - prodigy_spi_write(ice, PRODIGY_CS8415_CS, - cs_inits[i] | 0x200000, 24); - - - prodigy_set_headphone_amp(ice, 1); - - snd_ice1712_restore_gpio_status(ice); - - return 0; -} - -/* - * Prodigy boards don't provide the EEPROM data except for the vendor IDs. - * hence the driver needs to sets up it properly. - */ - -static unsigned char prodigy71_eeprom[] __devinitdata = { - 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xf8, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0xbf, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ -}; - -/* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy_cards[] __devinitdata = { - { - .subvendor = VT1724_SUBDEVICE_PRODIGY71, - .name = "Audiotrak Prodigy 7.1", - .chip_init = prodigy_init, - .build_controls = prodigy_add_controls, - .eeprom_size = sizeof(prodigy71_eeprom), - .eeprom_data = prodigy71_eeprom, - }, - { } /* terminator */ -}; diff --git a/sound/pci/ice1712/prodigy.h b/sound/pci/ice1712/prodigy.h deleted file mode 100644 index 1ff29fee2..000000000 --- a/sound/pci/ice1712/prodigy.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __SOUND_PRODIGY_H -#define __SOUND_PRODIGY_H - -/* - * ALSA driver for VIA VT1724 (Envy24HT) - * - * Lowlevel functions for Terratec PRODIGY cards - * - * Copyright (c) 2003 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#define PRODIGY_DEVICE_DESC "{AudioTrak,Prodigy 7.1}," - -#define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ - -extern struct snd_ice1712_card_info snd_vt1724_prodigy_cards[]; - -/* GPIO bits */ -#define PRODIGY_CS8415_CS (1 << 23) -#define PRODIGY_CS8415_CDTO (1 << 22) -#define PRODIGY_WM_RESET (1 << 20) -#define PRODIGY_WM_CLK (1 << 19) -#define PRODIGY_WM_DATA (1 << 18) -#define PRODIGY_WM_RW (1 << 17) -#define PRODIGY_AC97_RESET (1 << 16) -#define PRODIGY_DIGITAL_SEL1 (1 << 15) -// #define PRODIGY_HP_SEL (1 << 14) -#define PRODIGY_WM_CS (1 << 12) - -#define PRODIGY_HP_AMP_EN (1 << 14) - - -/* WM8770 registers */ -#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ -#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ -#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ -#define WM_DAC_DIG_MATER_ATTEN 0x11 /* DAC master digital attenuation */ -#define WM_PHASE_SWAP 0x12 /* DAC phase */ -#define WM_DAC_CTRL1 0x13 /* DAC control bits */ -#define WM_MUTE 0x14 /* mute controls */ -#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ -#define WM_INT_CTRL 0x16 /* interface control */ -#define WM_MASTER 0x17 /* master clock and mode */ -#define WM_POWERDOWN 0x18 /* power-down controls */ -#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ -#define WM_ADC_MUX 0x1b /* input MUX */ -#define WM_OUT_MUX1 0x1c /* output MUX */ -#define WM_OUT_MUX2 0x1e /* output MUX */ -#define WM_RESET 0x1f /* software reset */ - - -#endif /* __SOUND_PRODIGY_H */ diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index edd226021..c2fc6e339 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1328,7 +1328,7 @@ static int snd_korg1212_silence(korg1212_t *korg1212, int pos, int count, int of return 0; } -static int snd_korg1212_copy_to(korg1212_t *korg1212, void __user *dst, int pos, int count, int offset, int size) +static int snd_korg1212_copy_to(korg1212_t *korg1212, void *dst, int pos, int count, int offset, int size) { KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos; int i, rc; @@ -1346,7 +1346,7 @@ static int snd_korg1212_copy_to(korg1212_t *korg1212, void __user *dst, int pos, return -EFAULT; } #endif - rc = copy_to_user(dst + offset, src, size); + rc = copy_to_user((void*) dst + offset, src, size); if (rc) { #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i); @@ -1360,7 +1360,7 @@ static int snd_korg1212_copy_to(korg1212_t *korg1212, void __user *dst, int pos, return 0; } -static int snd_korg1212_copy_from(korg1212_t *korg1212, void __user *src, int pos, int count, int offset, int size) +static int snd_korg1212_copy_from(korg1212_t *korg1212, void *src, int pos, int count, int offset, int size) { KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos; int i, rc; @@ -1671,7 +1671,7 @@ static snd_pcm_uframes_t snd_korg1212_capture_pointer(snd_pcm_substream_t *subst static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *src, + void *src, snd_pcm_uframes_t count) { korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); @@ -1701,7 +1701,7 @@ static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream, static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *dst, + void *dst, snd_pcm_uframes_t count) { korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 2b918cc7f..4b1a5b20f 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1154,7 +1154,7 @@ static long long snd_mixart_BA1_llseek(snd_info_entry_t *entry, mixart_BA0 proc interface for BAR 0 - read callback */ static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data, - struct file *file, char __user *buf, long count) + struct file *file, char *buf, long count) { mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); @@ -1173,7 +1173,7 @@ static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data mixart_BA1 proc interface for BAR 1 - read callback */ static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data, - struct file *file, char __user *buf, long count) + struct file *file, char *buf, long count) { mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index ee3b246bb..8a2fa86aa 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -684,7 +684,7 @@ static int snd_nm256_playback_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *src, + void *src, snd_pcm_uframes_t count) { snd_pcm_runtime_t *runtime = substream->runtime; diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 2f209664d..1d19e7e08 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -298,7 +298,7 @@ static int snd_rme32_playback_silence(snd_pcm_substream_t * substream, int chann static int snd_rme32_playback_copy(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *src, snd_pcm_uframes_t count) + void *src, snd_pcm_uframes_t count) { rme32_t *rme32 = _snd_pcm_substream_chip(substream); count <<= rme32->playback_frlog; @@ -311,7 +311,7 @@ static int snd_rme32_playback_copy(snd_pcm_substream_t * substream, int channel, static int snd_rme32_capture_copy(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *dst, snd_pcm_uframes_t count) + void *dst, snd_pcm_uframes_t count) { rme32_t *rme32 = _snd_pcm_substream_chip(substream); count <<= rme32->capture_frlog; diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 0e04ae457..cf1776b08 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -361,7 +361,7 @@ static int snd_rme96_playback_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *src, + void *src, snd_pcm_uframes_t count) { rme96_t *rme96 = _snd_pcm_substream_chip(substream); @@ -376,7 +376,7 @@ static int snd_rme96_capture_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, - void __user *dst, + void *dst, snd_pcm_uframes_t count) { rme96_t *rme96 = _snd_pcm_substream_chip(substream); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index c91602c12..88eb35272 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1250,9 +1250,9 @@ static inline void snd_hdsp_midi_write_byte (hdsp_t *hdsp, int id, int val) { /* the hardware already does the relevant bit-mask with 0xff */ if (id) { - hdsp_write(hdsp, HDSP_midiDataOut1, val); + return hdsp_write(hdsp, HDSP_midiDataOut1, val); } else { - hdsp_write(hdsp, HDSP_midiDataOut0, val); + return hdsp_write(hdsp, HDSP_midiDataOut0, val); } } @@ -3834,7 +3834,7 @@ static char *hdsp_channel_buffer_location(hdsp_t *hdsp, } static int snd_hdsp_playback_copy(snd_pcm_substream_t *substream, int channel, - snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) + snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count) { hdsp_t *hdsp = _snd_pcm_substream_chip(substream); char *channel_buf; @@ -3849,7 +3849,7 @@ static int snd_hdsp_playback_copy(snd_pcm_substream_t *substream, int channel, } static int snd_hdsp_capture_copy(snd_pcm_substream_t *substream, int channel, - snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) + snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count) { hdsp_t *hdsp = _snd_pcm_substream_chip(substream); char *channel_buf; @@ -4531,11 +4531,10 @@ static int snd_hdsp_hwdep_dummy_op(snd_hwdep_t *hw, struct file *file) static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int cmd, unsigned long arg) { hdsp_t *hdsp = (hdsp_t *)hw->private_data; - void __user *argp = (void __user *)arg; switch (cmd) { case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: { - hdsp_peak_rms_t __user *peak_rms; + hdsp_peak_rms_t *peak_rms; int i; if (hdsp->io_type == H9652) { @@ -4543,38 +4542,38 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int int doublespeed = 0; if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) doublespeed = 1; - peak_rms = (hdsp_peak_rms_t __user *)arg; + peak_rms = (hdsp_peak_rms_t *)arg; for (i = 0; i < 26; ++i) { if (!(doublespeed && (i & 4))) { - if (copy_to_user_fromio((void __user *)peak_rms->input_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-i*4, 4) != 0) + if (copy_to_user_fromio((void *)peak_rms->input_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-i*4, 4) != 0) return -EFAULT; - if (copy_to_user_fromio((void __user *)peak_rms->playback_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + if (copy_to_user_fromio((void *)peak_rms->playback_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-(doublespeed ? 14 : 26)*4-i*4, 4) != 0) return -EFAULT; - if (copy_to_user_fromio((void __user *)peak_rms->output_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-2*(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + if (copy_to_user_fromio((void *)peak_rms->output_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-2*(doublespeed ? 14 : 26)*4-i*4, 4) != 0) return -EFAULT; rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8) & 0xFFFFFF00; rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8+4) & 0xFFFFFF00; rms_high += (rms_low >> 24); rms_low <<= 8; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8, &rms_low, 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8, &rms_low, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8+4, &rms_high, 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &rms_high, 4) != 0) return -EFAULT; rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; rms_high += (rms_low >> 24); rms_low <<= 8; - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8, &rms_low, 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &rms_low, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8+4, &rms_high, 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &rms_high, 4) != 0) return -EFAULT; rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; rms_high += (rms_low >> 24); rms_low <<= 8; - if (copy_to_user((void __user *)peak_rms->output_rms+i*8, &rms_low, 4) != 0) + if (copy_to_user((void *)peak_rms->output_rms+i*8, &rms_low, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->output_rms+i*8+4, &rms_high, 4) != 0) + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &rms_high, 4) != 0) return -EFAULT; } } @@ -4587,25 +4586,25 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) doublespeed = 1; m = (hdsp_9632_meters_t *)(hdsp->iobase+HDSP_9632_metersBase); - peak_rms = (hdsp_peak_rms_t __user *)arg; + peak_rms = (hdsp_peak_rms_t *)arg; for (i = 0, j = 0; i < 16; ++i, ++j) { - if (copy_to_user((void __user *)peak_rms->input_peaks+i*4, &(m->input_peak[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->input_peaks+i*4, &(m->input_peak[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->playback_peaks+i*4, &(m->playback_peak[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, &(m->playback_peak[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->output_peaks+i*4, &(m->output_peak[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->output_peaks+i*4, &(m->output_peak[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8, &(m->input_rms_low[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8, &(m->input_rms_low[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8, &(m->playback_rms_low[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &(m->playback_rms_low[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->output_rms+i*8, &(m->output_rms_low[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->output_rms+i*8, &(m->output_rms_low[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8+4, &(m->input_rms_high[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &(m->input_rms_high[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8+4, &(m->playback_rms_high[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &(m->playback_rms_high[j]), 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->output_rms+i*8+4, &(m->output_rms_high[j]), 4) != 0) + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &(m->output_rms_high[j]), 4) != 0) return -EFAULT; if (doublespeed && i == 3) i += 4; } @@ -4615,25 +4614,25 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int snd_printk("firmware needs to be uploaded to the card.\n"); return -EINVAL; } - peak_rms = (hdsp_peak_rms_t __user *)arg; + peak_rms = (hdsp_peak_rms_t *)arg; for (i = 0; i < 26; ++i) { - if (copy_to_user((void __user *)peak_rms->playback_peaks+i*4, (void *)hdsp->iobase+HDSP_playbackPeakLevel+i*4, 4) != 0) + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, (void *)hdsp->iobase+HDSP_playbackPeakLevel+i*4, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_peaks+i*4, (void *)hdsp->iobase+HDSP_inputPeakLevel+i*4, 4) != 0) + if (copy_to_user((void *)peak_rms->input_peaks+i*4, (void *)hdsp->iobase+HDSP_inputPeakLevel+i*4, 4) != 0) return -EFAULT; } for (i = 0; i < 26; ++i) { - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8+4, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8, 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->playback_rms+i*8, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8+4, 4) != 0) + if (copy_to_user((void *)peak_rms->playback_rms+i*8, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8+4, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8+4, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8, 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8, 4) != 0) return -EFAULT; - if (copy_to_user((void __user *)peak_rms->input_rms+i*8, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8+4, 4) != 0) + if (copy_to_user((void *)peak_rms->input_rms+i*8, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8+4, 4) != 0) return -EFAULT; } for (i = 0; i < 28; ++i) { - if (copy_to_user((void __user *)peak_rms->output_peaks+i*4, (void *)hdsp->iobase+HDSP_outputPeakLevel+i*4, 4) != 0) + if (copy_to_user((void *)peak_rms->output_peaks+i*4, (void *)hdsp->iobase+HDSP_outputPeakLevel+i*4, 4) != 0) return -EFAULT; } break; @@ -4681,7 +4680,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); } spin_unlock_irqrestore(&hdsp->lock, flags); - if (copy_to_user(argp, &info, sizeof(info))) + if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; break; } @@ -4691,7 +4690,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int if (hdsp->io_type != H9632) return -EINVAL; h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS; h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS; - if (copy_to_user(argp, &h9632_aeb, sizeof(h9632_aeb))) + if (copy_to_user((void *)arg, &h9632_aeb, sizeof(h9632_aeb))) return -EFAULT; break; } @@ -4707,14 +4706,14 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int } hdsp_version.io_type = hdsp->io_type; hdsp_version.firmware_rev = hdsp->firmware_rev; - if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) { + if ((err = copy_to_user((void *)arg, &hdsp_version, sizeof(hdsp_version)))) { return -EFAULT; } break; } case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: { - hdsp_firmware_t __user *firmware; - unsigned long __user *firmware_data; + hdsp_firmware_t *firmware; + unsigned long *firmware_data; int err; if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; @@ -4722,7 +4721,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int if (hdsp->io_type == Undefined) return -EINVAL; snd_printk("initializing firmware upload\n"); - firmware = (hdsp_firmware_t __user *)argp; + firmware = (hdsp_firmware_t *)arg; if (get_user(firmware_data, &firmware->firmware_data)) { return -EFAULT; @@ -4755,7 +4754,9 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int break; } case SNDRV_HDSP_IOCTL_GET_MIXER: { - hdsp_mixer_t __user *mixer = (hdsp_mixer_t __user *)argp; + hdsp_mixer_t *mixer; + + mixer = (hdsp_mixer_t *)arg; if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE)) return -EFAULT; break; diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index e1abd9813..155d72a73 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2011,7 +2011,7 @@ static char *rme9652_channel_buffer_location(rme9652_t *rme9652, } static int snd_rme9652_playback_copy(snd_pcm_substream_t *substream, int channel, - snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) + snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count) { rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); char *channel_buf; @@ -2028,7 +2028,7 @@ static int snd_rme9652_playback_copy(snd_pcm_substream_t *substream, int channel } static int snd_rme9652_capture_copy(snd_pcm_substream_t *substream, int channel, - snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) + snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count) { rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); char *channel_buf; -- 2.47.0