diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-02-18 13:51:42 +1100 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-02-18 13:51:42 +1100 |
commit | c58310bf4933986513020fa90b4190c7492995ae (patch) | |
tree | 143f2c7578d02ebef5db8fc57ae69e951ae0e2ee /arch/s390 | |
parent | 269cdfaf769f5cd831284cc831790c7c5038040f (diff) | |
parent | 1309d4e68497184d2fd87e892ddf14076c2bda98 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 8 | ||||
-rw-r--r-- | arch/s390/Kconfig.debug | 8 | ||||
-rw-r--r-- | arch/s390/defconfig | 87 | ||||
-rw-r--r-- | arch/s390/kernel/binfmt_elf32.c | 11 | ||||
-rw-r--r-- | arch/s390/kernel/compat_wrapper.S | 28 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 7 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 7 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 27 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 26 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 13 | ||||
-rw-r--r-- | arch/s390/kernel/stacktrace.c | 31 | ||||
-rw-r--r-- | arch/s390/kernel/syscalls.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 32 | ||||
-rw-r--r-- | arch/s390/kernel/vmlinux.lds.S | 2 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 40 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 28 | ||||
-rw-r--r-- | arch/s390/mm/mmap.c | 65 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 174 | ||||
-rw-r--r-- | arch/s390/mm/vmem.c | 33 |
20 files changed, 513 insertions, 120 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 82cbffd03654..92a4f7b4323a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -16,6 +16,9 @@ config LOCKDEP_SUPPORT config STACKTRACE_SUPPORT def_bool y +config HAVE_LATENCYTOP_SUPPORT + def_bool y + config RWSEM_GENERIC_SPINLOCK bool @@ -47,6 +50,11 @@ config NO_IOMEM config NO_DMA def_bool y +config GENERIC_LOCKBREAK + bool + default y + depends on SMP && PREEMPT + mainmenu "Linux Kernel Configuration" config S390 diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 2283933a9a93..4599fa06bd82 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" +config DEBUG_PAGEALLOC + bool "Debug page memory allocations" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a slowdown, but helps to find certain types of + memory corruptions. + endmenu diff --git a/arch/s390/defconfig b/arch/s390/defconfig index ece7b99da895..39921f3a9685 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,12 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23 -# Mon Oct 22 12:10:44 2007 +# Linux kernel version: 2.6.24 +# Sat Feb 9 12:13:01 2008 # CONFIG_MMU=y CONFIG_ZONE_DMA=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set @@ -15,6 +16,7 @@ CONFIG_GENERIC_TIME=y CONFIG_GENERIC_BUG=y CONFIG_NO_IOMEM=y CONFIG_NO_DMA=y +CONFIG_GENERIC_LOCKBREAK=y CONFIG_S390=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -32,7 +34,6 @@ CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_USER_NS is not set CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_IKCONFIG=y @@ -41,13 +42,19 @@ CONFIG_LOG_BUF_SHIFT=17 CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set CONFIG_CGROUP_NS=y -CONFIG_CGROUP_CPUACCT=y # CONFIG_CPUSETS is not set CONFIG_FAIR_GROUP_SCHED=y CONFIG_FAIR_USER_SCHED=y # CONFIG_FAIR_CGROUP_SCHED is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_RESOURCE_COUNTERS is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -61,17 +68,26 @@ CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -99,6 +115,8 @@ CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set # # Base setup @@ -137,7 +155,7 @@ CONFIG_ARCH_POPULATES_NODE_MAP=y # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y -CONFIG_PREEMPT_BKL=y +# CONFIG_RCU_TRACE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -151,7 +169,6 @@ CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y -CONFIG_HOLES_IN_ZONE=y # # I/O subsystem configuration @@ -180,6 +197,7 @@ CONFIG_HZ_100=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 +# CONFIG_SCHED_HRTICK is not set CONFIG_NO_IDLE_HZ=y CONFIG_NO_IDLE_HZ_INIT=y CONFIG_S390_HYPFS_FS=y @@ -201,6 +219,7 @@ CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=y # CONFIG_NET_KEY_MIGRATE is not set CONFIG_IUCV=m @@ -251,6 +270,7 @@ CONFIG_IPV6_SIT=y # CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y # # Core Netfilter Configuration @@ -258,7 +278,6 @@ CONFIG_NETFILTER=y CONFIG_NETFILTER_NETLINK=m CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NF_CONNTRACK_ENABLED=m CONFIG_NF_CONNTRACK=m # CONFIG_NF_CT_ACCT is not set # CONFIG_NF_CONNTRACK_MARK is not set @@ -286,7 +305,7 @@ CONFIG_NF_CONNTRACK=m # CONFIG_IP_NF_ARPTABLES is not set # -# IPv6: Netfilter Configuration (EXPERIMENTAL) +# IPv6: Netfilter Configuration # # CONFIG_NF_CONNTRACK_IPV6 is not set # CONFIG_IP6_NF_QUEUE is not set @@ -343,6 +362,7 @@ CONFIG_NET_CLS_U32=m CONFIG_CLS_U32_MARK=y CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m # CONFIG_NET_EMATCH is not set CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y @@ -351,7 +371,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_NAT=m # CONFIG_NET_ACT_PEDIT is not set # CONFIG_NET_ACT_SIMP is not set -CONFIG_NET_CLS_POLICE=y # CONFIG_NET_CLS_IND is not set CONFIG_NET_SCH_FIFO=y @@ -360,6 +379,15 @@ CONFIG_NET_SCH_FIFO=y # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=m +# CONFIG_CAN_DEBUG_DEVICES is not set # CONFIG_AF_RXRPC is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set @@ -389,7 +417,7 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_XIP=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -406,6 +434,7 @@ CONFIG_DASD_DIAG=y CONFIG_DASD_EER=y CONFIG_MISC_DEVICES=y # CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set # # SCSI device support @@ -487,6 +516,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_IBM_NEW_EMAC_TAH is not set # CONFIG_IBM_NEW_EMAC_EMAC4 is not set CONFIG_NETDEV_1000=y +# CONFIG_E1000E_ENABLED is not set CONFIG_NETDEV_10000=y # CONFIG_TR is not set # CONFIG_WAN is not set @@ -508,7 +538,6 @@ CONFIG_QETH=y CONFIG_CCWGROUP=y # CONFIG_PPP is not set # CONFIG_SLIP is not set -# CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -558,6 +587,7 @@ CONFIG_S390_TAPE_34XX=m CONFIG_MONWRITER=m CONFIG_S390_VMUR=m # CONFIG_POWER_SUPPLY is not set +# CONFIG_THERMAL is not set # CONFIG_WATCHDOG is not set # @@ -584,12 +614,10 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set +CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_FUSE_FS is not set @@ -632,8 +660,10 @@ CONFIG_CONFIGFS_FS=m # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y @@ -686,16 +716,13 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS is not set CONFIG_DLM=m # CONFIG_DLM_DEBUG is not set -CONFIG_INSTRUMENTATION=y -# CONFIG_PROFILING is not set -CONFIG_KPROBES=y -# CONFIG_MARKERS is not set # # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set @@ -721,12 +748,18 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set # CONFIG_FRAME_POINTER is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set CONFIG_SAMPLES=y +# CONFIG_SAMPLE_KOBJECT is not set +# CONFIG_DEBUG_PAGEALLOC is not set # # Security options @@ -738,6 +771,7 @@ CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_AEAD=m CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_SEQIV=m CONFIG_CRYPTO_HASH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=m @@ -745,17 +779,20 @@ CONFIG_CRYPTO_HMAC=m # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=m -# CONFIG_CRYPTO_SHA1 is not set +CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_GF128MUL=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set # CONFIG_CRYPTO_XTS is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CCM=m # CONFIG_CRYPTO_CRYPTD is not set # CONFIG_CRYPTO_DES is not set CONFIG_CRYPTO_FCRYPT=m @@ -770,20 +807,22 @@ CONFIG_CRYPTO_FCRYPT=m # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SALSA20=m # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set CONFIG_CRYPTO_CAMELLIA=m # CONFIG_CRYPTO_TEST is not set CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_HW=y +CONFIG_ZCRYPT=m +# CONFIG_ZCRYPT_MONOLITHIC is not set # CONFIG_CRYPTO_SHA1_S390 is not set # CONFIG_CRYPTO_SHA256_S390 is not set # CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_AES_S390 is not set CONFIG_S390_PRNG=m -CONFIG_ZCRYPT=m -# CONFIG_ZCRYPT_MONOLITHIC is not set # # Library routines @@ -794,5 +833,7 @@ CONFIG_BITREVERSE=m # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=m CONFIG_CRC7=m -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m CONFIG_PLIST=y diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index f1e40ca00d8d..3e1c315b736d 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -134,6 +134,7 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) } #include <asm/processor.h> +#include <asm/pgalloc.h> #include <linux/module.h> #include <linux/elfcore.h> #include <linux/binfmts.h> @@ -183,6 +184,16 @@ struct elf_prpsinfo32 #undef start_thread #define start_thread start_thread31 +static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw, + unsigned long new_stackp) +{ + set_fs(USER_DS); + regs->psw.mask = psw_user32_bits; + regs->psw.addr = new_psw; + regs->gprs[15] = new_stackp; + crst_table_downgrade(current->mm, 1UL << 31); +} + MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries," " Copyright 2000 IBM Corporation"); MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>"); diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 6ee1bedbd1bf..743d54f0b8db 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1698,14 +1698,6 @@ compat_sys_signalfd_wrapper: llgfr %r4,%r4 # compat_size_t jg compat_sys_signalfd - .globl compat_sys_timerfd_wrapper -compat_sys_timerfd_wrapper: - lgfr %r2,%r2 # int - lgfr %r3,%r3 # int - lgfr %r4,%r4 # int - llgtr %r5,%r5 # struct compat_itimerspec * - jg compat_sys_timerfd - .globl sys_eventfd_wrapper sys_eventfd_wrapper: llgfr %r2,%r2 # unsigned int @@ -1720,3 +1712,23 @@ sys_fallocate_wrapper: sllg %r5,%r6,32 # get high word of 64bit loff_t l %r5,164(%r15) # get low word of 64bit loff_t jg sys_fallocate + + .globl sys_timerfd_create_wrapper +sys_timerfd_create_wrapper: + lgfr %r2,%r2 # int + lgfr %r3,%r3 # int + jg sys_timerfd_create + + .globl compat_sys_timerfd_settime_wrapper +compat_sys_timerfd_settime_wrapper: + lgfr %r2,%r2 # int + lgfr %r3,%r3 # int + llgtr %r4,%r4 # struct compat_itimerspec * + llgtr %r5,%r5 # struct compat_itimerspec * + jg compat_sys_timerfd_settime + + .globl compat_sys_timerfd_gettime_wrapper +compat_sys_timerfd_gettime_wrapper: + lgfr %r2,%r2 # int + llgtr %r3,%r3 # struct compat_itimerspec * + jg compat_sys_timerfd_gettime diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1a6dac8df6fb..6766e37fe8ea 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -11,6 +11,7 @@ #include <linux/sys.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/cache.h> #include <asm/lowcore.h> #include <asm/errno.h> @@ -830,9 +831,7 @@ mcck_return: * Restart interruption handler, kick starter for additional CPUs */ #ifdef CONFIG_SMP -#ifndef CONFIG_HOTPLUG_CPU - .section .init.text,"ax" -#endif + __CPUINIT .globl restart_int_handler restart_int_handler: l %r15,__LC_SAVE_AREA+60 # load ksp @@ -845,9 +844,7 @@ restart_int_handler: br %r14 # branch to start_secondary restart_addr: .long start_secondary -#ifndef CONFIG_HOTPLUG_CPU .previous -#endif #else /* * If we do not run with SMP enabled, let the new CPU crash ... diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index a3e47b893f07..efde6e178f6c 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -11,6 +11,7 @@ #include <linux/sys.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/cache.h> #include <asm/lowcore.h> #include <asm/errno.h> @@ -801,9 +802,7 @@ mcck_return: * Restart interruption handler, kick starter for additional CPUs */ #ifdef CONFIG_SMP -#ifndef CONFIG_HOTPLUG_CPU - .section .init.text,"ax" -#endif + __CPUINIT .globl restart_int_handler restart_int_handler: lg %r15,__LC_SAVE_AREA+120 # load ksp @@ -814,9 +813,7 @@ restart_int_handler: lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on jg start_secondary -#ifndef CONFIG_HOTPLUG_CPU .previous -#endif #else /* * If we do not run with SMP enabled, let the new CPU crash ... diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index db28cca81fef..60acdc266db1 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -439,7 +439,7 @@ static void ipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&ipl_info.data.ccw.dev_id); } -static int ipl_init(void) +static int __init ipl_init(void) { int rc; @@ -471,8 +471,11 @@ out: return 0; } -static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run, - ipl_init}; +static struct shutdown_action __refdata ipl_action = { + .name = SHUTDOWN_ACTION_IPL_STR, + .fn = ipl_run, + .init = ipl_init, +}; /* * reipl shutdown action: Reboot Linux on shutdown. @@ -792,7 +795,7 @@ static int __init reipl_fcp_init(void) return 0; } -static int reipl_init(void) +static int __init reipl_init(void) { int rc; @@ -819,8 +822,11 @@ static int reipl_init(void) return 0; } -static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR, - reipl_run, reipl_init}; +static struct shutdown_action __refdata reipl_action = { + .name = SHUTDOWN_ACTION_REIPL_STR, + .fn = reipl_run, + .init = reipl_init, +}; /* * dump shutdown action: Dump Linux on shutdown. @@ -998,7 +1004,7 @@ static int __init dump_fcp_init(void) return 0; } -static int dump_init(void) +static int __init dump_init(void) { int rc; @@ -1020,8 +1026,11 @@ static int dump_init(void) return 0; } -static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR, - dump_run, dump_init}; +static struct shutdown_action __refdata dump_action = { + .name = SHUTDOWN_ACTION_DUMP_STR, + .fn = dump_run, + .init = dump_init, +}; /* * vmcmd shutdown action: Trigger vm command on shutdown. diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 0e7aca039307..a6a4729e0e94 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/reboot.h> diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 766c783bd7a7..290e504061a3 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -24,7 +24,6 @@ #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/tty.h> #include <linux/ioport.h> #include <linux/delay.h> @@ -77,7 +76,7 @@ unsigned long machine_flags = 0; unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; +struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ static unsigned long __initdata memory_end; @@ -145,7 +144,7 @@ __setup("condev=", condev_setup); static int __init conmode_setup(char *str) { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) SET_CONSOLE_SCLP; #endif @@ -183,7 +182,7 @@ static void __init conmode_default(void) */ cpcmd("TERM CONMODE 3215", NULL, 0, NULL); if (ptr == NULL) { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif return; @@ -193,7 +192,7 @@ static void __init conmode_default(void) SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; -#elif defined(CONFIG_SCLP_CONSOLE) +#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } else if (strncmp(ptr + 8, "3215", 4) == 0) { @@ -201,7 +200,7 @@ static void __init conmode_default(void) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; -#elif defined(CONFIG_SCLP_CONSOLE) +#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } @@ -212,7 +211,7 @@ static void __init conmode_default(void) SET_CONSOLE_3270; #endif } else { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } @@ -528,7 +527,7 @@ static void __init setup_memory_end(void) memory_size = 0; memory_end &= PAGE_MASK; - max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START; + max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS; memory_end = min(max_mem, memory_end); /* @@ -649,21 +648,24 @@ setup_memory(void) /* * Reserve memory used for lowcore/command line/kernel image. */ - reserve_bootmem(0, (unsigned long)_ehead); + reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT); reserve_bootmem((unsigned long)_stext, - PFN_PHYS(start_pfn) - (unsigned long)_stext); + PFN_PHYS(start_pfn) - (unsigned long)_stext, + BOOTMEM_DEFAULT); /* * Reserve the bootmem bitmap itself as well. We do this in two * steps (first step was init_bootmem()) because this catches * the (very unlikely) case of us accidentally initializing the * bootmem allocator with an invalid RAM area. */ - reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); + reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size, + BOOTMEM_DEFAULT); #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START && INITRD_SIZE) { if (INITRD_START + INITRD_SIZE <= memory_end) { - reserve_bootmem(INITRD_START, INITRD_SIZE); + reserve_bootmem(INITRD_START, INITRD_SIZE, + BOOTMEM_DEFAULT); initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; } else { diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index aa37fa154512..85060659fb12 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -225,12 +225,11 @@ EXPORT_SYMBOL(smp_call_function_single); * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int -smp_call_function_mask(cpumask_t mask, - void (*func)(void *), void *info, - int wait) +int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, + int wait) { preempt_disable(); + cpu_clear(smp_processor_id(), mask); __smp_call_function_map(func, info, 0, wait, mask); preempt_enable(); return 0; @@ -1008,7 +1007,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { .notifier_call = smp_cpu_notify, }; -static int smp_add_present_cpu(int cpu) +static int __devinit smp_add_present_cpu(int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; @@ -1036,8 +1035,8 @@ out: } #ifdef CONFIG_HOTPLUG_CPU -static ssize_t rescan_store(struct sys_device *dev, const char *buf, - size_t count) +static ssize_t __ref rescan_store(struct sys_device *dev, + const char *buf, size_t count) { cpumask_t newcpus; int cpu; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index da6924729964..85e46a5d0e08 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -14,7 +14,8 @@ static unsigned long save_context_stack(struct stack_trace *trace, unsigned long sp, unsigned long low, - unsigned long high) + unsigned long high, + int savesched) { struct stack_frame *sf; struct pt_regs *regs; @@ -47,10 +48,12 @@ static unsigned long save_context_stack(struct stack_trace *trace, return sp; regs = (struct pt_regs *)sp; addr = regs->psw.addr & PSW_ADDR_INSN; - if (!trace->skip) - trace->entries[trace->nr_entries++] = addr; - else - trace->skip--; + if (savesched || !in_sched_functions(addr)) { + if (!trace->skip) + trace->entries[trace->nr_entries++] = addr; + else + trace->skip--; + } if (trace->nr_entries >= trace->max_entries) return sp; low = sp; @@ -66,15 +69,27 @@ void save_stack_trace(struct stack_trace *trace) orig_sp = sp & PSW_ADDR_INSN; new_sp = save_context_stack(trace, orig_sp, S390_lowcore.panic_stack - PAGE_SIZE, - S390_lowcore.panic_stack); + S390_lowcore.panic_stack, 1); if (new_sp != orig_sp) return; new_sp = save_context_stack(trace, new_sp, S390_lowcore.async_stack - ASYNC_SIZE, - S390_lowcore.async_stack); + S390_lowcore.async_stack, 1); if (new_sp != orig_sp) return; save_context_stack(trace, new_sp, S390_lowcore.thread_info, - S390_lowcore.thread_info + THREAD_SIZE); + S390_lowcore.thread_info + THREAD_SIZE, 1); +} + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + unsigned long sp, low, high; + + sp = tsk->thread.ksp & PSW_ADDR_INSN; + low = (unsigned long) task_stack_page(tsk); + high = (unsigned long) task_pt_regs(tsk); + save_context_stack(trace, sp, low, high, 0); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; } diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9e26ed9fe4e7..c87ec687d4c6 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -325,5 +325,8 @@ SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper) SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper) SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */ SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper) -SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper) +NI_SYSCALL /* 317 old sys_timer_fd */ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) +SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) +SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ +SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 52b8342c6bf2..60f728aeaf12 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -24,6 +24,7 @@ #include <linux/smp.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/seq_file.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kdebug.h> @@ -59,6 +60,7 @@ int sysctl_userprocess_debug = 0; extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_dat_exception; extern pgm_check_handler_t do_monitor_call; +extern pgm_check_handler_t do_asce_exception; #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) @@ -218,41 +220,40 @@ void show_registers(struct pt_regs *regs) } /* This is called from fs/proc/array.c */ -char *task_show_regs(struct task_struct *task, char *buffer) +void task_show_regs(struct seq_file *m, struct task_struct *task) { struct pt_regs *regs; regs = task_pt_regs(task); - buffer += sprintf(buffer, "task: %p, ksp: %p\n", + seq_printf(m, "task: %p, ksp: %p\n", task, (void *)task->thread.ksp); - buffer += sprintf(buffer, "User PSW : %p %p\n", + seq_printf(m, "User PSW : %p %p\n", (void *) regs->psw.mask, (void *)regs->psw.addr); - buffer += sprintf(buffer, "User GPRS: " FOURLONG, + seq_printf(m, "User GPRS: " FOURLONG, regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); - buffer += sprintf(buffer, " " FOURLONG, + seq_printf(m, " " FOURLONG, regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); - buffer += sprintf(buffer, " " FOURLONG, + seq_printf(m, " " FOURLONG, regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); - buffer += sprintf(buffer, " " FOURLONG, + seq_printf(m, " " FOURLONG, regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); - buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n", + seq_printf(m, "User ACRS: %08x %08x %08x %08x\n", task->thread.acrs[0], task->thread.acrs[1], task->thread.acrs[2], task->thread.acrs[3]); - buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + seq_printf(m, " %08x %08x %08x %08x\n", task->thread.acrs[4], task->thread.acrs[5], task->thread.acrs[6], task->thread.acrs[7]); - buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + seq_printf(m, " %08x %08x %08x %08x\n", task->thread.acrs[8], task->thread.acrs[9], task->thread.acrs[10], task->thread.acrs[11]); - buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + seq_printf(m, " %08x %08x %08x %08x\n", task->thread.acrs[12], task->thread.acrs[13], task->thread.acrs[14], task->thread.acrs[15]); - return buffer; } static DEFINE_SPINLOCK(die_lock); @@ -271,7 +272,10 @@ void die(const char * str, struct pt_regs * regs, long err) printk("PREEMPT "); #endif #ifdef CONFIG_SMP - printk("SMP"); + printk("SMP "); +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); #endif printk("\n"); notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); @@ -727,7 +731,7 @@ void __init trap_init(void) pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; #ifdef CONFIG_64BIT - pgm_check_table[0x38] = &do_dat_exception; + pgm_check_table[0x38] = &do_asce_exception; pgm_check_table[0x39] = &do_dat_exception; pgm_check_table[0x3A] = &do_dat_exception; pgm_check_table[0x3B] = &do_dat_exception; diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 7d43c3cd3ef3..b4607155e8d0 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -35,7 +35,7 @@ SECTIONS KPROBES_TEXT *(.fixup) *(.gnu.warning) - } = 0x0700 + } :text = 0x0700 _etext = .; /* End of text section */ diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 2456b52ed068..ed13d429a487 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -32,6 +32,7 @@ #include <asm/system.h> #include <asm/pgtable.h> #include <asm/s390_ext.h> +#include <asm/mmu_context.h> #ifndef CONFIG_64BIT #define __FAIL_ADDR_MASK 0x7ffff000 @@ -444,6 +445,45 @@ void __kprobes do_dat_exception(struct pt_regs *regs, unsigned long error_code) do_exception(regs, error_code & 0xff, 0); } +#ifdef CONFIG_64BIT +void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long address; + int space; + + mm = current->mm; + address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; + space = check_space(current); + + if (unlikely(space == 0 || in_atomic() || !mm)) + goto no_context; + + local_irq_enable(); + + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + up_read(&mm->mmap_sem); + + if (vma) { + update_mm(mm, current); + return; + } + + /* User mode accesses just cause a SIGSEGV */ + if (regs->psw.mask & PSW_MASK_PSTATE) { + current->thread.prot_addr = address; + current->thread.trap_no = error_code; + do_sigsegv(regs, error_code, SEGV_MAPERR, address); + return; + } + +no_context: + do_no_context(regs, error_code, address); +} +#endif + #ifdef CONFIG_PFAULT /* * 'pfault' pseudo page faults routines. diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index b234bb4a6da7..8053245fe259 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -112,6 +112,7 @@ void __init paging_init(void) init_mm.pgd = swapper_pg_dir; S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK; #ifdef CONFIG_64BIT + /* A three level page table (4TB) is enough for the kernel space. */ S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; pgd_type = _REGION3_ENTRY_EMPTY; #else @@ -167,6 +168,33 @@ void __init mem_init(void) PFN_ALIGN((unsigned long)&_eshared) - 1); } +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages(struct page *page, int numpages, int enable) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long address; + int i; + + for (i = 0; i < numpages; i++) { + address = page_to_phys(page + i); + pgd = pgd_offset_k(address); + pud = pud_offset(pgd, address); + pmd = pmd_offset(pud, address); + pte = pte_offset_kernel(pmd, address); + if (!enable) { + ptep_invalidate(&init_mm, address, pte); + continue; + } + *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); + /* Flush cpu write queue. */ + mb(); + } +} +#endif + void free_initmem(void) { unsigned long addr; diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 356257c171de..5932a824547a 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -27,6 +27,7 @@ #include <linux/personality.h> #include <linux/mm.h> #include <linux/module.h> +#include <asm/pgalloc.h> /* * Top of mmap area (just below the process stack). @@ -62,6 +63,8 @@ static inline int mmap_is_legacy(void) current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY; } +#ifndef CONFIG_64BIT + /* * This function, called very early during the creation of a new * process VM image, sets up which VM layout function to use: @@ -84,3 +87,65 @@ void arch_pick_mmap_layout(struct mm_struct *mm) } EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); +#else + +static unsigned long +s390_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + int rc; + + addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags); + if (addr & ~PAGE_MASK) + return addr; + if (unlikely(mm->context.asce_limit < addr + len)) { + rc = crst_table_upgrade(mm, addr + len); + if (rc) + return (unsigned long) rc; + } + return addr; +} + +static unsigned long +s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct mm_struct *mm = current->mm; + unsigned long addr = addr0; + int rc; + + addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); + if (addr & ~PAGE_MASK) + return addr; + if (unlikely(mm->context.asce_limit < addr + len)) { + rc = crst_table_upgrade(mm, addr + len); + if (rc) + return (unsigned long) rc; + } + return addr; +} +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if (mmap_is_legacy()) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = s390_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(); + mm->get_unmapped_area = s390_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + } +} +EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); + +#endif diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index e60e0ae13402..fd072013f88c 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -23,11 +23,18 @@ #include <asm/pgalloc.h> #include <asm/tlb.h> #include <asm/tlbflush.h> +#include <asm/mmu_context.h> #ifndef CONFIG_64BIT #define ALLOC_ORDER 1 +#define TABLES_PER_PAGE 4 +#define FRAG_MASK 15UL +#define SECOND_HALVES 10UL #else #define ALLOC_ORDER 2 +#define TABLES_PER_PAGE 2 +#define FRAG_MASK 3UL +#define SECOND_HALVES 2UL #endif unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) @@ -45,50 +52,179 @@ unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) } page->index = page_to_phys(shadow); } + spin_lock(&mm->page_table_lock); + list_add(&page->lru, &mm->context.crst_list); + spin_unlock(&mm->page_table_lock); return (unsigned long *) page_to_phys(page); } -void crst_table_free(unsigned long *table) +void crst_table_free(struct mm_struct *mm, unsigned long *table) { unsigned long *shadow = get_shadow_table(table); + struct page *page = virt_to_page(table); + spin_lock(&mm->page_table_lock); + list_del(&page->lru); + spin_unlock(&mm->page_table_lock); if (shadow) free_pages((unsigned long) shadow, ALLOC_ORDER); free_pages((unsigned long) table, ALLOC_ORDER); } +#ifdef CONFIG_64BIT +int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) +{ + unsigned long *table, *pgd; + unsigned long entry; + + BUG_ON(limit > (1UL << 53)); +repeat: + table = crst_table_alloc(mm, mm->context.noexec); + if (!table) + return -ENOMEM; + spin_lock(&mm->page_table_lock); + if (mm->context.asce_limit < limit) { + pgd = (unsigned long *) mm->pgd; + if (mm->context.asce_limit <= (1UL << 31)) { + entry = _REGION3_ENTRY_EMPTY; + mm->context.asce_limit = 1UL << 42; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION3; + } else { + entry = _REGION2_ENTRY_EMPTY; + mm->context.asce_limit = 1UL << 53; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION2; + } + crst_table_init(table, entry); + pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); + mm->pgd = (pgd_t *) table; + table = NULL; + } + spin_unlock(&mm->page_table_lock); + if (table) + crst_table_free(mm, table); + if (mm->context.asce_limit < limit) + goto repeat; + update_mm(mm, current); + return 0; +} + +void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) +{ + pgd_t *pgd; + + if (mm->context.asce_limit <= limit) + return; + __tlb_flush_mm(mm); + while (mm->context.asce_limit > limit) { + pgd = mm->pgd; + switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { + case _REGION_ENTRY_TYPE_R2: + mm->context.asce_limit = 1UL << 42; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_REGION3; + break; + case _REGION_ENTRY_TYPE_R3: + mm->context.asce_limit = 1UL << 31; + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | + _ASCE_TYPE_SEGMENT; + break; + default: + BUG(); + } + mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); + crst_table_free(mm, (unsigned long *) pgd); + } + update_mm(mm, current); +} +#endif + /* * page table entry allocation/free routines. */ -unsigned long *page_table_alloc(int noexec) +unsigned long *page_table_alloc(struct mm_struct *mm) { - struct page *page = alloc_page(GFP_KERNEL); + struct page *page; unsigned long *table; + unsigned long bits; - if (!page) - return NULL; - page->index = 0; - if (noexec) { - struct page *shadow = alloc_page(GFP_KERNEL); - if (!shadow) { - __free_page(page); + bits = mm->context.noexec ? 3UL : 1UL; + spin_lock(&mm->page_table_lock); + page = NULL; + if (!list_empty(&mm->context.pgtable_list)) { + page = list_first_entry(&mm->context.pgtable_list, + struct page, lru); + if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1)) + page = NULL; + } + if (!page) { + spin_unlock(&mm->page_table_lock); + page = alloc_page(GFP_KERNEL|__GFP_REPEAT); + if (!page) return NULL; - } - table = (unsigned long *) page_to_phys(shadow); + pgtable_page_ctor(page); + page->flags &= ~FRAG_MASK; + table = (unsigned long *) page_to_phys(page); clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); - page->index = (addr_t) table; + spin_lock(&mm->page_table_lock); + list_add(&page->lru, &mm->context.pgtable_list); } table = (unsigned long *) page_to_phys(page); - clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); + while (page->flags & bits) { + table += 256; + bits <<= 1; + } + page->flags |= bits; + if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1)) + list_move_tail(&page->lru, &mm->context.pgtable_list); + spin_unlock(&mm->page_table_lock); return table; } -void page_table_free(unsigned long *table) +void page_table_free(struct mm_struct *mm, unsigned long *table) { - unsigned long *shadow = get_shadow_pte(table); + struct page *page; + unsigned long bits; - if (shadow) - free_page((unsigned long) shadow); - free_page((unsigned long) table); + bits = mm->context.noexec ? 3UL : 1UL; + bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); + page = pfn_to_page(__pa(table) >> PAGE_SHIFT); + spin_lock(&mm->page_table_lock); + page->flags ^= bits; + if (page->flags & FRAG_MASK) { + /* Page now has some free pgtable fragments. */ + list_move(&page->lru, &mm->context.pgtable_list); + page = NULL; + } else + /* All fragments of the 4K page have been freed. */ + list_del(&page->lru); + spin_unlock(&mm->page_table_lock); + if (page) { + pgtable_page_dtor(page); + __free_page(page); + } +} +void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) +{ + struct page *page; + + spin_lock(&mm->page_table_lock); + /* Free shadow region and segment tables. */ + list_for_each_entry(page, &mm->context.crst_list, lru) + if (page->index) { + free_pages((unsigned long) page->index, ALLOC_ORDER); + page->index = 0; + } + /* "Free" second halves of page tables. */ + list_for_each_entry(page, &mm->context.pgtable_list, lru) + page->flags &= ~SECOND_HALVES; + spin_unlock(&mm->page_table_lock); + mm->context.noexec = 0; + update_mm(mm, tsk); } diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 79d13a166a3d..35d90a4720fd 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -62,14 +62,26 @@ void __meminit memmap_init(unsigned long size, int nid, unsigned long zone, } } -static void __init_refok *vmem_alloc_pages(unsigned int order) +static void __ref *vmem_alloc_pages(unsigned int order) { if (slab_is_available()) return (void *)__get_free_pages(GFP_KERNEL, order); return alloc_bootmem_pages((1 << order) * PAGE_SIZE); } -#define vmem_pud_alloc() ({ BUG(); ((pud_t *) NULL); }) +static inline pud_t *vmem_pud_alloc(void) +{ + pud_t *pud = NULL; + +#ifdef CONFIG_64BIT + pud = vmem_alloc_pages(2); + if (!pud) + return NULL; + pud_val(*pud) = _REGION3_ENTRY_EMPTY; + memcpy(pud + 1, pud, (PTRS_PER_PUD - 1)*sizeof(pud_t)); +#endif + return pud; +} static inline pmd_t *vmem_pmd_alloc(void) { @@ -84,13 +96,18 @@ static inline pmd_t *vmem_pmd_alloc(void) return pmd; } -static inline pte_t *vmem_pte_alloc(void) +static pte_t __init_refok *vmem_pte_alloc(void) { - pte_t *pte = vmem_alloc_pages(0); + pte_t *pte; + if (slab_is_available()) + pte = (pte_t *) page_table_alloc(&init_mm); + else + pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t)); if (!pte) return NULL; - clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, PAGE_SIZE); + clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, + PTRS_PER_PTE * sizeof(pte_t)); return pte; } @@ -250,7 +267,7 @@ static int insert_memory_segment(struct memory_segment *seg) { struct memory_segment *tmp; - if (seg->start + seg->size >= VMALLOC_START || + if (seg->start + seg->size >= VMEM_MAX_PHYS || seg->start + seg->size < seg->start) return -ERANGE; @@ -360,7 +377,9 @@ void __init vmem_map_init(void) { int i; - BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX); + INIT_LIST_HEAD(&init_mm.context.crst_list); + INIT_LIST_HEAD(&init_mm.context.pgtable_list); + init_mm.context.noexec = 0; NODE_DATA(0)->node_mem_map = VMEM_MAP; for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); |