diff options
126 files changed, 2912 insertions, 1452 deletions
diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 0eb7c58916d..e0542097369 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt @@ -115,6 +115,27 @@ Return Value: Handle for generated debug area Description: Allocates memory for a debug log Must not be called within an interrupt handler +---------------------------------------------------------------------------- +debug_info_t *debug_register_mode(char *name, int pages, int nr_areas, + int buf_size, mode_t mode, uid_t uid, + gid_t gid); + +Parameter: name: Name of debug log (e.g. used for debugfs entry) + pages: Number of pages, which will be allocated per area + nr_areas: Number of debug areas + buf_size: Size of data area in each debug entry + mode: File mode for debugfs files. E.g. S_IRWXUGO + uid: User ID for debugfs files. Currently only 0 is + supported. + gid: Group ID for debugfs files. Currently only 0 is + supported. + +Return Value: Handle for generated debug area + NULL if register failed + +Description: Allocates memory for a debug log + Must not be called within an interrupt handler + --------------------------------------------------------------------------- void debug_unregister (debug_info_t * id); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 1831833c430..f6a68e178fc 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -3,6 +3,10 @@ # see Documentation/kbuild/kconfig-language.txt. # +config SCHED_MC + def_bool y + depends on SMP + config MMU def_bool y @@ -39,6 +43,9 @@ config GENERIC_HWEIGHT config GENERIC_TIME def_bool y +config GENERIC_CLOCKEVENTS + def_bool y + config GENERIC_BUG bool depends on BUG @@ -69,6 +76,8 @@ menu "Base setup" comment "Processor type and features" +source "kernel/time/Kconfig" + config 64BIT bool "64 bit kernel" help @@ -301,10 +310,7 @@ config QDIO tristate "QDIO support" ---help--- This driver provides the Queued Direct I/O base support for - IBM mainframes. - - For details please refer to the documentation provided by IBM at - <http://www10.software.ibm.com/developerworks/opensource/linux390> + IBM System z. To compile this driver as a module, choose M here: the module will be called qdio. @@ -486,25 +492,6 @@ config APPLDATA_NET_SUM source kernel/Kconfig.hz -config NO_IDLE_HZ - bool "No HZ timer ticks in idle" - help - Switches the regular HZ timer off when the system is going idle. - This helps z/VM to detect that the Linux system is idle. VM can - then "swap-out" this guest which reduces memory usage. It also - reduces the overhead of idle systems. - - The HZ timer can be switched on/off via /proc/sys/kernel/hz_timer. - hz_timer=0 means HZ timer is disabled. hz_timer=1 means HZ - timer is active. - -config NO_IDLE_HZ_INIT - bool "HZ timer in idle off by default" - depends on NO_IDLE_HZ - help - The HZ timer is switched off in idle by default. That means the - HZ timer is already disabled at boot time. - config S390_HYPFS_FS bool "s390 hypervisor file system support" select SYS_HYPERVISOR diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index a3f67f8b542..e33f32b54c0 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -499,7 +499,7 @@ static struct crypto_alg cbc_aes_alg = { } }; -static int __init aes_init(void) +static int __init aes_s390_init(void) { int ret; @@ -542,15 +542,15 @@ aes_err: goto out; } -static void __exit aes_fini(void) +static void __exit aes_s390_fini(void) { crypto_unregister_alg(&cbc_aes_alg); crypto_unregister_alg(&ecb_aes_alg); crypto_unregister_alg(&aes_alg); } -module_init(aes_init); -module_exit(aes_fini); +module_init(aes_s390_init); +module_exit(aes_s390_fini); MODULE_ALIAS("aes"); diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index ea22707f435..4aba83b3159 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -550,7 +550,7 @@ static struct crypto_alg cbc_des3_192_alg = { } }; -static int init(void) +static int des_s390_init(void) { int ret = 0; @@ -612,7 +612,7 @@ des_err: goto out; } -static void __exit fini(void) +static void __exit des_s390_fini(void) { crypto_unregister_alg(&cbc_des3_192_alg); crypto_unregister_alg(&ecb_des3_192_alg); @@ -625,8 +625,8 @@ static void __exit fini(void) crypto_unregister_alg(&des_alg); } -module_init(init); -module_exit(fini); +module_init(des_s390_init); +module_exit(des_s390_fini); MODULE_ALIAS("des"); MODULE_ALIAS("des3_ede"); diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 5a834f6578a..9cf9eca2274 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -137,7 +137,7 @@ static struct crypto_alg alg = { .dia_final = sha1_final } } }; -static int __init init(void) +static int __init sha1_s390_init(void) { if (!crypt_s390_func_available(KIMD_SHA_1)) return -EOPNOTSUPP; @@ -145,13 +145,13 @@ static int __init init(void) return crypto_register_alg(&alg); } -static void __exit fini(void) +static void __exit sha1_s390_fini(void) { crypto_unregister_alg(&alg); } -module_init(init); -module_exit(fini); +module_init(sha1_s390_init); +module_exit(sha1_s390_fini); MODULE_ALIAS("sha1"); diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index ccf8633c4f6..2a3d756b35d 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -133,7 +133,7 @@ static struct crypto_alg alg = { .dia_final = sha256_final } } }; -static int init(void) +static int sha256_s390_init(void) { if (!crypt_s390_func_available(KIMD_SHA_256)) return -EOPNOTSUPP; @@ -141,13 +141,13 @@ static int init(void) return crypto_register_alg(&alg); } -static void __exit fini(void) +static void __exit sha256_s390_fini(void) { crypto_unregister_alg(&alg); } -module_init(init); -module_exit(fini); +module_init(sha256_s390_init); +module_exit(sha256_s390_fini); MODULE_ALIAS("sha256"); diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 62f6b5a606d..dcc3ec2ef64 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -3,6 +3,7 @@ # Linux kernel version: 2.6.25-rc4 # Wed Mar 5 11:22:59 2008 # +CONFIG_SCHED_MC=y CONFIG_MMU=y CONFIG_ZONE_DMA=y CONFIG_LOCKDEP_SUPPORT=y diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 4d3e38392cb..ef2b2470c25 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -19,7 +19,7 @@ obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) extra-y += head.o init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += smp.o topology.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index e89f8c0c42a..20723a06201 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -162,4 +162,77 @@ struct ucontext32 { compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; +struct __sysctl_args32; +struct stat64_emu31; +struct mmap_arg_struct_emu31; +struct fadvise64_64_args; +struct old_sigaction32; +struct old_sigaction32; + +long sys32_chown16(const char __user * filename, u16 user, u16 group); +long sys32_lchown16(const char __user * filename, u16 user, u16 group); +long sys32_fchown16(unsigned int fd, u16 user, u16 group); +long sys32_setregid16(u16 rgid, u16 egid); +long sys32_setgid16(u16 gid); +long sys32_setreuid16(u16 ruid, u16 euid); +long sys32_setuid16(u16 uid); +long sys32_setresuid16(u16 ruid, u16 euid, u16 suid); +long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid); +long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid); +long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid); +long sys32_setfsuid16(u16 uid); +long sys32_setfsgid16(u16 gid); +long sys32_getgroups16(int gidsetsize, u16 __user *grouplist); +long sys32_setgroups16(int gidsetsize, u16 __user *grouplist); +long sys32_getuid16(void); +long sys32_geteuid16(void); +long sys32_getgid16(void); +long sys32_getegid16(void); +long sys32_ipc(u32 call, int first, int second, int third, u32 ptr); +long sys32_truncate64(const char __user * path, unsigned long high, + unsigned long low); +long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low); +long sys32_sched_rr_get_interval(compat_pid_t pid, + struct compat_timespec __user *interval); +long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, + compat_sigset_t __user *oset, size_t sigsetsize); +long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize); +long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo); +long sys32_execve(void); +long sys32_init_module(void __user *umod, unsigned long len, + const char __user *uargs); +long sys32_delete_module(const char __user *name_user, unsigned int flags); +long sys32_gettimeofday(struct compat_timeval __user *tv, + struct timezone __user *tz); +long sys32_settimeofday(struct compat_timeval __user *tv, + struct timezone __user *tz); +long sys32_pause(void); +long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, + u32 poshi, u32 poslo); +long sys32_pwrite64(unsigned int fd, const char __user *ubuf, + size_t count, u32 poshi, u32 poslo); +compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count); +long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, + size_t count); +long sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, + s32 count); +long sys32_sysctl(struct __sysctl_args32 __user *args); +long sys32_stat64(char __user * filename, struct stat64_emu31 __user * statbuf); +long sys32_lstat64(char __user * filename, + struct stat64_emu31 __user * statbuf); +long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf); +long sys32_fstatat64(unsigned int dfd, char __user *filename, + struct stat64_emu31 __user* statbuf, int flag); +unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg); +long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg); +long sys32_read(unsigned int fd, char __user * buf, size_t count); +long sys32_write(unsigned int fd, char __user * buf, size_t count); +long sys32_clone(void); +long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise); +long sys32_fadvise64_64(struct fadvise64_64_args __user *args); +long sys32_sigaction(int sig, const struct old_sigaction32 __user *act, + struct old_sigaction32 __user *oact); +long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, + struct sigaction32 __user *oact, size_t sigsetsize); +long sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss); #endif /* _ASM_S390X_S390_H */ diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index a5692c460ba..c7f02e777af 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -29,6 +29,7 @@ #include <asm/lowcore.h> #include "compat_linux.h" #include "compat_ptrace.h" +#include "entry.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -428,6 +429,10 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) /* Default to using normal stack */ sp = (unsigned long) A(regs->gprs[15]); + /* Overflow on alternate signal stack gives SIGSEGV. */ + if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL)) + return (void __user *) -1UL; + /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { if (! sas_ss_flags(sp)) @@ -461,6 +466,9 @@ static int setup_frame32(int sig, struct k_sigaction *ka, if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32))) goto give_sigsegv; + if (frame == (void __user *) -1UL) + goto give_sigsegv; + if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32)) goto give_sigsegv; @@ -514,6 +522,9 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32))) goto give_sigsegv; + if (frame == (void __user *) -1UL) + goto give_sigsegv; + if (copy_siginfo_to_user32(&frame->info, info)) goto give_sigsegv; diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 1b2f5ce4532..1e7d4ac7068 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -73,7 +73,7 @@ static ssize_t debug_input(struct file *file, const char __user *user_buf, static int debug_open(struct inode *inode, struct file *file); static int debug_close(struct inode *inode, struct file *file); static debug_info_t* debug_info_create(char *name, int pages_per_area, - int nr_areas, int buf_size); + int nr_areas, int buf_size, mode_t mode); static void debug_info_get(debug_info_t *); static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t * id, @@ -157,7 +157,7 @@ struct debug_view debug_sprintf_view = { }; /* used by dump analysis tools to determine version of debug feature */ -unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; +static unsigned int __used debug_feature_version = __DEBUG_FEATURE_VERSION; /* static globals */ @@ -327,7 +327,8 @@ debug_info_free(debug_info_t* db_info){ */ static debug_info_t* -debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size) +debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size, + mode_t mode) { debug_info_t* rc; @@ -336,6 +337,8 @@ debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size) if(!rc) goto out; + rc->mode = mode & ~S_IFMT; + /* create root directory */ rc->debugfs_root_entry = debugfs_create_dir(rc->name, debug_debugfs_root_entry); @@ -676,23 +679,30 @@ debug_close(struct inode *inode, struct file *file) } /* - * debug_register: - * - creates and initializes debug area for the caller - * - returns handle for debug area + * debug_register_mode: + * - Creates and initializes debug area for the caller + * The mode parameter allows to specify access rights for the s390dbf files + * - Returns handle for debug area */ -debug_info_t* -debug_register (char *name, int pages_per_area, int nr_areas, int buf_size) +debug_info_t *debug_register_mode(char *name, int pages_per_area, int nr_areas, + int buf_size, mode_t mode, uid_t uid, + gid_t gid) { debug_info_t *rc = NULL; + /* Since debugfs currently does not support uid/gid other than root, */ + /* we do not allow gid/uid != 0 until we get support for that. */ + if ((uid != 0) || (gid != 0)) + printk(KERN_WARNING "debug: Warning - Currently only uid/gid " + "= 0 are supported. Using root as owner now!"); if (!initialized) BUG(); mutex_lock(&debug_mutex); /* create new debug_info */ - rc = debug_info_create(name, pages_per_area, nr_areas, buf_size); + rc = debug_info_create(name, pages_per_area, nr_areas, buf_size, mode); if(!rc) goto out; debug_register_view(rc, &debug_level_view); @@ -705,6 +715,20 @@ out: mutex_unlock(&debug_mutex); return rc; } +EXPORT_SYMBOL(debug_register_mode); + +/* + * debug_register: + * - creates and initializes debug area for the caller + * - returns handle for debug area + */ + +debug_info_t *debug_register(char *name, int pages_per_area, int nr_areas, + int buf_size) +{ + return debug_register_mode(name, pages_per_area, nr_areas, buf_size, + S_IRUSR | S_IWUSR, 0, 0); +} /* * debug_unregister: @@ -1073,15 +1097,16 @@ debug_register_view(debug_info_t * id, struct debug_view *view) int rc = 0; int i; unsigned long flags; - mode_t mode = S_IFREG; + mode_t mode; struct dentry *pde; if (!id) goto out; - if (view->prolog_proc || view->format_proc || view->header_proc) - mode |= S_IRUSR; - if (view->input_proc) - mode |= S_IWUSR; + mode = (id->mode | S_IFREG) & ~S_IXUGO; + if (!(view->prolog_proc || view->format_proc || view->header_proc)) + mode &= ~(S_IRUSR | S_IRGRP | S_IROTH); + if (!view->input_proc) + mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, id , &debug_file_ops); if (!pde){ diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 01832c44063..540a67f979b 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -21,6 +21,7 @@ #include <asm/setup.h> #include <asm/cpcmd.h> #include <asm/sclp.h> +#include "entry.h" /* * Create a Kernel NSS if the SAVESYS= parameter is defined diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h new file mode 100644 index 00000000000..6b1896345ed --- /dev/null +++ b/arch/s390/kernel/entry.h @@ -0,0 +1,60 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include <linux/types.h> +#include <linux/signal.h> +#include <asm/ptrace.h> + +typedef void pgm_check_handler_t(struct pt_regs *, long); +extern pgm_check_handler_t *pgm_check_table[128]; +pgm_check_handler_t do_protection_exception; +pgm_check_handler_t do_dat_exception; + +extern int sysctl_userprocess_debug; + +void do_single_step(struct pt_regs *regs); +void syscall_trace(struct pt_regs *regs, int entryexit); +void kernel_stack_overflow(struct pt_regs * regs); +void do_signal(struct pt_regs *regs); +int handle_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); + +void do_extint(struct pt_regs *regs, unsigned short code); +int __cpuinit start_secondary(void *cpuvoid); +void __init startup_init(void); +void die(const char * str, struct pt_regs * regs, long err); + +struct new_utsname; +struct mmap_arg_struct; +struct fadvise64_64_args; +struct old_sigaction; +struct sel_arg_struct; + +long sys_pipe(unsigned long __user *fildes); +long sys_mmap2(struct mmap_arg_struct __user *arg); +long old_mmap(struct mmap_arg_struct __user *arg); +long sys_ipc(uint call, int first, unsigned long second, + unsigned long third, void __user *ptr); +long s390x_newuname(struct new_utsname __user *name); +long s390x_personality(unsigned long personality); +long s390_fadvise64(int fd, u32 offset_high, u32 offset_low, + size_t len, int advice); +long s390_fadvise64_64(struct fadvise64_64_args __user *args); +long s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, u32 len_low); +long sys_fork(void); +long sys_clone(void); +long sys_vfork(void); +void execve_tail(void); +long sys_execve(void); +int sys_sigsuspend(int history0, int history1, old_sigset_t mask); +long sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact); +long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss); +long sys_sigreturn(void); +long sys_rt_sigreturn(void); +long sys32_sigreturn(void); +long sys32_rt_sigreturn(void); +long old_select(struct sel_arg_struct __user *arg); +long sys_ptrace(long request, long pid, long addr, long data); + +#endif /* _ENTRY_H */ diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index efde6e178f6..cd959c0b2e1 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -475,6 +475,7 @@ pgm_check_handler: pgm_no_vtime: #endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + mvc SP_ARGS(8,%r15),__LC_LAST_BREAK TRACE_IRQS_OFF lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f @@ -847,6 +848,7 @@ stack_overflow: je 0f la %r1,__LC_SAVE_AREA+32 0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack + mvc SP_ARGS(8,%r15),__LC_LAST_BREAK xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain la %r2,SP_PTREGS(%r15) # load pt_regs jg kernel_stack_overflow diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 375232c46c7..532542447d6 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -655,7 +655,7 @@ static struct kobj_attribute reipl_type_attr = static struct kset *reipl_kset; -void reipl_run(struct shutdown_trigger *trigger) +static void reipl_run(struct shutdown_trigger *trigger) { struct ccw_dev_id devid; static char buf[100]; diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index c5549a20628..ed04d1372d5 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -360,7 +360,7 @@ no_kprobe: * - When the probed function returns, this probe * causes the handlers to fire */ -void kretprobe_trampoline_holder(void) +static void __used kretprobe_trampoline_holder(void) { asm volatile(".global kretprobe_trampoline\n" "kretprobe_trampoline: bcr 0,0\n"); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index ce203154d8c..c1aff194141 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -36,6 +36,8 @@ #include <linux/module.h> #include <linux/notifier.h> #include <linux/utsname.h> +#include <linux/tick.h> +#include <linux/elfcore.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -44,6 +46,7 @@ #include <asm/irq.h> #include <asm/timer.h> #include <asm/cpu.h> +#include "entry.h" asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); @@ -76,6 +79,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) * Need to know about CPUs going idle? */ static ATOMIC_NOTIFIER_HEAD(idle_chain); +DEFINE_PER_CPU(struct s390_idle_data, s390_idle); int register_idle_notifier(struct notifier_block *nb) { @@ -89,9 +93,33 @@ int unregister_idle_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(unregister_idle_notifier); -void do_monitor_call(struct pt_regs *regs, long interruption_code) +static int s390_idle_enter(void) +{ + struct s390_idle_data *idle; + int nr_calls = 0; + void *hcpu; + int rc; + + hcpu = (void *)(long)smp_processor_id(); + rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, + &nr_calls); + if (rc == NOTIFY_BAD) { + nr_calls--; + __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + hcpu, nr_calls, NULL); + return rc; + } + idle = &__get_cpu_var(s390_idle); + spin_lock(&idle->lock); + idle->idle_count++; + idle->in_idle = 1; + idle->idle_enter = get_clock(); + spin_unlock(&idle->lock); + return NOTIFY_OK; +} + +void s390_idle_leave(void) { -#ifdef CONFIG_SMP struct s390_idle_data *idle; idle = &__get_cpu_var(s390_idle); @@ -99,10 +127,6 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) idle->idle_time += get_clock() - idle->idle_enter; idle->in_idle = 0; spin_unlock(&idle->lock); -#endif - /* disable monitor call class 0 */ - __ctl_clear_bit(8, 15); - atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, (void *)(long) smp_processor_id()); } @@ -113,61 +137,30 @@ extern void s390_handle_mcck(void); */ static void default_idle(void) { - int cpu, rc; - int nr_calls = 0; - void *hcpu; -#ifdef CONFIG_SMP - struct s390_idle_data *idle; -#endif - /* CPU is going idle. */ - cpu = smp_processor_id(); - hcpu = (void *)(long)cpu; local_irq_disable(); if (need_resched()) { local_irq_enable(); return; } - - rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, - &nr_calls); - if (rc == NOTIFY_BAD) { - nr_calls--; - __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, - hcpu, nr_calls, NULL); + if (s390_idle_enter() == NOTIFY_BAD) { local_irq_enable(); return; } - - /* enable monitor call class 0 */ - __ctl_set_bit(8, 15); - #ifdef CONFIG_HOTPLUG_CPU - if (cpu_is_offline(cpu)) { + if (cpu_is_offline(smp_processor_id())) { preempt_enable_no_resched(); cpu_die(); } #endif - local_mcck_disable(); if (test_thread_flag(TIF_MCCK_PENDING)) { local_mcck_enable(); - /* disable monitor call class 0 */ - __ctl_clear_bit(8, 15); - atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, - hcpu); + s390_idle_leave(); local_irq_enable(); s390_handle_mcck(); return; } -#ifdef CONFIG_SMP - idle = &__get_cpu_var(s390_idle); - spin_lock(&idle->lock); - idle->idle_count++; - idle->in_idle = 1; - idle->idle_enter = get_clock(); - spin_unlock(&idle->lock); -#endif trace_hardirqs_on(); /* Wait for external, I/O or machine check interrupt. */ __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | @@ -177,9 +170,10 @@ static void default_idle(void) void cpu_idle(void) { for (;;) { + tick_nohz_stop_sched_tick(); while (!need_resched()) default_idle(); - + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); @@ -201,6 +195,7 @@ void show_regs(struct pt_regs *regs) /* Show stack backtrace if pt_regs is from kernel mode */ if (!(regs->psw.mask & PSW_MASK_PSTATE)) show_trace(NULL, (unsigned long *) regs->gprs[15]); + show_last_breaking_event(regs); } extern void kernel_thread_starter(void); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 6e036bae987..58a06429698 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -41,6 +41,7 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/unistd.h> +#include "entry.h" #ifdef CONFIG_COMPAT #include "compat_ptrace.h" diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index acf93dba772..e019b419efc 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -13,11 +13,12 @@ #include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/interrupt.h> - +#include <asm/cpu.h> #include <asm/lowcore.h> #include <asm/s390_ext.h> #include <asm/irq_regs.h> #include <asm/irq.h> +#include "entry.h" /* * ext_int_hash[index] is the start of the list for all external interrupts @@ -119,13 +120,10 @@ void do_extint(struct pt_regs *regs, unsigned short code) old_regs = set_irq_regs(regs); irq_enter(); - asm volatile ("mc 0,0"); - if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) - /** - * Make sure that the i/o interrupt did not "overtake" - * the last HZ timer interrupt. - */ - account_ticks(S390_lowcore.int_clock); + s390_idle_check(); + if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) + /* Serve timer interrupts first. */ + clock_comparator_work(); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); for (p = ext_int_hash[index]; p; p = p->next) { diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 290e504061a..7141147e6b6 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -39,6 +39,7 @@ #include <linux/pfn.h> #include <linux/ctype.h> #include <linux/reboot.h> +#include <linux/topology.h> #include <asm/ipl.h> #include <asm/uaccess.h> @@ -427,7 +428,7 @@ setup_lowcore(void) lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; lc->ipl_device = S390_lowcore.ipl_device; - lc->jiffy_timer = -1LL; + lc->clock_comparator = -1ULL; lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->async_stack = (unsigned long) __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; @@ -687,7 +688,7 @@ static __init unsigned int stfl(void) return S390_lowcore.stfl_fac_list; } -static __init int stfle(unsigned long long *list, int doublewords) +static int __init __stfle(unsigned long long *list, int doublewords) { typedef struct { unsigned long long _[doublewords]; } addrtype; register unsigned long __nr asm("0") = doublewords - 1; @@ -697,6 +698,13 @@ static __init int stfle(unsigned long long *list, int doublewords) return __nr + 1; } +int __init stfle(unsigned long long *list, int doublewords) +{ + if (!(stfl() & (1UL << 24))) + return -EOPNOTSUPP; + return __stfle(list, doublewords); +} + /* * Setup hardware capabilities. */ @@ -741,7 +749,7 @@ static void __init setup_hwcaps(void) * HWCAP_S390_DFP bit 6. */ if ((elf_hwcap & (1UL << 2)) && - stfle(&facility_list_extended, 1) > 0) { + __stfle(&facility_list_extended, 1) > 0) { if (facility_list_extended & (1ULL << (64 - 43))) elf_hwcap |= 1UL << 6; } @@ -823,6 +831,7 @@ setup_arch(char **cmdline_p) cpu_init(); __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; + s390_init_cpu_topology(); /* * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 4449bf32cbf..b9768204021 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -27,6 +27,7 @@ #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/lowcore.h> +#include "entry.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -235,6 +236,10 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) /* Default to using normal stack */ sp = regs->gprs[15]; + /* Overflow on alternate signal stack gives SIGSEGV. */ + if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL)) + return (void __user *) -1UL; + /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { if (! sas_ss_flags(sp)) @@ -270,6 +275,9 @@ static int setup_frame(int sig, struct k_sigaction *ka, if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe))) goto give_sigsegv; + if (frame == (void __user *) -1UL) + goto give_sigsegv; + if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE)) goto give_sigsegv; @@ -327,6 +335,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe))) goto give_sigsegv; + if (frame == (void __user *) -1UL) + goto give_sigsegv; + if (copy_siginfo_to_user(&frame->info, info)) goto give_sigsegv; @@ -474,11 +485,6 @@ void do_signal(struct pt_regs *regs) int ret; #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_31BIT)) { - extern int handle_signal32(unsigned long sig, - struct k_sigaction *ka, - siginfo_t *info, - sigset_t *oldset, - struct pt_regs *regs); ret = handle_signal32(signr, &ka, &info, oldset, regs); } else diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 8f894d380a6..0dfa988c1b2 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -44,6 +44,7 @@ #include <asm/lowcore.h> #include <asm/sclp.h> #include <asm/cpu.h> +#include "entry.h" /* * An array with a pointer the lowcore of every CPU. @@ -67,13 +68,12 @@ enum s390_cpu_state { CPU_STATE_CONFIGURED, }; -#ifdef CONFIG_HOTPLUG_CPU -static DEFINE_MUTEX(smp_cpu_state_mutex); -#endif +DEFINE_MUTEX(smp_cpu_state_mutex); +int smp_cpu_polarization[NR_CPUS]; static int smp_cpu_state[NR_CPUS]; +static int cpu_management; static DEFINE_PER_CPU(struct cpu, cpu_devices); -DEFINE_PER_CPU(struct s390_idle_data, s390_idle); static void smp_ext_bitcall(int, ec_bit_sig); @@ -298,7 +298,7 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) /* * this function sends a 'purge tlb' signal to another CPU. */ -void smp_ptlb_callback(void *info) +static void smp_ptlb_callback(void *info) { __tlb_flush_local(); } @@ -456,6 +456,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) if (cpu_known(cpu_id)) continue; __cpu_logical_map[logical_cpu] = cpu_id; + smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; if (!cpu_stopped(logical_cpu)) continue; cpu_set(logical_cpu, cpu_present_map); @@ -489,6 +490,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) if (cpu_known(cpu_id)) continue; __cpu_logical_map[logical_cpu] = cpu_id; + smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; cpu_set(logical_cpu, cpu_present_map); if (cpu >= info->configured) smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; @@ -846,6 +848,7 @@ void __init smp_prepare_boot_cpu(void) S390_lowcore.percpu_offset = __per_cpu_offset[0]; current_set[0] = current; smp_cpu_state[0] = CPU_STATE_CONFIGURED; + smp_cpu_polarization[0] = POLARIZATION_UNKNWN; spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); } @@ -897,15 +900,19 @@ static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf, case 0: if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); - if (!rc) + if (!rc) { smp_cpu_state[cpu] = CPU_STATE_STANDBY; + smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; + } } break; case 1: if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { rc = sclp_cpu_configure(__cpu_logical_map[cpu]); - if (!rc) + if (!rc) { smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; + smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; + } } break; default: @@ -919,6 +926,34 @@ out: static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); #endif /* CONFIG_HOTPLUG_CPU */ +static ssize_t cpu_polarization_show(struct sys_device *dev, char *buf) +{ + int cpu = dev->id; + ssize_t count; + + mutex_lock(&smp_cpu_state_mutex); + switch (smp_cpu_polarization[cpu]) { + case POLARIZATION_HRZ: + count = sprintf(buf, "horizontal\n"); + break; + case POLARIZATION_VL: + count = sprintf(buf, "vertical:low\n"); + break; + case POLARIZATION_VM: + count = sprintf(buf, "vertical:medium\n"); + break; + case POLARIZATION_VH: + count = sprintf(buf, "vertical:high\n"); + break; + default: + count = sprintf(buf, "unknown\n"); + break; + } + mutex_unlock(&smp_cpu_state_mutex); + return count; +} +static SYSDEV_ATTR(polarization, 0444, cpu_polarization_show, NULL); + static ssize_t show_cpu_address(struct sys_device *dev, char *buf) { return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); @@ -931,6 +966,7 @@ static struct attribute *cpu_common_attrs[] = { &attr_configure.attr, #endif &attr_address.attr, + &attr_polarization.attr, NULL, }; @@ -1075,11 +1111,48 @@ static ssize_t __ref rescan_store(struct sys_device *dev, out: put_online_cpus(); mutex_unlock(&smp_cpu_state_mutex); + if (!cpus_empty(newcpus)) + topology_schedule_update(); return rc ? rc : count; } static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); #endif /* CONFIG_HOTPLUG_CPU */ +static ssize_t dispatching_show(struct sys_device *dev, char *buf) +{ + ssize_t count; + + mutex_lock(&smp_cpu_state_mutex); + count = sprintf(buf, "%d\n", cpu_management); + mutex_unlock(&smp_cpu_state_mutex); + return count; +} + +static ssize_t dispatching_store(struct sys_device *dev, const char *buf, + size_t count) +{ + int val, rc; + char delim; + + if (sscanf(buf, "%d %c", &val, &delim) != 1) + return -EINVAL; + if (val != 0 && val != 1) + return -EINVAL; + rc = 0; + mutex_lock(&smp_cpu_state_mutex); + get_online_cpus(); + if (cpu_management == val) + goto out; + rc = topology_set_cpu_management(val); + if (!rc) + cpu_management = val; +out: + put_online_cpus(); + mutex_unlock(&smp_cpu_state_mutex); + return rc ? rc : count; +} +static SYSDEV_ATTR(dispatching, 0644, dispatching_show, dispatching_store); + static int __init topology_init(void) { int cpu; @@ -1093,6 +1166,10 @@ static int __init topology_init(void) if (rc) return rc; #endif + rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj, + &attr_dispatching.attr); + if (rc) + return rc; for_each_present_cpu(cpu) { rc = smp_add_present_cpu(cpu); if (rc) diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index fefee99f28a..988d0d64c2c 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -29,8 +29,8 @@ #include <linux/personality.h> #include <linux/unistd.h> #include <linux/ipc.h> - #include <asm/uaccess.h> +#include "entry.h" /* * sys_pipe() is the normal C calling standard for creating diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index cb232c15536..7aec676fefd 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -30,7 +30,7 @@ #include <linux/timex.h> #include <linux/notifier.h> #include <linux/clocksource.h> - +#include <linux/clockchips.h> #include <asm/uaccess.h> #include <asm/delay.h> #include <asm/s390_ext.h> @@ -39,6 +39,7 @@ #include <asm/irq_regs.h> #include <asm/timer.h> #include <asm/etr.h> +#include <asm/cio.h> /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) @@ -57,16 +58,16 @@ static ext_int_info_t ext_int_info_cc; static ext_int_info_t ext_int_etr_cc; -static u64 init_timer_cc; static u64 jiffies_timer_cc; -static u64 xtime_cc; + +static DEFINE_PER_CPU(struct clock_event_device, comparators); /* * Scheduler clock - returns current time in nanosec units. */ unsigned long long sched_clock(void) { - return ((get_clock() - jiffies_timer_cc) * 125) >> 9; + return ((get_clock_xt() - jiffies_timer_cc) * 125) >> 9; } /* @@ -95,162 +96,40 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) #define s390_do_profile() do { ; } while(0) #endif /* CONFIG_PROFILING */ -/* - * Advance the per cpu tick counter up to the time given with the - * "time" argument. The per cpu update consists of accounting - * the virtual cpu time, calling update_process_times and calling - * the profiling hook. If xtime is before time it is advanced as well. - */ -void account_ticks(u64 time) +void clock_comparator_work(void) { - __u32 ticks; - __u64 tmp; - - /* Calculate how many ticks have passed. */ - if (time < S390_lowcore.jiffy_timer) - return; - tmp = time - S390_lowcore.jiffy_timer; - if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ - ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; - S390_lowcore.jiffy_timer += - CLK_TICKS_PER_JIFFY * (__u64) ticks; - } else if (tmp >= CLK_TICKS_PER_JIFFY) { - ticks = 2; - S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY; - } else { - ticks = 1; - S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; - } - -#ifdef CONFIG_SMP - /* - * Do not rely on the boot cpu to do the calls to do_timer. - * Spread it over all cpus instead. - */ - write_seqlock(&xtime_lock); - if (S390_lowcore.jiffy_timer > xtime_cc) { - __u32 xticks; - tmp = S390_lowcore.jiffy_timer - xtime_cc; - if (tmp >= 2*CLK_TICKS_PER_JIFFY) { - xticks = __div(tmp, CLK_TICKS_PER_JIFFY); - xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; - } else { - xticks = 1; - xtime_cc += CLK_TICKS_PER_JIFFY; - } - do_timer(xticks); - } - write_sequnlock(&xtime_lock); -#else - do_timer(ticks); -#endif - - while (ticks--) - update_process_times(user_mode(get_irq_regs())); + struct clock_event_device *cd; + S390_lowcore.clock_comparator = -1ULL; + set_clock_comparator(S390_lowcore.clock_comparator); + cd = &__get_cpu_var(comparators); + cd->event_handler(cd); s390_do_profile(); } -#ifdef CONFIG_NO_IDLE_HZ - -#ifdef CONFIG_NO_IDLE_HZ_INIT -int sysctl_hz_timer = 0; -#else -int sysctl_hz_timer = 1; -#endif - -/* - * Stop the HZ tick on the current CPU. - * Only cpu_idle may call this function. - */ -static void stop_hz_timer(void) -{ - unsigned long flags; - unsigned long seq, next; - __u64 timer, todval; - int cpu = smp_processor_id(); - - if (sysctl_hz_timer != 0) - return; - - cpu_set(cpu, nohz_cpu_mask); - - /* - * Leave the clock comparator set up for the next timer - * tick if either rcu or a softirq is pending. - */ - if (rcu_needs_cpu(cpu) || local_softirq_pending()) { - cpu_clear(cpu, nohz_cpu_mask); - return; - } - - /* - * This cpu is going really idle. Set up the clock comparator - * for the next event. - */ - next = next_timer_interrupt(); - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - timer = ((__u64) next) - ((__u64) jiffies) + jiffies_64; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - todval = -1ULL; - /* Be careful about overflows. */ - if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) { - timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; - if (timer >= jiffies_timer_cc) - todval = timer; - } - set_clock_comparator(todval); -} - /* - * Start the HZ tick on the current CPU. - * Only cpu_idle may call this function. + * Fixup the clock comparator. */ -static void start_hz_timer(void) +static void fixup_clock_comparator(unsigned long long delta) { - if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) + /* If nobody is waiting there's nothing to fix. */ + if (S390_lowcore.clock_comparator == -1ULL) return; - account_ticks(get_clock()); - set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); - cpu_clear(smp_processor_id(), nohz_cpu_mask); -} - -static int nohz_idle_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - switch (action) { - case S390_CPU_IDLE: - stop_hz_timer(); - break; - case S390_CPU_NOT_IDLE: - start_hz_timer(); - break; - } - return NOTIFY_OK; + S390_lowcore.clock_comparator += delta; + set_clock_comparator(S390_lowcore.clock_comparator); } -static struct notifier_block nohz_idle_nb = { - .notifier_call = nohz_idle_notify, -}; - -static void __init nohz_init(void) +static int s390_next_event(unsigned long delta, + struct clock_event_device *evt) { - if (register_idle_notifier(&nohz_idle_nb)) - panic("Couldn't register idle notifier"); + S390_lowcore.clock_comparator = get_clock() + delta; + set_clock_comparator(S390_lowcore.clock_comparator); + return 0; } -#endif - -/* - * Set up per cpu jiffy timer and set the clock comparator. - */ -static void setup_jiffy_timer(void) +static void s390_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) { - /* Set up clock comparator to next jiffy. */ - S390_lowcore.jiffy_timer = - jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY; - set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); } /* @@ -259,7 +138,26 @@ static void setup_jiffy_timer(void) */ void init_cpu_timer(void) { - setup_jiffy_timer(); + struct clock_event_device *cd; + int cpu; + + S390_lowcore.clock_comparator = -1ULL; + set_clock_comparator(S390_lowcore.clock_comparator); + + cpu = smp_processor_id(); + cd = &per_cpu(comparators, cpu); + cd->name = "comparator"; + cd->features = CLOCK_EVT_FEAT_ONESHOT; + cd->mult = 16777; + cd->shift = 12; + cd->min_delta_ns = 1; + cd->max_delta_ns = LONG_MAX; + cd->rating = 400; + cd->cpumask = cpumask_of_cpu(cpu); + cd->set_next_event = s390_next_event; + cd->set_mode = s390_set_mode; + + clockevents_register_device(cd); /* Enable clock comparator timer interrupt. */ __ctl_set_bit(0,11); @@ -270,8 +168,6 @@ void init_cpu_timer(void) static void clock_comparator_interrupt(__u16 code) { - /* set clock comparator for next tick */ - set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); } static void etr_reset(void); @@ -316,8 +212,9 @@ static struct clocksource clocksource_tod = { */ void __init time_init(void) { + u64 init_timer_cc; + init_timer_cc = reset_tod_clock(); - xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; /* set xtime */ @@ -342,10 +239,6 @@ void __init time_init(void) /* Enable TOD clock interrupts on the boot cpu. */ init_cpu_timer(); -#ifdef CONFIG_NO_IDLE_HZ - nohz_init(); -#endif - #ifdef CONFIG_VIRT_TIMER vtime_init(); #endif @@ -699,53 +592,49 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) } /* - * The time is "clock". xtime is what we think the time is. + * The time is "clock". old is what we think the time is. * Adjust the value by a multiple of jiffies and add the delta to ntp. * "delay" is an approximation how long the synchronization took. If * the time correction is positive, then "delay" is subtracted from * the time difference and only the remaining part is passed to ntp. */ -static void etr_adjust_time(unsigned long long clock, unsigned long long delay) +static unsigned long long etr_adjust_time(unsigned long long old, + unsigned long long clock, + unsigned long long delay) { unsigned long long delta, ticks; struct timex adjust; - /* - * We don't have to take the xtime lock because the cpu - * executing etr_adjust_time is running disabled in - * tasklet context and all other cpus are looping in - * etr_sync_cpu_start. - */ - if (clock > xtime_cc) { + if (clock > old) { /* It is later than we thought. */ - delta = ticks = clock - xtime_cc; + delta = ticks = clock - old; delta = ticks = (delta < delay) ? 0 : delta - delay; delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - init_timer_cc = init_timer_cc + delta; - jiffies_timer_cc = jiffies_timer_cc + delta; - xtime_cc = xtime_cc + delta; adjust.offset = ticks * (1000000 / HZ); } else { /* It is earlier than we thought. */ - delta = ticks = xtime_cc - clock; + delta = ticks = old - clock; delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - init_timer_cc = init_timer_cc - delta; - jiffies_timer_cc = jiffies_timer_cc - delta; - xtime_cc = xtime_cc - delta; + delta = -delta; adjust.offset = -ticks * (1000000 / HZ); } + jiffies_timer_cc += delta; if (adjust.offset != 0) { printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", adjust.offset); adjust.modes = ADJ_OFFSET_SINGLESHOT; do_adjtimex(&adjust); } + return delta; } +static struct { + int in_sync; + unsigned long long fixup_cc; +} etr_sync; + static void etr_sync_cpu_start(void *dummy) { - int *in_sync = dummy; - etr_enable_sync_clock(); /* * This looks like a busy wait loop but it isn't. etr_sync_cpus @@ -753,7 +642,7 @@ static void etr_sync_cpu_start(void *dummy) * __udelay will stop the cpu on an enabled wait psw until the * TOD is running again. */ - while (*in_sync == 0) { + while (etr_sync.in_sync == 0) { __udelay(1); /* * A different cpu changes *in_sync. Therefore use @@ -761,14 +650,14 @@ static void etr_sync_cpu_start(void *dummy) */ barrier(); } - if (*in_sync != 1) + if (etr_sync.in_sync != 1) /* Didn't work. Clear per-cpu in sync bit again. */ etr_disable_sync_clock(NULL); /* * This round of TOD syncing is done. Set the clock comparator * to the next tick and let the processor continue. */ - setup_jiffy_timer(); + fixup_clock_comparator(etr_sync.fixup_cc); } static void etr_sync_cpu_end(void *dummy) @@ -783,8 +672,8 @@ static void etr_sync_cpu_end(void *dummy) static int etr_sync_clock(struct etr_aib *aib, int port) { struct etr_aib *sync_port; - unsigned long long clock, delay; - int in_sync, follows; + unsigned long long clock, old_clock, delay, delta; + int follows; int rc; /* Check if the current aib is adjacent to the sync port aib. */ @@ -799,9 +688,9 @@ static int etr_sync_clock(struct etr_aib *aib, int port) * successfully synced the clock. smp_call_function will * return after all other cpus are in etr_sync_cpu_start. */ - in_sync = 0; + memset(&etr_sync, 0, sizeof(etr_sync)); preempt_disable(); - smp_call_function(etr_sync_cpu_start,&in_sync,0,0); + smp_call_function(etr_sync_cpu_start, NULL, 0, 0); local_irq_disable(); etr_enable_sync_clock(); @@ -809,6 +698,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port) __ctl_set_bit(14, 21); __ctl_set_bit(0, 29); clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; + old_clock = get_clock(); if (set_clock(clock) == 0) { __udelay(1); /* Wait for the clock to start. */ __ctl_clear_bit(0, 29); @@ -817,16 +707,17 @@ static int etr_sync_clock(struct etr_aib *aib, int port) /* Adjust Linux timing variables. */ delay = (unsigned long long) (aib->edf2.etv - sync_port->edf2.etv) << 32; - etr_adjust_time(clock, delay); - setup_jiffy_timer(); + delta = etr_adjust_time(old_clock, clock, delay); + etr_sync.fixup_cc = delta; + fixup_clock_comparator(delta); /* Verify that the clock is properly set. */ if (!etr_aib_follows(sync_port, aib, port)) { /* Didn't work. */ etr_disable_sync_clock(NULL); - in_sync = -EAGAIN; + etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } else { - in_sync = 1; + etr_sync.in_sync = 1; rc = 0; } } else { @@ -834,7 +725,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port) __ctl_clear_bit(0, 29); __ctl_clear_bit(14, 21); etr_disable_sync_clock(NULL); - in_sync = -EAGAIN; + etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } local_irq_enable(); diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c new file mode 100644 index 00000000000..12b39b3d9c3 --- /dev/null +++ b/arch/s390/kernel/topology.c @@ -0,0 +1,314 @@ +/* + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + */ + +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/bootmem.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <asm/delay.h> +#include <asm/s390_ext.h> +#include <asm/sysinfo.h> + +#define CPU_BITS 64 +#define NR_MAG 6 + +#define PTF_HORIZONTAL (0UL) +#define PTF_VERTICAL (1UL) +#define PTF_CHECK (2UL) + +struct tl_cpu { + unsigned char reserved0[4]; + unsigned char :6; + unsigned char pp:2; + unsigned char reserved1; + unsigned short origin; + unsigned long mask[CPU_BITS / BITS_PER_LONG]; +}; + +struct tl_container { + unsigned char reserved[8]; +}; + +union tl_entry { + unsigned char nl; + struct tl_cpu cpu; + struct tl_container container; +}; + +struct tl_info { + unsigned char reserved0[2]; + unsigned short length; + unsigned char mag[NR_MAG]; + unsigned char reserved1; + unsigned char mnest; + unsigned char reserved2[4]; + union tl_entry tle[0]; +}; + +struct core_info { + struct core_info *next; + cpumask_t mask; +}; + +static void topology_work_fn(struct work_struct *work); +static struct tl_info *tl_info; +static struct core_info core_info; +static int machine_has_topology; +static int machine_has_topology_irq; +static struct timer_list topology_timer; +static void set_topology_timer(void); +static DECLARE_WORK(topology_work, topology_work_fn); + +cpumask_t cpu_coregroup_map(unsigned int cpu) +{ + struct core_info *core = &core_info; + cpumask_t mask; + + cpus_clear(mask); + if (!machine_has_topology) + return cpu_present_map; + mutex_lock(&smp_cpu_state_mutex); + while (core) { + if (cpu_isset(cpu, core->mask)) { + mask = core->mask; + break; + } + core = core->next; + } + mutex_unlock(&smp_cpu_state_mutex); + if (cpus_empty(mask)) + mask = cpumask_of_cpu(cpu); + return mask; +} + +static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core) +{ + unsigned int cpu; + + for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS); + cpu < CPU_BITS; + cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1)) + { + unsigned int rcpu, lcpu; + + rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin; + for_each_present_cpu(lcpu) { + if (__cpu_logical_map[lcpu] == rcpu) { + cpu_set(lcpu, core->mask); + smp_cpu_polarization[lcpu] = tl_cpu->pp; + } + } + } +} + +static void clear_cores(void) +{ + struct core_info *core = &core_info; + + while (core) { + cpus_clear(core->mask); + core = core->next; + } +} + +static union tl_entry *next_tle(union tl_entry *tle) +{ + if (tle->nl) + return (union tl_entry *)((struct tl_container *)tle + 1); + else + return (union tl_entry *)((struct tl_cpu *)tle + 1); +} + +static void tl_to_cores(struct tl_info *info) +{ + union tl_entry *tle, *end; + struct core_info *core = &core_info; + + mutex_lock(&smp_cpu_state_mutex); + clear_cores(); + tle = info->tle; + end = (union tl_entry *)((unsigned long)info + info->length); + while (tle < end) { + switch (tle->nl) { + case 5: + case 4: + case 3: + case 2: + break; + case 1: + core = core->next; + break; + case 0: + add_cpus_to_core(&tle->cpu, core); + break; + default: + clear_cores(); + machine_has_topology = 0; + return; + } + tle = next_tle(tle); + } + mutex_unlock(&smp_cpu_state_mutex); +} + +static void topology_update_polarization_simple(void) +{ + int cpu; + + mutex_lock(&smp_cpu_state_mutex); + for_each_present_cpu(cpu) + smp_cpu_polarization[cpu] = POLARIZATION_HRZ; + mutex_unlock(&smp_cpu_state_mutex); +} + +static int ptf(unsigned long fc) +{ + int rc; + + asm volatile( + " .insn rre,0xb9a20000,%1,%1\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (rc) + : "d" (fc) : "cc"); + return rc; +} + +int topology_set_cpu_management(int fc) +{ + int cpu; + int rc; + + if (!machine_has_topology) + return -EOPNOTSUPP; + if (fc) + rc = ptf(PTF_VERTICAL); + else + rc = ptf(PTF_HORIZONTAL); + if (rc) + return -EBUSY; + for_each_present_cpu(cpu) + smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; + return rc; +} + +void arch_update_cpu_topology(void) +{ + struct tl_info *info = tl_info; + struct sys_device *sysdev; + int cpu; + + if (!machine_has_topology) { + topology_update_polarization_simple(); + return; + } + stsi(info, 15, 1, 2); + tl_to_cores(info); + for_each_online_cpu(cpu) { + sysdev = get_cpu_sysdev(cpu); + kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); + } +} + +static void topology_work_fn(struct work_struct *work) +{ + arch_reinit_sched_domains(); +} + +void topology_schedule_update(void) +{ + schedule_work(&topology_work); +} + +static void topology_timer_fn(unsigned long ignored) +{ + if (ptf(PTF_CHECK)) + topology_schedule_update(); + set_topology_timer(); +} + +static void set_topology_timer(void) +{ + topology_timer.function = topology_timer_fn; + topology_timer.data = 0; + topology_timer.expires = jiffies + 60 * HZ; + add_timer(&topology_timer); +} + +static void topology_interrupt(__u16 code) +{ + schedule_work(&topology_work); +} + +static int __init init_topology_update(void) +{ + int rc; + + if (!machine_has_topology) { + topology_update_polarization_simple(); + return 0; + } + init_timer_deferrable(&topology_timer); + if (machine_has_topology_irq) { + rc = register_external_interrupt(0x2005, topology_interrupt); + if (rc) + return rc; + ctl_set_bit(0, 8); + } + else + set_topology_timer(); + return 0; +} +__initcall(init_topology_update); + +void __init s390_init_cpu_topology(void) +{ + unsigned long long facility_bits; + struct tl_info *info; + struct core_info *core; + int nr_cores; + int i; + + if (stfle(&facility_bits, 1) <= 0) + return; + if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61))) + return; + machine_has_topology = 1; + + if (facility_bits & (1ULL << 51)) + machine_has_topology_irq = 1; + + tl_info = alloc_bootmem_pages(PAGE_SIZE); + if (!tl_info) + goto error; + info = tl_info; + stsi(info, 15, 1, 2); + + nr_cores = info->mag[NR_MAG - 2]; + for (i = 0; i < info->mnest - 2; i++) + nr_cores *= info->mag[NR_MAG - 3 - i]; + + printk(KERN_INFO "CPU topology:"); + for (i = 0; i < NR_MAG; i++) + printk(" %d", info->mag[i]); + printk(" / %d\n", info->mnest); + + core = &core_info; + for (i = 0; i < nr_cores; i++) { + core->next = alloc_bootmem(sizeof(struct core_info)); + core = core->next; + if (!core) + goto error; + } + return; +error: + machine_has_topology = 0; + machine_has_topology_irq = 0; +} diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 60f728aeaf1..57b607b6110 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -42,11 +42,8 @@ #include <asm/s390_ext.h> #include <asm/lowcore.h> #include <asm/debug.h> +#include "entry.h" -/* Called from entry.S only */ -extern void handle_per_exception(struct pt_regs *regs); - -typedef void pgm_check_handler_t(struct pt_regs *, long); pgm_check_handler_t *pgm_check_table[128]; #ifdef CONFIG_SYSCTL @@ -59,7 +56,6 @@ 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; }) @@ -138,7 +134,6 @@ void show_trace(struct task_struct *task, unsigned long *stack) else __show_trace(sp, S390_lowcore.thread_info, S390_lowcore.thread_info + THREAD_SIZE); - printk("\n"); if (!task) task = current; debug_show_held_locks(task); @@ -166,6 +161,15 @@ void show_stack(struct task_struct *task, unsigned long *sp) show_trace(task, sp); } +#ifdef CONFIG_64BIT +void show_last_breaking_event(struct pt_regs *regs) +{ + printk("Last Breaking-Event-Address:\n"); + printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN); + print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN); +} +#endif + /* * The architecture-independent dump_stack generator */ @@ -739,6 +743,5 @@ void __init trap_init(void) pgm_check_table[0x15] = &operand_exception; pgm_check_table[0x1C] = &space_switch_exception; pgm_check_table[0x1D] = &hfp_sqrt_exception; - pgm_check_table[0x40] = &do_monitor_call; pfault_irq_init(); } diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 70f2a862b67..eae21a8ac72 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -34,7 +34,7 @@ void __delay(unsigned long loops) */ void __udelay(unsigned long usecs) { - u64 end, time, jiffy_timer = 0; + u64 end, time, old_cc = 0; unsigned long flags, cr0, mask, dummy; int irq_context; @@ -43,8 +43,8 @@ void __udelay(unsigned long usecs) local_bh_disable(); local_irq_save(flags); if (raw_irqs_disabled_flags(flags)) { - jiffy_timer = S390_lowcore.jiffy_timer; - S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); + old_cc = S390_lowcore.clock_comparator; + S390_lowcore.clock_comparator = -1ULL; __ctl_store(cr0, 0, 0); dummy = (cr0 & 0xffff00e0) | 0x00000800; __ctl_load(dummy , 0, 0); @@ -55,8 +55,8 @@ void __udelay(unsigned long usecs) end = get_clock() + ((u64) usecs << 12); do { - time = end < S390_lowcore.jiffy_timer ? - end : S390_lowcore.jiffy_timer; + time = end < S390_lowcore.clock_comparator ? + end : S390_lowcore.clock_comparator; set_clock_comparator(time); trace_hardirqs_on(); __load_psw_mask(mask); @@ -65,10 +65,10 @@ void __udelay(unsigned long usecs) if (raw_irqs_disabled_flags(flags)) { __ctl_load(cr0, 0, 0); - S390_lowcore.jiffy_timer = jiffy_timer; + S390_lowcore.clock_comparator = old_cc; } if (!irq_context) _local_bh_enable(); - set_clock_comparator(S390_lowcore.jiffy_timer); + set_clock_comparator(S390_lowcore.clock_comparator); local_irq_restore(flags); } diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 5efdfe9f5e7..d66215b0fde 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -302,6 +302,10 @@ static size_t copy_in_user_pt(size_t n, void __user *to, pte_t *pte_from, *pte_to; int write_user; + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy((void __force *) to, (void __force *) from, n); + return 0; + } done = 0; retry: spin_lock(&mm->page_table_lock); @@ -361,18 +365,10 @@ fault: : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ "m" (*uaddr) : "cc" ); -int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) +static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) { int oldval = 0, newval, ret; - spin_lock(¤t->mm->page_table_lock); - uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); - if (!uaddr) { - spin_unlock(¤t->mm->page_table_lock); - return -EFAULT; - } - get_page(virt_to_page(uaddr)); - spin_unlock(¤t->mm->page_table_lock); switch (op) { case FUTEX_OP_SET: __futex_atomic_op("lr %2,%5\n", @@ -397,17 +393,17 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) default: ret = -ENOSYS; } - put_page(virt_to_page(uaddr)); - *old = oldval; + if (ret == 0) + *old = oldval; return ret; } -int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) +int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) { int ret; - if (!current->mm) - return -EFAULT; + if (segment_eq(get_fs(), KERNEL_DS)) + return __futex_atomic_op_pt(op, uaddr, oparg, old); spin_lock(¤t->mm->page_table_lock); uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); if (!uaddr) { @@ -416,13 +412,40 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) } get_page(virt_to_page(uaddr)); spin_unlock(¤t->mm->page_table_lock); - asm volatile(" cs %1,%4,0(%5)\n" - "0: lr %0,%1\n" - "1:\n" - EX_TABLE(0b,1b) + ret = __futex_atomic_op_pt(op, uaddr, oparg, old); + put_page(virt_to_page(uaddr)); + return ret; +} + +static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) +{ + int ret; + + asm volatile("0: cs %1,%4,0(%5)\n" + "1: lr %0,%1\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+d" (oldval), "=m" (*uaddr) : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) : "cc", "memory" ); + return ret; +} + +int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) +{ + int ret; + + if (segment_eq(get_fs(), KERNEL_DS)) + return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval); + spin_lock(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval); put_page(virt_to_page(uaddr)); return ret; } diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 880b0ebf894..ed2af0a3303 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -289,22 +289,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long rc = add_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); - switch (rc) { - case 0: - break; - case -ENOSPC: - PRINT_WARN("segment_load: not loading segment %s - overlaps " - "storage/segment\n", name); - goto out_free; - case -ERANGE: - PRINT_WARN("segment_load: not loading segment %s - exceeds " - "kernel mapping range\n", name); - goto out_free; - default: - PRINT_WARN("segment_load: not loading segment %s (rc: %d)\n", - name, rc); + if (rc) goto out_free; - } seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL); if (seg->res == NULL) { @@ -582,8 +568,59 @@ out: mutex_unlock(&dcss_lock); } +/* + * print appropriate error message for segment_load()/segment_type() + * return code + */ +void segment_warning(int rc, char *seg_name) +{ + switch (rc) { + case -ENOENT: + PRINT_WARN("cannot load/query segment %s, " + "does not exist\n", seg_name); + break; + case -ENOSYS: + PRINT_WARN("cannot load/query segment %s, " + "not running on VM\n", seg_name); + break; + case -EIO: + PRINT_WARN("cannot load/query segment %s, " + "hardware error\n", seg_name); + break; + case -ENOTSUPP: + PRINT_WARN("cannot load/query segment %s, " + "is a multi-part segment\n", seg_name); + break; + case -ENOSPC: + PRINT_WARN("cannot load/query segment %s, " + "overlaps with storage\n", seg_name); + break; + case -EBUSY: + PRINT_WARN("cannot load/query segment %s, " + "overlaps with already loaded dcss\n", seg_name); + break; + case -EPERM: + PRINT_WARN("cannot load/query segment %s, " + "already loaded in incompatible mode\n", seg_name); + break; + case -ENOMEM: + PRINT_WARN("cannot load/query segment %s, " + "out of memory\n", seg_name); + break; + case -ERANGE: + PRINT_WARN("cannot load/query segment %s, " + "exceeds kernel mapping range\n", seg_name); + break; + default: + PRINT_WARN("cannot load/query segment %s, " + "return value %i\n", seg_name, rc); + break; + } +} + EXPORT_SYMBOL(segment_load); EXPORT_SYMBOL(segment_unload); EXPORT_SYMBOL(segment_save); EXPORT_SYMBOL(segment_type); EXPORT_SYMBOL(segment_modify_shared); +EXPORT_SYMBOL(segment_warning); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index ed13d429a48..2650f46001d 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -28,11 +28,11 @@ #include <linux/hardirq.h> #include <linux/kprobes.h> #include <linux/uaccess.h> - #include <asm/system.h> #include <asm/pgtable.h> #include <asm/s390_ext.h> #include <asm/mmu_context.h> +#include "../kernel/entry.h" #ifndef CONFIG_64BIT #define __FAIL_ADDR_MASK 0x7ffff000 @@ -50,8 +50,6 @@ extern int sysctl_userprocess_debug; #endif -extern void die(const char *,struct pt_regs *,long); - #ifdef CONFIG_KPROBES static inline int notify_page_fault(struct pt_regs *regs, long err) { @@ -245,11 +243,6 @@ static void do_sigbus(struct pt_regs *regs, unsigned long error_code, } #ifdef CONFIG_S390_EXEC_PROTECT -extern long sys_sigreturn(struct pt_regs *regs); -extern long sys_rt_sigreturn(struct pt_regs *regs); -extern long sys32_sigreturn(struct pt_regs *regs); -extern long sys32_rt_sigreturn(struct pt_regs *regs); - static int signal_return(struct mm_struct *mm, struct pt_regs *regs, unsigned long address, unsigned long error_code) { @@ -270,15 +263,15 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs, #ifdef CONFIG_COMPAT compat = test_tsk_thread_flag(current, TIF_31BIT); if (compat && instruction == 0x0a77) - sys32_sigreturn(regs); + sys32_sigreturn(); else if (compat && instruction == 0x0aad) - sys32_rt_sigreturn(regs); + sys32_rt_sigreturn(); else #endif if (instruction == 0x0a77) - sys_sigreturn(regs); + sys_sigreturn(); else if (instruction == 0x0aad) - sys_rt_sigreturn(regs); + sys_rt_sigreturn(); else { current->thread.prot_addr = address; current->thread.trap_no = error_code; @@ -424,7 +417,7 @@ no_context: } void __kprobes do_protection_exception(struct pt_regs *regs, - unsigned long error_code) + long error_code) { /* Protection exception is supressing, decrement psw address. */ regs->psw.addr -= (error_code >> 16); @@ -440,7 +433,7 @@ void __kprobes do_protection_exception(struct pt_regs *regs, do_exception(regs, 4, 1); } -void __kprobes do_dat_exception(struct pt_regs *regs, unsigned long error_code) +void __kprobes do_dat_exception(struct pt_regs *regs, long error_code) { do_exception(regs, error_code & 0xff, 0); } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 8053245fe25..202c952a29b 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -50,7 +50,6 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10)); i = max_mapnr; while (i-- > 0) { if (!pfn_valid(i)) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 84cdf902573..349b6edc579 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -116,6 +116,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, err = -EAGAIN; if (!bytes_read && (filp->f_flags & O_NONBLOCK)) goto out; + if (bytes_read < 0) { + err = bytes_read; + goto out; + } err = -EFAULT; while (bytes_read && size) { diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 6b658d84d52..6d2f0c8d419 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -64,6 +64,7 @@ config ZCRYPT tristate "Support for PCI-attached cryptographic adapters" depends on S390 select ZCRYPT_MONOLITHIC if ZCRYPT="y" + select HW_RANDOM help Select this option if you want to use a PCI-attached cryptographic adapter like: diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index e879b212cf4..07883197f47 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -20,6 +20,7 @@ config DCSSBLK config DASD tristate "Support for DASD devices" depends on CCW && BLOCK + select IOSCHED_DEADLINE help Enable this option if you want to access DASDs directly utilizing S/390s channel subsystem commands. This is necessary for running diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index ccf46c96adb..ac6d4d3218b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -980,12 +980,12 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, break; case -ETIMEDOUT: printk(KERN_WARNING"%s(%s): request timed out\n", - __FUNCTION__, cdev->dev.bus_id); + __func__, cdev->dev.bus_id); //FIXME - dasd uses own timeout interface... break; default: printk(KERN_WARNING"%s(%s): unknown error %ld\n", - __FUNCTION__, cdev->dev.bus_id, PTR_ERR(irb)); + __func__, cdev->dev.bus_id, PTR_ERR(irb)); } return; } @@ -1956,6 +1956,7 @@ static int dasd_alloc_queue(struct dasd_block *block) block->request_queue->queuedata = block; elevator_exit(block->request_queue->elevator); + block->request_queue->elevator = NULL; rc = elevator_init(block->request_queue, "deadline"); if (rc) { blk_cleanup_queue(block->request_queue); @@ -2298,9 +2299,8 @@ int dasd_generic_set_offline(struct ccw_device *cdev) * in the other openers. */ if (device->block) { - struct dasd_block *block = device->block; - max_count = block->bdev ? 0 : -1; - open_count = (int) atomic_read(&block->open_count); + max_count = device->block->bdev ? 0 : -1; + open_count = atomic_read(&device->block->open_count); if (open_count > max_count) { if (open_count > 0) printk(KERN_WARNING "Can't offline dasd " diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index b19db20a0be..e6700df52df 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1996,6 +1996,36 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense) } /* end dasd_3990_erp_compound */ /* + *DASD_3990_ERP_HANDLE_SIM + * + *DESCRIPTION + * inspects the SIM SENSE data and starts an appropriate action + * + * PARAMETER + * sense sense data of the actual error + * + * RETURN VALUES + * none + */ +void +dasd_3990_erp_handle_sim(struct dasd_device *device, char *sense) +{ + /* print message according to log or message to operator mode */ + if ((sense[24] & DASD_SIM_MSG_TO_OP) || (sense[1] & 0x10)) { + + /* print SIM SRC from RefCode */ + DEV_MESSAGE(KERN_ERR, device, "SIM - SRC: " + "%02x%02x%02x%02x", sense[22], + sense[23], sense[11], sense[12]); + } else if (sense[24] & DASD_SIM_LOG) { + /* print SIM SRC Refcode */ + DEV_MESSAGE(KERN_WARNING, device, "SIM - SRC: " + "%02x%02x%02x%02x", sense[22], + sense[23], sense[11], sense[12]); + } +} + +/* * DASD_3990_ERP_INSPECT_32 * * DESCRIPTION @@ -2018,6 +2048,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) erp->function = dasd_3990_erp_inspect_32; + /* check for SIM sense data */ + if ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE) + dasd_3990_erp_handle_sim(device, sense); + if (sense[25] & DASD_SENSE_BIT_0) { /* compound program action codes (byte25 bit 0 == '1') */ diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 3a40bee9d35..2d8df0b3053 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -745,6 +745,19 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu) spin_unlock_irqrestore(&lcu->lock, flags); } +static void __stop_device_on_lcu(struct dasd_device *device, + struct dasd_device *pos) +{ + /* If pos == device then device is already locked! */ + if (pos == device) { + pos->stopped |= DASD_STOPPED_SU; + return; + } + spin_lock(get_ccwdev_lock(pos->cdev)); + pos->stopped |= DASD_STOPPED_SU; + spin_unlock(get_ccwdev_lock(pos->cdev)); +} + /* * This function is called in interrupt context, so the * cdev lock for device is already locked! @@ -755,35 +768,15 @@ static void _stop_all_devices_on_lcu(struct alias_lcu *lcu, struct alias_pav_group *pavgroup; struct dasd_device *pos; - list_for_each_entry(pos, &lcu->active_devices, alias_list) { - if (pos != device) - spin_lock(get_ccwdev_lock(pos->cdev)); - pos->stopped |= DASD_STOPPED_SU; - if (pos != device) - spin_unlock(get_ccwdev_lock(pos->cdev)); - } - list_for_each_entry(pos, &lcu->inactive_devices, alias_list) { - if (pos != device) - spin_lock(get_ccwdev_lock(pos->cdev)); - pos->stopped |= DASD_STOPPED_SU; - if (pos != device) - spin_unlock(get_ccwdev_lock(pos->cdev)); - } + list_for_each_entry(pos, &lcu->active_devices, alias_list) + __stop_device_on_lcu(device, pos); + list_for_each_entry(pos, &lcu->inactive_devices, alias_list) + __stop_device_on_lcu(device, pos); list_for_each_entry(pavgroup, &lcu->grouplist, group) { - list_for_each_entry(pos, &pavgroup->baselist, alias_list) { - if (pos != device) - spin_lock(get_ccwdev_lock(pos->cdev)); - pos->stopped |= DASD_STOPPED_SU; - if (pos != device) - spin_unlock(get_ccwdev_lock(pos->cdev)); - } - list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) { - if (pos != device) - spin_lock(get_ccwdev_lock(pos->cdev)); - pos->stopped |= DASD_STOPPED_SU; - if (pos != device) - spin_unlock(get_ccwdev_lock(pos->cdev)); - } + list_for_each_entry(pos, &pavgroup->baselist, alias_list) + __stop_device_on_lcu(device, pos); + list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) + __stop_device_on_lcu(device, pos); } } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 61f16937c1e..a0edae091b5 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1415,6 +1415,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, return; } + + /* service information message SIM */ + if ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE) { + dasd_3990_erp_handle_sim(device, irb->ecw); + return; + } + /* just report other unsolicited interrupts */ DEV_MESSAGE(KERN_DEBUG, device, "%s", "unsolicited interrupt received"); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index d13ea05089a..116611583df 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -125,7 +125,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) private = (struct dasd_fba_private *) device->private; if (private == NULL) { - private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL); + private = kzalloc(sizeof(struct dasd_fba_private), + GFP_KERNEL | GFP_DMA); if (private == NULL) { DEV_MESSAGE(KERN_WARNING, device, "%s", "memory allocation failed for private " diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 44b2984dfbe..6c624bf4461 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -72,6 +72,11 @@ struct dasd_block; #define DASD_SENSE_BIT_2 0x20 #define DASD_SENSE_BIT_3 0x10 +/* BIT DEFINITIONS FOR SIM SENSE */ +#define DASD_SIM_SENSE 0x0F +#define DASD_SIM_MSG_TO_OP 0x03 +#define DASD_SIM_LOG 0x0C + /* * SECTION: MACROs for klogd and s390 debug feature (dbf) */ @@ -621,6 +626,7 @@ void dasd_log_sense(struct dasd_ccw_req *, struct irb *); /* externals in dasd_3990_erp.c */ struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *); +void dasd_3990_erp_handle_sim(struct dasd_device *, char *); /* externals in dasd_eer.c */ #ifdef CONFIG_DASD_EER diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index e6c94dbfdea..04787eab101 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -142,57 +142,6 @@ dcssblk_get_device_by_name(char *name) return NULL; } -/* - * print appropriate error message for segment_load()/segment_type() - * return code - */ -static void -dcssblk_segment_warn(int rc, char* seg_name) -{ - switch (rc) { - case -ENOENT: - PRINT_WARN("cannot load/query segment %s, does not exist\n", - seg_name); - break; - case -ENOSYS: - PRINT_WARN("cannot load/query segment %s, not running on VM\n", - seg_name); - break; - case -EIO: - PRINT_WARN("cannot load/query segment %s, hardware error\n", - seg_name); - break; - case -ENOTSUPP: - PRINT_WARN("cannot load/query segment %s, is a multi-part " - "segment\n", seg_name); - break; - case -ENOSPC: - PRINT_WARN("cannot load/query segment %s, overlaps with " - "storage\n", seg_name); - break; - case -EBUSY: - PRINT_WARN("cannot load/query segment %s, overlaps with " - "already loaded dcss\n", seg_name); - break; - case -EPERM: - PRINT_WARN("cannot load/query segment %s, already loaded in " - "incompatible mode\n", seg_name); - break; - case -ENOMEM: - PRINT_WARN("cannot load/query segment %s, out of memory\n", - seg_name); - break; - case -ERANGE: - PRINT_WARN("cannot load/query segment %s, exceeds kernel " - "mapping range\n", seg_name); - break; - default: - PRINT_WARN("cannot load/query segment %s, return value %i\n", - seg_name, rc); - break; - } -} - static void dcssblk_unregister_callback(struct device *dev) { device_unregister(dev); @@ -423,7 +372,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char rc = segment_load(local_buf, SEGMENT_SHARED, &dev_info->start, &dev_info->end); if (rc < 0) { - dcssblk_segment_warn(rc, dev_info->segment_name); + segment_warning(rc, dev_info->segment_name); goto dealloc_gendisk; } seg_byte_size = (dev_info->end - dev_info->start + 1); diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 67009bfa093..1e1f50655bb 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -111,56 +111,6 @@ static void dcss_mkname(char *ascii_name, char *ebcdic_name) ASCEBC(ebcdic_name, 8); } -/* - * print appropriate error message for segment_load()/segment_type() - * return code - */ -static void mon_segment_warn(int rc, char* seg_name) -{ - switch (rc) { - case -ENOENT: - P_WARNING("cannot load/query segment %s, does not exist\n", - seg_name); - break; - case -ENOSYS: - P_WARNING("cannot load/query segment %s, not running on VM\n", - seg_name); - break; - case -EIO: - P_WARNING("cannot load/query segment %s, hardware error\n", - seg_name); - break; - case -ENOTSUPP: - P_WARNING("cannot load/query segment %s, is a multi-part " - "segment\n", seg_name); - break; - case -ENOSPC: - P_WARNING("cannot load/query segment %s, overlaps with " - "storage\n", seg_name); - break; - case -EBUSY: - P_WARNING("cannot load/query segment %s, overlaps with " - "already loaded dcss\n", seg_name); - break; - case -EPERM: - P_WARNING("cannot load/query segment %s, already loaded in " - "incompatible mode\n", seg_name); - break; - case -ENOMEM: - P_WARNING("cannot load/query segment %s, out of memory\n", - seg_name); - break; - case -ERANGE: - P_WARNING("cannot load/query segment %s, exceeds kernel " - "mapping range\n", seg_name); - break; - default: - P_WARNING("cannot load/query segment %s, return value %i\n", - seg_name, rc); - break; - } -} - static inline unsigned long mon_mca_start(struct mon_msg *monmsg) { return *(u32 *) &monmsg->msg.rmmsg; @@ -585,7 +535,7 @@ static int __init mon_init(void) rc = segment_type(mon_dcss_name); if (rc < 0) { - mon_segment_warn(rc, mon_dcss_name); + segment_warning(rc, mon_dcss_name); goto out_iucv; } if (rc != SEG_TYPE_SC) { @@ -598,7 +548,7 @@ static int __init mon_init(void) rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { - mon_segment_warn(rc, mon_dcss_name); + segment_warning(rc, mon_dcss_name); rc = -EINVAL; goto out_iucv; } diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 2e616e33891..e3b3d390b4a 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count) if (sclp_ttybuf == NULL) { while (list_empty(&sclp_tty_pages)) { spin_unlock_irqrestore(&sclp_tty_lock, flags); - if (in_atomic()) + if (in_interrupt()) sclp_sync_wait(); else wait_event(sclp_tty_waitq, diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index f7b258dfd52..ed507594e62 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -383,7 +383,7 @@ sclp_vt220_timeout(unsigned long data) */ static int __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, - int convertlf) + int convertlf, int may_schedule) { unsigned long flags; void *page; @@ -398,9 +398,8 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, /* Create a sclp output buffer if none exists yet */ if (sclp_vt220_current_request == NULL) { while (list_empty(&sclp_vt220_empty)) { - spin_unlock_irqrestore(&sclp_vt220_lock, - flags); - if (in_atomic()) + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + if (in_interrupt() || !may_schedule) sclp_sync_wait(); else wait_event(sclp_vt220_waitq, @@ -450,7 +449,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, static int sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count) { - return __sclp_vt220_write(buf, count, 1, 0); + return __sclp_vt220_write(buf, count, 1, 0, 1); } #define SCLP_VT220_SESSION_ENDED 0x01 @@ -529,7 +528,7 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp) static void sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) { - __sclp_vt220_write(&ch, 1, 0, 0); + __sclp_vt220_write(&ch, 1, 0, 0, 1); } /* @@ -746,7 +745,7 @@ __initcall(sclp_vt220_tty_init); static void sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count) { - __sclp_vt220_write((const unsigned char *) buf, count, 1, 1); + __sclp_vt220_write((const unsigned char *) buf, count, 1, 1, 0); } static struct tty_driver * diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5b47e9cce75..874adf365e4 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -394,7 +394,7 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, return tape_34xx_erp_failed(request, -ENOSPC); default: PRINT_ERR("Invalid op in %s:%i\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); return tape_34xx_erp_failed(request, 0); } } diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index b830a8cbef7..ebe84067bae 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -83,9 +83,9 @@ tapechar_setup_device(struct tape_device * device) void tapechar_cleanup_device(struct tape_device *device) { - unregister_tape_dev(device->rt); + unregister_tape_dev(&device->cdev->dev, device->rt); device->rt = NULL; - unregister_tape_dev(device->nt); + unregister_tape_dev(&device->cdev->dev, device->nt); device->nt = NULL; } diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index aa7f166f403..6dfdb7c1798 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -99,11 +99,10 @@ fail_with_tcd: } EXPORT_SYMBOL(register_tape_dev); -void unregister_tape_dev(struct tape_class_device *tcd) +void unregister_tape_dev(struct device *device, struct tape_class_device *tcd) { if (tcd != NULL && !IS_ERR(tcd)) { - sysfs_remove_link(&tcd->class_device->kobj, - tcd->mode_name); + sysfs_remove_link(&device->kobj, tcd->mode_name); device_destroy(tape_class, tcd->char_device->dev); cdev_del(tcd->char_device); kfree(tcd); diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h index e2b5ac918ac..707b7f48c23 100644 --- a/drivers/s390/char/tape_class.h +++ b/drivers/s390/char/tape_class.h @@ -56,6 +56,6 @@ struct tape_class_device *register_tape_dev( char * device_name, char * node_name ); -void unregister_tape_dev(struct tape_class_device *tcd); +void unregister_tape_dev(struct device *device, struct tape_class_device *tcd); #endif /* __TAPE_CLASS_H__ */ diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 7689b500a10..83ae9a852f0 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -100,7 +100,8 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev) urd->reclen = cdev->id.driver_info; ccw_device_get_id(cdev, &urd->dev_id); mutex_init(&urd->io_mutex); - mutex_init(&urd->open_mutex); + init_waitqueue_head(&urd->wait); + spin_lock_init(&urd->open_lock); atomic_set(&urd->ref_count, 1); urd->cdev = cdev; get_device(&cdev->dev); @@ -678,17 +679,21 @@ static int ur_open(struct inode *inode, struct file *file) if (!urd) return -ENXIO; - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&urd->open_mutex)) { + spin_lock(&urd->open_lock); + while (urd->open_flag) { + spin_unlock(&urd->open_lock); + if (file->f_flags & O_NONBLOCK) { rc = -EBUSY; goto fail_put; } - } else { - if (mutex_lock_interruptible(&urd->open_mutex)) { + if (wait_event_interruptible(urd->wait, urd->open_flag == 0)) { rc = -ERESTARTSYS; goto fail_put; } + spin_lock(&urd->open_lock); } + urd->open_flag++; + spin_unlock(&urd->open_lock); TRACE("ur_open\n"); @@ -720,7 +725,9 @@ static int ur_open(struct inode *inode, struct file *file) fail_urfile_free: urfile_free(urf); fail_unlock: - mutex_unlock(&urd->open_mutex); + spin_lock(&urd->open_lock); + urd->open_flag--; + spin_unlock(&urd->open_lock); fail_put: urdev_put(urd); return rc; @@ -731,7 +738,10 @@ static int ur_release(struct inode *inode, struct file *file) struct urfile *urf = file->private_data; TRACE("ur_release\n"); - mutex_unlock(&urf->urd->open_mutex); + spin_lock(&urf->urd->open_lock); + urf->urd->open_flag--; + spin_unlock(&urf->urd->open_lock); + wake_up_interruptible(&urf->urd->wait); urdev_put(urf->urd); urfile_free(urf); return 0; diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h index fa959644735..fa320ad4593 100644 --- a/drivers/s390/char/vmur.h +++ b/drivers/s390/char/vmur.h @@ -62,7 +62,6 @@ struct file_control_block { struct urdev { struct ccw_device *cdev; /* Backpointer to ccw device */ struct mutex io_mutex; /* Serialises device IO */ - struct mutex open_mutex; /* Serialises access to device */ struct completion *io_done; /* do_ur_io waits; irq completes */ struct device *device; struct cdev *char_device; @@ -71,6 +70,9 @@ struct urdev { int class; /* VM device class */ int io_request_rc; /* return code from I/O request */ atomic_t ref_count; /* reference counter */ + wait_queue_head_t wait; /* wait queue to serialize open */ + int open_flag; /* "urdev is open" flag */ + spinlock_t open_lock; /* serialize critical sections */ }; /* diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 6f40facb1c4..19f8389291b 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -96,7 +96,7 @@ static int vmwdt_keepalive(void) if (ret) { printk(KERN_WARNING "%s: problem setting interval %d, " - "cmd %s\n", __FUNCTION__, vmwdt_interval, + "cmd %s\n", __func__, vmwdt_interval, vmwdt_cmd); } return ret; @@ -107,7 +107,7 @@ static int vmwdt_disable(void) int ret = __diag288(wdt_cancel, 0, "", 0); if (ret) { printk(KERN_WARNING "%s: problem disabling watchdog\n", - __FUNCTION__); + __func__); } return ret; } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index f523501e6e6..bbbd14e9d48 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -224,7 +224,7 @@ static int __init init_cpu_info(enum arch_id arch) sa = kmalloc(sizeof(*sa), GFP_KERNEL); if (!sa) { - ERROR_MSG("kmalloc failed: %s: %i\n",__FUNCTION__, __LINE__); + ERROR_MSG("kmalloc failed: %s: %i\n",__func__, __LINE__); return -ENOMEM; } if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 007aaeb4f53..5de86908b0d 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -217,6 +217,8 @@ void chsc_chp_offline(struct chp_id chpid) if (chp_get_status(chpid) <= 0) return; + /* Wait until previous actions have settled. */ + css_wait_for_slow_path(); for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); } @@ -303,7 +305,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data) sprintf(dbf_txt, "fla%x", res_data->fla); CIO_TRACE_EVENT( 2, dbf_txt); } - + /* Wait until previous actions have settled. */ + css_wait_for_slow_path(); /* * I/O resources may have become accessible. * Scan through all subchannels that may be concerned and @@ -561,9 +564,12 @@ void chsc_chp_online(struct chp_id chpid) sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); - if (chp_get_status(chpid) != 0) + if (chp_get_status(chpid) != 0) { + /* Wait until previous actions have settled. */ + css_wait_for_slow_path(); for_each_subchannel_staged(__chp_add, __chp_add_new_sch, &chpid); + } } static void __s390_subchannel_vary_chpid(struct subchannel *sch, @@ -650,6 +656,8 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) */ int chsc_chp_vary(struct chp_id chpid, int on) { + /* Wait until previous actions have settled. */ + css_wait_for_slow_path(); /* * Redo PathVerification on the devices the chpid connects to */ @@ -758,7 +766,6 @@ chsc_secm(struct channel_subsystem *css, int enable) if (!secm_area) return -ENOMEM; - mutex_lock(&css->mutex); if (enable && !css->cm_enabled) { css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); @@ -766,7 +773,6 @@ chsc_secm(struct channel_subsystem *css, int enable) free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); free_page((unsigned long)secm_area); - mutex_unlock(&css->mutex); return -ENOMEM; } } @@ -787,7 +793,6 @@ chsc_secm(struct channel_subsystem *css, int enable) free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); } - mutex_unlock(&css->mutex); free_page((unsigned long)secm_area); return ret; } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 60590a12d52..23ffcc4768a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -24,6 +24,7 @@ #include <asm/ipl.h> #include <asm/chpid.h> #include <asm/airq.h> +#include <asm/cpu.h> #include "cio.h" #include "css.h" #include "chsc.h" @@ -649,13 +650,10 @@ do_IRQ (struct pt_regs *regs) old_regs = set_irq_regs(regs); irq_enter(); - asm volatile ("mc 0,0"); - if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) - /** - * Make sure that the i/o interrupt did not "overtake" - * the last HZ timer interrupt. - */ - account_ticks(S390_lowcore.int_clock); + s390_idle_check(); + if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) + /* Serve timer interrupts first. */ + clock_comparator_work(); /* * Get interrupt information from lowcore */ @@ -672,10 +670,14 @@ do_IRQ (struct pt_regs *regs) continue; } sch = (struct subchannel *)(unsigned long)tpi_info->intparm; - if (sch) - spin_lock(sch->lock); + if (!sch) { + /* Clear pending interrupt condition. */ + tsch(tpi_info->schid, irb); + continue; + } + spin_lock(sch->lock); /* Store interrupt response block to lowcore. */ - if (tsch (tpi_info->schid, irb) == 0 && sch) { + if (tsch(tpi_info->schid, irb) == 0) { /* Keep subchannel information word up to date. */ memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw)); @@ -683,8 +685,7 @@ do_IRQ (struct pt_regs *regs) if (sch->driver && sch->driver->irq) sch->driver->irq(sch); } - if (sch) - spin_unlock(sch->lock); + spin_unlock(sch->lock); /* * Are more interrupts pending? * If so, the tpi instruction will update the lowcore @@ -710,8 +711,9 @@ void *cio_get_console_priv(void) /* * busy wait for the next interrupt on the console */ -void -wait_cons_dev (void) +void wait_cons_dev(void) + __releases(console_subchannel.lock) + __acquires(console_subchannel.lock) { unsigned long cr6 __attribute__ ((aligned (8))); unsigned long save_cr6 __attribute__ ((aligned (8))); diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 52afa4c784d..08f2235c5a6 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -100,6 +100,7 @@ extern int cio_modify (struct subchannel *); int cio_create_sch_lock(struct subchannel *); void do_adapter_IO(void); +void do_IRQ(struct pt_regs *); /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 3b45bbe6cce..c1afab5f72d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -533,6 +533,12 @@ void css_schedule_eval_all(void) spin_unlock_irqrestore(&slow_subchannel_lock, flags); } +void css_wait_for_slow_path(void) +{ + flush_workqueue(ccw_device_notify_work); + flush_workqueue(slow_path_wq); +} + /* Reprobe subchannel if unregistered. */ static int reprobe_subchannel(struct subchannel_id schid, void *data) { @@ -683,10 +689,14 @@ css_cm_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_subsystem *css = to_css(dev); + int ret; if (!css) return 0; - return sprintf(buf, "%x\n", css->cm_enabled); + mutex_lock(&css->mutex); + ret = sprintf(buf, "%x\n", css->cm_enabled); + mutex_unlock(&css->mutex); + return ret; } static ssize_t @@ -696,6 +706,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, struct channel_subsystem *css = to_css(dev); int ret; + mutex_lock(&css->mutex); switch (buf[0]) { case '0': ret = css->cm_enabled ? chsc_secm(css, 0) : 0; @@ -706,6 +717,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, default: ret = -EINVAL; } + mutex_unlock(&css->mutex); return ret < 0 ? ret : count; } @@ -752,9 +764,11 @@ static int css_reboot_event(struct notifier_block *this, struct channel_subsystem *css; css = channel_subsystems[i]; + mutex_lock(&css->mutex); if (css->cm_enabled) if (chsc_secm(css, 0)) ret = NOTIFY_BAD; + mutex_unlock(&css->mutex); } return ret; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index b7055452355..e1913518f35 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -144,6 +144,7 @@ struct schib; int css_sch_is_valid(struct schib *); extern struct workqueue_struct *slow_path_wq; +void css_wait_for_slow_path(void); extern struct attribute_group *subch_attr_groups[]; #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index fec004f62bc..e0c7adb8958 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -577,7 +577,6 @@ static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); static DEVICE_ATTR(online, 0644, online_show, online_store); -extern struct device_attribute dev_attr_cmb_enable; static DEVICE_ATTR(availability, 0444, available_show, NULL); static struct attribute * subch_attrs[] = { diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index d40a2ffaa00..cb08092be39 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -127,4 +127,5 @@ extern struct bus_type ccw_bus_type; void retry_set_schib(struct ccw_device *cdev); void cmf_retry_copy_block(struct ccw_device *); int cmf_reenable(struct ccw_device *); +extern struct device_attribute dev_attr_cmb_enable; #endif diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 49b58eb0fab..a1718a0aa53 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -193,8 +193,15 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return -EACCES; } ret = cio_start_key (sch, cpa, lpm, key); - if (ret == 0) + switch (ret) { + case 0: cdev->private->intparm = intparm; + break; + case -EACCES: + case -ENODEV: + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + break; + } return ret; } diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index ebe0848cfe3..4a38993000f 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -62,7 +62,7 @@ ccw_device_path_notoper(struct ccw_device *cdev) stsch (sch->schid, &sch->schib); CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are " - "not operational \n", __FUNCTION__, + "not operational \n", __func__, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pnom); @@ -312,6 +312,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) { struct subchannel *sch; struct ccw1 *sense_ccw; + int rc; sch = to_subchannel(cdev->dev.parent); @@ -337,7 +338,10 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) /* Reset internal retry indication. */ cdev->private->flags.intretry = 0; - return cio_start(sch, sense_ccw, 0xff); + rc = cio_start(sch, sense_ccw, 0xff); + if (rc == -ENODEV || rc == -EACCES) + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + return rc; } /* diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 2b5bfb7c69e..c359386708e 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1399,7 +1399,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) * q->dev_st_chg_ind is the indicator, be it shared or not. * only clear it, if indicator is non-shared */ - if (!spare_ind_was_set) + if (q->dev_st_chg_ind != &spare_indicator) tiqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind); if (q->hydra_gives_outbound_pcis) { @@ -2217,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, return cc; } +static int +qdio_get_ssqd_information(struct subchannel_id *schid, + struct qdio_chsc_ssqd **ssqd_area) +{ + int result; + + QDIO_DBF_TEXT0(0, setup, "getssqd"); + *ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); + if (!ssqd_area) { + QDIO_PRINT_WARN("Could not get memory for chsc on sch x%x.\n", + schid->sch_no); + return -ENOMEM; + } + + (*ssqd_area)->request = (struct chsc_header) { + .length = 0x0010, + .code = 0x0024, + }; + (*ssqd_area)->first_sch = schid->sch_no; + (*ssqd_area)->last_sch = schid->sch_no; + (*ssqd_area)->ssid = schid->ssid; + result = chsc(*ssqd_area); + + if (result) { + QDIO_PRINT_WARN("CHSC returned cc %i on sch 0.%x.%x.\n", + result, schid->ssid, schid->sch_no); + goto out; + } + + if ((*ssqd_area)->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { + QDIO_PRINT_WARN("CHSC response is 0x%x on sch 0.%x.%x.\n", + (*ssqd_area)->response.code, + schid->ssid, schid->sch_no); + goto out; + } + if (!((*ssqd_area)->flags & CHSC_FLAG_QDIO_CAPABILITY) || + !((*ssqd_area)->flags & CHSC_FLAG_VALIDITY) || + ((*ssqd_area)->sch != schid->sch_no)) { + QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ + "using all SIGAs.\n", + schid->ssid, schid->sch_no); + goto out; + } + return 0; +out: + return -EINVAL; +} + +int +qdio_get_ssqd_pct(struct ccw_device *cdev) +{ + struct qdio_chsc_ssqd *ssqd_area; + struct subchannel_id schid; + char dbf_text[15]; + int rc; + int pct = 0; + + QDIO_DBF_TEXT0(0, setup, "getpct"); + schid = ccw_device_get_subchannel_id(cdev); + rc = qdio_get_ssqd_information(&schid, &ssqd_area); + if (!rc) + pct = (int)ssqd_area->pct; + if (rc != -ENOMEM) + mempool_free(ssqd_area, qdio_mempool_scssc); + sprintf(dbf_text, "pct: %d", pct); + QDIO_DBF_TEXT2(0, setup, dbf_text); + return pct; +} +EXPORT_SYMBOL(qdio_get_ssqd_pct); + static void -qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, - unsigned long token) +qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token) { struct qdio_q *q; int i; @@ -2227,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, char dbf_text[15]; /*check if QEBSM is disabled */ - if (!(irq_ptr->is_qebsm) || !(qdioac & 0x01)) { + if (!(irq_ptr->is_qebsm) || !(irq_ptr->qdioac & 0x01)) { irq_ptr->is_qebsm = 0; irq_ptr->sch_token = 0; irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; @@ -2256,102 +2325,27 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, } static void -qdio_get_ssqd_information(struct qdio_irq *irq_ptr) +qdio_get_ssqd_siga(struct qdio_irq *irq_ptr) { - int result; - unsigned char qdioac; - struct { - struct chsc_header request; - u16 reserved1:10; - u16 ssid:2; - u16 fmt:4; - u16 first_sch; - u16 reserved2; - u16 last_sch; - u32 reserved3; - struct chsc_header response; - u32 reserved4; - u8 flags; - u8 reserved5; - u16 sch; - u8 qfmt; - u8 parm; - u8 qdioac1; - u8 sch_class; - u8 reserved7; - u8 icnt; - u8 reserved8; - u8 ocnt; - u8 reserved9; - u8 mbccnt; - u16 qdioac2; - u64 sch_token; - } *ssqd_area; + int rc; + struct qdio_chsc_ssqd *ssqd_area; QDIO_DBF_TEXT0(0,setup,"getssqd"); - qdioac = 0; - ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); - if (!ssqd_area) { - QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ - "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); + irq_ptr->qdioac = 0; + rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area); + if (rc) { + QDIO_PRINT_WARN("using all SIGAs for sch x%x.n", + irq_ptr->schid.sch_no); irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ irq_ptr->is_qebsm = 0; - irq_ptr->sch_token = 0; - irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; - return; - } - - ssqd_area->request = (struct chsc_header) { - .length = 0x0010, - .code = 0x0024, - }; - ssqd_area->first_sch = irq_ptr->schid.sch_no; - ssqd_area->last_sch = irq_ptr->schid.sch_no; - ssqd_area->ssid = irq_ptr->schid.ssid; - result = chsc(ssqd_area); - - if (result) { - QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ - "SIGAs for sch 0.%x.%x.\n", result, - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ - irq_ptr->is_qebsm = 0; - goto out; - } + } else + irq_ptr->qdioac = ssqd_area->qdioac1; - if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { - QDIO_PRINT_WARN("response upon checking SIGA needs " \ - "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n", - ssqd_area->response.code, - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ - irq_ptr->is_qebsm = 0; - goto out; - } - if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) || - !(ssqd_area->flags & CHSC_FLAG_VALIDITY) || - (ssqd_area->sch != irq_ptr->schid.sch_no)) { - QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ - "using all SIGAs.\n", - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ - irq_ptr->is_qebsm = 0; - goto out; - } - qdioac = ssqd_area->qdioac1; -out: - qdio_check_subchannel_qebsm(irq_ptr, qdioac, - ssqd_area->sch_token); - mempool_free(ssqd_area, qdio_mempool_scssc); - irq_ptr->qdioac = qdioac; + qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token); + if (rc != -ENOMEM) + mempool_free(ssqd_area, qdio_mempool_scssc); } static unsigned int @@ -3227,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data) return -EIO; } - qdio_get_ssqd_information(irq_ptr); + qdio_get_ssqd_siga(irq_ptr); /* if this gets set once, we're running under VM and can omit SVSes */ if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY) omit_svs=1; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index da8a272fd75..c3df6b2c38b 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -406,6 +406,34 @@ do_clear_global_summary(void) #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 +struct qdio_chsc_ssqd { + struct chsc_header request; + u16 reserved1:10; + u16 ssid:2; + u16 fmt:4; + u16 first_sch; + u16 reserved2; + u16 last_sch; + u32 reserved3; + struct chsc_header response; + u32 reserved4; + u8 flags; + u8 reserved5; + u16 sch; + u8 qfmt; + u8 parm; + u8 qdioac1; + u8 sch_class; + u8 pct; + u8 icnt; + u8 reserved7; + u8 ocnt; + u8 reserved8; + u8 mbccnt; + u16 qdioac2; + u64 sch_token; +}; + struct qdio_perf_stats { #ifdef CONFIG_64BIT atomic64_t tl_runs; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 7b0b8190129..a1ab3e3efd1 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -45,7 +45,7 @@ static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); -/** +/* * Module description. */ MODULE_AUTHOR("IBM Corporation"); @@ -53,7 +53,7 @@ MODULE_DESCRIPTION("Adjunct Processor Bus driver, " "Copyright 2006 IBM Corporation"); MODULE_LICENSE("GPL"); -/** +/* * Module parameter */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ @@ -69,7 +69,7 @@ static struct device *ap_root_device = NULL; static DEFINE_SPINLOCK(ap_device_lock); static LIST_HEAD(ap_device_list); -/** +/* * Workqueue & timer for bus rescan. */ static struct workqueue_struct *ap_work_queue; @@ -77,7 +77,7 @@ static struct timer_list ap_config_timer; static int ap_config_time = AP_CONFIG_TIME; static DECLARE_WORK(ap_config_work, ap_scan_bus); -/** +/* * Tasklet & timer for AP request polling. */ static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0); @@ -88,9 +88,9 @@ static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); /** - * Test if ap instructions are available. + * ap_intructions_available() - Test if AP instructions are available. * - * Returns 0 if the ap instructions are installed. + * Returns 0 if the AP instructions are installed. */ static inline int ap_instructions_available(void) { @@ -108,12 +108,12 @@ static inline int ap_instructions_available(void) } /** - * Test adjunct processor queue. - * @qid: the ap queue number - * @queue_depth: pointer to queue depth value - * @device_type: pointer to device type value + * ap_test_queue(): Test adjunct processor queue. + * @qid: The AP queue number + * @queue_depth: Pointer to queue depth value + * @device_type: Pointer to device type value * - * Returns ap queue status structure. + * Returns AP queue status structure. */ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type) @@ -130,10 +130,10 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type) } /** - * Reset adjunct processor queue. - * @qid: the ap queue number + * ap_reset_queue(): Reset adjunct processor queue. + * @qid: The AP queue number * - * Returns ap queue status structure. + * Returns AP queue status structure. */ static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) { @@ -148,16 +148,14 @@ static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) } /** - * Send message to adjunct processor queue. - * @qid: the ap queue number - * @psmid: the program supplied message identifier - * @msg: the message text - * @length: the message length - * - * Returns ap queue status structure. + * __ap_send(): Send message to adjunct processor queue. + * @qid: The AP queue number + * @psmid: The program supplied message identifier + * @msg: The message text + * @length: The message length * + * Returns AP queue status structure. * Condition code 1 on NQAP can't happen because the L bit is 1. - * * Condition code 2 on NQAP also means the send is incomplete, * because a segment boundary was reached. The NQAP is repeated. */ @@ -198,23 +196,20 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) } EXPORT_SYMBOL(ap_send); -/* - * Receive message from adjunct processor queue. - * @qid: the ap queue number - * @psmid: pointer to program supplied message identifier - * @msg: the message text - * @length: the message length - * - * Returns ap queue status structure. +/** + * __ap_recv(): Receive message from adjunct processor queue. + * @qid: The AP queue number + * @psmid: Pointer to program supplied message identifier + * @msg: The message text + * @length: The message length * + * Returns AP queue status structure. * Condition code 1 on DQAP means the receive has taken place * but only partially. The response is incomplete, hence the * DQAP is repeated. - * * Condition code 2 on DQAP also means the receive is incomplete, * this time because a segment boundary was reached. Again, the * DQAP is repeated. - * * Note that gpr2 is used by the DQAP instruction to keep track of * any 'residual' length, in case the instruction gets interrupted. * Hence it gets zeroed before the instruction. @@ -263,11 +258,12 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) EXPORT_SYMBOL(ap_recv); /** - * Check if an AP queue is available. The test is repeated for - * AP_MAX_RESET times. - * @qid: the ap queue number - * @queue_depth: pointer to queue depth value - * @device_type: pointer to device type value + * ap_query_queue(): Check if an AP queue is available. + * @qid: The AP queue number + * @queue_depth: Pointer to queue depth value + * @device_type: Pointer to device type value + * + * The test is repeated for AP_MAX_RESET times. */ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type) { @@ -308,8 +304,10 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type) } /** + * ap_init_queue(): Reset an AP queue. + * @qid: The AP queue number + * * Reset an AP queue and wait for it to become available again. - * @qid: the ap queue number */ static int ap_init_queue(ap_qid_t qid) { @@ -346,7 +344,10 @@ static int ap_init_queue(ap_qid_t qid) } /** - * Arm request timeout if a AP device was idle and a new request is submitted. + * ap_increase_queue_count(): Arm request timeout. + * @ap_dev: Pointer to an AP device. + * + * Arm request timeout if an AP device was idle and a new request is submitted. */ static void ap_increase_queue_count(struct ap_device *ap_dev) { @@ -360,7 +361,10 @@ static void ap_increase_queue_count(struct ap_device *ap_dev) } /** - * AP device is still alive, re-schedule request timeout if there are still + * ap_decrease_queue_count(): Decrease queue count. + * @ap_dev: Pointer to an AP device. + * + * If AP device is still alive, re-schedule request timeout if there are still * pending requests. */ static void ap_decrease_queue_count(struct ap_device *ap_dev) @@ -371,7 +375,7 @@ static void ap_decrease_queue_count(struct ap_device *ap_dev) if (ap_dev->queue_count > 0) mod_timer(&ap_dev->timeout, jiffies + timeout); else - /** + /* * The timeout timer should to be disabled now - since * del_timer_sync() is very expensive, we just tell via the * reset flag to ignore the pending timeout timer. @@ -379,7 +383,7 @@ static void ap_decrease_queue_count(struct ap_device *ap_dev) ap_dev->reset = AP_RESET_IGNORE; } -/** +/* * AP device related attributes. */ static ssize_t ap_hwtype_show(struct device *dev, @@ -433,6 +437,10 @@ static struct attribute_group ap_dev_attr_group = { }; /** + * ap_bus_match() + * @dev: Pointer to device + * @drv: Pointer to device_driver + * * AP bus driver registration/unregistration. */ static int ap_bus_match(struct device *dev, struct device_driver *drv) @@ -441,7 +449,7 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) struct ap_driver *ap_drv = to_ap_drv(drv); struct ap_device_id *id; - /** + /* * Compare device type of the device with the list of * supported types of the device_driver. */ @@ -455,8 +463,12 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) } /** - * uevent function for AP devices. It sets up a single environment - * variable DEV_TYPE which contains the hardware device type. + * ap_uevent(): Uevent function for AP devices. + * @dev: Pointer to device + * @env: Pointer to kobj_uevent_env + * + * It sets up a single environment variable DEV_TYPE which contains the + * hardware device type. */ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { @@ -500,8 +512,10 @@ static int ap_device_probe(struct device *dev) } /** + * __ap_flush_queue(): Flush requests. + * @ap_dev: Pointer to the AP device + * * Flush all requests from the request/pending queue of an AP device. - * @ap_dev: pointer to the AP device. */ static void __ap_flush_queue(struct ap_device *ap_dev) { @@ -565,7 +579,7 @@ void ap_driver_unregister(struct ap_driver *ap_drv) } EXPORT_SYMBOL(ap_driver_unregister); -/** +/* * AP bus attributes. */ static ssize_t ap_domain_show(struct bus_type *bus, char *buf) @@ -630,14 +644,16 @@ static struct bus_attribute *const ap_bus_attrs[] = { }; /** - * Pick one of the 16 ap domains. + * ap_select_domain(): Select an AP domain. + * + * Pick one of the 16 AP domains. */ static int ap_select_domain(void) { int queue_depth, device_type, count, max_count, best_domain; int rc, i, j; - /** + /* * We want to use a single domain. Either the one specified with * the "domain=" parameter or the domain with the maximum number * of devices. @@ -669,8 +685,10 @@ static int ap_select_domain(void) } /** - * Find the device type if query queue returned a device type of 0. + * ap_probe_device_type(): Find the device type of an AP. * @ap_dev: pointer to the AP device. + * + * Find the device type if query queue returned a device type of 0. */ static int ap_probe_device_type(struct ap_device *ap_dev) { @@ -764,7 +782,11 @@ out: } /** - * Scan the ap bus for new devices. + * __ap_scan_bus(): Scan the AP bus. + * @dev: Pointer to device + * @data: Pointer to data + * + * Scan the AP bus for new devices. */ static int __ap_scan_bus(struct device *dev, void *data) { @@ -867,6 +889,8 @@ ap_config_timeout(unsigned long ptr) } /** + * ap_schedule_poll_timer(): Schedule poll timer. + * * Set up the timer to run the poll tasklet */ static inline void ap_schedule_poll_timer(void) @@ -877,10 +901,11 @@ static inline void ap_schedule_poll_timer(void) } /** - * Receive pending reply messages from an AP device. + * ap_poll_read(): Receive pending reply messages from an AP device. * @ap_dev: pointer to the AP device * @flags: pointer to control flags, bit 2^0 is set if another poll is * required, bit 2^1 is set if the poll timer needs to get armed + * * Returns 0 if the device is still present, -ENODEV if not. */ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) @@ -925,10 +950,11 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) } /** - * Send messages from the request queue to an AP device. + * ap_poll_write(): Send messages from the request queue to an AP device. * @ap_dev: pointer to the AP device * @flags: pointer to control flags, bit 2^0 is set if another poll is * required, bit 2^1 is set if the poll timer needs to get armed + * * Returns 0 if the device is still present, -ENODEV if not. */ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) @@ -968,11 +994,13 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) } /** - * Poll AP device for pending replies and send new messages. If either - * ap_poll_read or ap_poll_write returns -ENODEV unregister the device. + * ap_poll_queue(): Poll AP device for pending replies and send new messages. * @ap_dev: pointer to the bus device * @flags: pointer to control flags, bit 2^0 is set if another poll is * required, bit 2^1 is set if the poll timer needs to get armed + * + * Poll AP device for pending replies and send new messages. If either + * ap_poll_read or ap_poll_write returns -ENODEV unregister the device. * Returns 0. */ static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags) @@ -986,9 +1014,11 @@ static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags) } /** - * Queue a message to a device. + * __ap_queue_message(): Queue a message to a device. * @ap_dev: pointer to the AP device * @ap_msg: the message to be queued + * + * Queue a message to a device. Returns 0 if successful. */ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) { @@ -1055,12 +1085,14 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) EXPORT_SYMBOL(ap_queue_message); /** + * ap_cancel_message(): Cancel a crypto request. + * @ap_dev: The AP device that has the message queued + * @ap_msg: The message that is to be removed + * * Cancel a crypto request. This is done by removing the request - * from the devive pendingq or requestq queue. Note that the + * from the device pending or request queue. Note that the * request stays on the AP queue. When it finishes the message * reply will be discarded because the psmid can't be found. - * @ap_dev: AP device that has the message queued - * @ap_msg: the message that is to be removed */ void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg) { @@ -1082,7 +1114,10 @@ void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg) EXPORT_SYMBOL(ap_cancel_message); /** - * AP receive polling for finished AP requests + * ap_poll_timeout(): AP receive polling for finished AP requests. + * @unused: Unused variable. + * + * Schedules the AP tasklet. */ static void ap_poll_timeout(unsigned long unused) { @@ -1090,6 +1125,9 @@ static void ap_poll_timeout(unsigned long unused) } /** + * ap_reset(): Reset a not responding AP device. + * @ap_dev: Pointer to the AP device + * * Reset a not responding AP device and move all requests from the * pending queue to the request queue. */ @@ -1108,11 +1146,6 @@ static void ap_reset(struct ap_device *ap_dev) ap_dev->unregistered = 1; } -/** - * Poll all AP devices on the bus in a round robin fashion. Continue - * polling until bit 2^0 of the control flags is not set. If bit 2^1 - * of the control flags has been set arm the poll timer. - */ static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags) { spin_lock(&ap_dev->lock); @@ -1126,6 +1159,14 @@ static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags) return 0; } +/** + * ap_poll_all(): Poll all AP devices. + * @dummy: Unused variable + * + * Poll all AP devices on the bus in a round robin fashion. Continue + * polling until bit 2^0 of the control flags is not set. If bit 2^1 + * of the control flags has been set arm the poll timer. + */ static void ap_poll_all(unsigned long dummy) { unsigned long flags; @@ -1144,6 +1185,9 @@ static void ap_poll_all(unsigned long dummy) } /** + * ap_poll_thread(): Thread that polls for finished requests. + * @data: Unused pointer + * * AP bus poll thread. The purpose of this thread is to poll for * finished requests in a loop if there is a "free" cpu - that is * a cpu that doesn't have anything better to do. The polling stops @@ -1213,7 +1257,10 @@ static void ap_poll_thread_stop(void) } /** - * Handling of request timeouts + * ap_request_timeout(): Handling of request timeouts + * @data: Holds the AP device. + * + * Handles request timeouts. */ static void ap_request_timeout(unsigned long data) { @@ -1246,7 +1293,9 @@ static struct reset_call ap_reset_call = { }; /** - * The module initialization code. + * ap_module_init(): The module initialization code. + * + * Initializes the module. */ int __init ap_module_init(void) { @@ -1288,7 +1337,7 @@ int __init ap_module_init(void) if (ap_select_domain() == 0) ap_scan_bus(NULL); - /* Setup the ap bus rescan timer. */ + /* Setup the AP bus rescan timer. */ init_timer(&ap_config_timer); ap_config_timer.function = ap_config_timeout; ap_config_timer.data = 0; @@ -1325,7 +1374,9 @@ static int __ap_match_all(struct device *dev, void *data) } /** - * The module termination code + * ap_modules_exit(): The module termination code + * + * Terminates the module. */ void ap_module_exit(void) { diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 87c2d644287..c1e1200c43f 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -50,6 +50,15 @@ typedef unsigned int ap_qid_t; #define AP_QID_QUEUE(_qid) ((_qid) & 15) /** + * structy ap_queue_status - Holds the AP queue status. + * @queue_empty: Shows if queue is empty + * @replies_waiting: Waiting replies + * @queue_full: Is 1 if the queue is full + * @pad: A 4 bit pad + * @int_enabled: Shows if interrupts are enabled for the AP + * @response_conde: Holds the 8 bit response code + * @pad2: A 16 bit pad + * * The ap queue status word is returned by all three AP functions * (PQAP, NQAP and DQAP). There's a set of flags in the first * byte, followed by a 1 byte response code. @@ -75,7 +84,7 @@ struct ap_queue_status { #define AP_RESPONSE_NO_FIRST_PART 0x13 #define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 -/** +/* * Known device types */ #define AP_DEVICE_TYPE_PCICC 3 @@ -84,7 +93,7 @@ struct ap_queue_status { #define AP_DEVICE_TYPE_CEX2A 6 #define AP_DEVICE_TYPE_CEX2C 7 -/** +/* * AP reset flag states */ #define AP_RESET_IGNORE 0 /* request timeout will be ignored */ @@ -152,7 +161,7 @@ struct ap_message { .dev_type=(dt), \ .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, -/** +/* * Note: don't use ap_send/ap_recv after using ap_queue_message * for the first time. Otherwise the ap message queue will get * confused. diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index e3625a47a59..4d36e805a23 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -36,10 +36,11 @@ #include <linux/compat.h> #include <asm/atomic.h> #include <asm/uaccess.h> +#include <linux/hw_random.h> #include "zcrypt_api.h" -/** +/* * Module description. */ MODULE_AUTHOR("IBM Corporation"); @@ -52,7 +53,10 @@ static LIST_HEAD(zcrypt_device_list); static int zcrypt_device_count = 0; static atomic_t zcrypt_open_count = ATOMIC_INIT(0); -/** +static int zcrypt_rng_device_add(void); +static void zcrypt_rng_device_remove(void); + +/* * Device attributes common for all crypto devices. */ static ssize_t zcrypt_type_show(struct device *dev, @@ -99,6 +103,9 @@ static struct attribute_group zcrypt_device_attr_group = { }; /** + * __zcrypt_increase_preference(): Increase preference of a crypto device. + * @zdev: Pointer the crypto device + * * Move the device towards the head of the device list. * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. @@ -125,6 +132,9 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev) } /** + * __zcrypt_decrease_preference(): Decrease preference of a crypto device. + * @zdev: Pointer to a crypto device. + * * Move the device towards the tail of the device list. * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. @@ -198,7 +208,10 @@ void zcrypt_device_free(struct zcrypt_device *zdev) EXPORT_SYMBOL(zcrypt_device_free); /** - * Register a crypto device. + * zcrypt_device_register() - Register a crypto device. + * @zdev: Pointer to a crypto device + * + * Register a crypto device. Returns 0 if successful. */ int zcrypt_device_register(struct zcrypt_device *zdev) { @@ -216,16 +229,37 @@ int zcrypt_device_register(struct zcrypt_device *zdev) __zcrypt_increase_preference(zdev); zcrypt_device_count++; spin_unlock_bh(&zcrypt_device_lock); + if (zdev->ops->rng) { + rc = zcrypt_rng_device_add(); + if (rc) + goto out_unregister; + } + return 0; + +out_unregister: + spin_lock_bh(&zcrypt_device_lock); + zcrypt_device_count--; + list_del_init(&zdev->list); + spin_unlock_bh(&zcrypt_device_lock); + sysfs_remove_group(&zdev->ap_dev->device.kobj, + &zcrypt_device_attr_group); + put_device(&zdev->ap_dev->device); + zcrypt_device_put(zdev); out: return rc; } EXPORT_SYMBOL(zcrypt_device_register); /** + * zcrypt_device_unregister(): Unregister a crypto device. + * @zdev: Pointer to crypto device + * * Unregister a crypto device. */ void zcrypt_device_unregister(struct zcrypt_device *zdev) { + if (zdev->ops->rng) + zcrypt_rng_device_remove(); spin_lock_bh(&zcrypt_device_lock); zcrypt_device_count--; list_del_init(&zdev->list); @@ -238,7 +272,9 @@ void zcrypt_device_unregister(struct zcrypt_device *zdev) EXPORT_SYMBOL(zcrypt_device_unregister); /** - * zcrypt_read is not be supported beyond zcrypt 1.3.1 + * zcrypt_read (): Not supported beyond zcrypt 1.3.1. + * + * This function is not supported beyond zcrypt 1.3.1. */ static ssize_t zcrypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) @@ -247,6 +283,8 @@ static ssize_t zcrypt_read(struct file *filp, char __user *buf, } /** + * zcrypt_write(): Not allowed. + * * Write is is not allowed */ static ssize_t zcrypt_write(struct file *filp, const char __user *buf, @@ -256,7 +294,9 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf, } /** - * Device open/close functions to count number of users. + * zcrypt_open(): Count number of users. + * + * Device open function to count number of users. */ static int zcrypt_open(struct inode *inode, struct file *filp) { @@ -264,13 +304,18 @@ static int zcrypt_open(struct inode *inode, struct file *filp) return 0; } +/** + * zcrypt_release(): Count number of users. + * + * Device close function to count number of users. + */ static int zcrypt_release(struct inode *inode, struct file *filp) { atomic_dec(&zcrypt_open_count); return 0; } -/** +/* * zcrypt ioctls. */ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) @@ -280,7 +325,7 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) if (mex->outputdatalength < mex->inputdatalength) return -EINVAL; - /** + /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the * number of bytes we will copy in any case @@ -326,7 +371,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) if (crt->outputdatalength < crt->inputdatalength || (crt->inputdatalength & 1)) return -EINVAL; - /** + /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the * number of bytes we will copy in any case @@ -343,7 +388,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) zdev->max_mod_size < crt->inputdatalength) continue; if (zdev->short_crt && crt->inputdatalength > 240) { - /** + /* * Check inputdata for leading zeros for cards * that can't handle np_prime, bp_key, or * u_mult_inv > 128 bytes. @@ -359,7 +404,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) copy_from_user(&z3, crt->u_mult_inv, len)) return -EFAULT; copied = 1; - /** + /* * We have to restart device lookup - * the device list may have changed by now. */ @@ -427,6 +472,37 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) return -ENODEV; } +static long zcrypt_rng(char *buffer) +{ + struct zcrypt_device *zdev; + int rc; + + spin_lock_bh(&zcrypt_device_lock); + list_for_each_entry(zdev, &zcrypt_device_list, list) { + if (!zdev->online || !zdev->ops->rng) + continue; + zcrypt_device_get(zdev); + get_device(&zdev->ap_dev->device); + zdev->request_count++; + __zcrypt_decrease_preference(zdev); + if (try_module_get(zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = zdev->ops->rng(zdev, buffer); + spin_lock_bh(&zcrypt_device_lock); + module_put(zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + zdev->request_count--; + __zcrypt_increase_preference(zdev); + put_device(&zdev->ap_dev->device); + zcrypt_device_put(zdev); + spin_unlock_bh(&zcrypt_device_lock); + return rc; + } + spin_unlock_bh(&zcrypt_device_lock); + return -ENODEV; +} + static void zcrypt_status_mask(char status[AP_DEVICES]) { struct zcrypt_device *zdev; @@ -514,6 +590,8 @@ static int zcrypt_count_type(int type) } /** + * zcrypt_ica_status(): Old, depracted combi status call. + * * Old, deprecated combi status call. */ static long zcrypt_ica_status(struct file *filp, unsigned long arg) @@ -615,7 +693,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, (int __user *) arg); case Z90STAT_DOMAIN_INDEX: return put_user(ap_domain_index, (int __user *) arg); - /** + /* * Deprecated ioctls. Don't add another device count ioctl, * you can count them yourself in the user space with the * output of the Z90STAT_STATUS_MASK ioctl. @@ -653,7 +731,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, } #ifdef CONFIG_COMPAT -/** +/* * ioctl32 conversion routines */ struct compat_ica_rsa_modexpo { @@ -804,7 +882,7 @@ static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, } #endif -/** +/* * Misc device file operations. */ static const struct file_operations zcrypt_fops = { @@ -819,7 +897,7 @@ static const struct file_operations zcrypt_fops = { .release = zcrypt_release }; -/** +/* * Misc device. */ static struct miscdevice zcrypt_misc_device = { @@ -828,7 +906,7 @@ static struct miscdevice zcrypt_misc_device = { .fops = &zcrypt_fops, }; -/** +/* * Deprecated /proc entry support. */ static struct proc_dir_entry *zcrypt_entry; @@ -1022,7 +1100,7 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer, } for (j = 0; j < 64 && *ptr; ptr++) { - /** + /* * '0' for no device, '1' for PCICA, '2' for PCICC, * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3, * '5' for CEX2C and '6' for CEX2A' @@ -1041,7 +1119,76 @@ out: return count; } +static int zcrypt_rng_device_count; +static u32 *zcrypt_rng_buffer; +static int zcrypt_rng_buffer_index; +static DEFINE_MUTEX(zcrypt_rng_mutex); + +static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) +{ + int rc; + + /* + * We don't need locking here because the RNG API guarantees serialized + * read method calls. + */ + if (zcrypt_rng_buffer_index == 0) { + rc = zcrypt_rng((char *) zcrypt_rng_buffer); + if (rc < 0) + return -EIO; + zcrypt_rng_buffer_index = rc / sizeof *data; + } + *data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index]; + return sizeof *data; +} + +static struct hwrng zcrypt_rng_dev = { + .name = "zcrypt", + .data_read = zcrypt_rng_data_read, +}; + +static int zcrypt_rng_device_add(void) +{ + int rc = 0; + + mutex_lock(&zcrypt_rng_mutex); + if (zcrypt_rng_device_count == 0) { + zcrypt_rng_buffer = (u32 *) get_zeroed_page(GFP_KERNEL); + if (!zcrypt_rng_buffer) { + rc = -ENOMEM; + goto out; + } + zcrypt_rng_buffer_index = 0; + rc = hwrng_register(&zcrypt_rng_dev); + if (rc) + goto out_free; + zcrypt_rng_device_count = 1; + } else + zcrypt_rng_device_count++; + mutex_unlock(&zcrypt_rng_mutex); + return 0; + +out_free: + free_page((unsigned long) zcrypt_rng_buffer); +out: + mutex_unlock(&zcrypt_rng_mutex); + return rc; +} + +static void zcrypt_rng_device_remove(void) +{ + mutex_lock(&zcrypt_rng_mutex); + zcrypt_rng_device_count--; + if (zcrypt_rng_device_count == 0) { + hwrng_unregister(&zcrypt_rng_dev); + free_page((unsigned long) zcrypt_rng_buffer); + } + mutex_unlock(&zcrypt_rng_mutex); +} + /** + * zcrypt_api_init(): Module initialization. + * * The module initialization code. */ int __init zcrypt_api_init(void) @@ -1076,6 +1223,8 @@ out: } /** + * zcrypt_api_exit(): Module termination. + * * The module termination code. */ void zcrypt_api_exit(void) diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index de4877ee618..5c6e222b2ac 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -43,17 +43,17 @@ #define DEV_NAME "zcrypt" #define PRINTK(fmt, args...) \ - printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args) + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) #define PRINTKN(fmt, args...) \ printk(KERN_DEBUG DEV_NAME ": " fmt, ## args) #define PRINTKW(fmt, args...) \ - printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args) + printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __func__ , ## args) #define PRINTKC(fmt, args...) \ - printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args) + printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __func__ , ## args) #ifdef ZCRYPT_DEBUG #define PDEBUG(fmt, args...) \ - printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args) + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) #else #define PDEBUG(fmt, args...) do {} while (0) #endif @@ -100,6 +100,13 @@ struct ica_z90_status { #define ZCRYPT_CEX2C 5 #define ZCRYPT_CEX2A 6 +/** + * Large random numbers are pulled in 4096 byte chunks from the crypto cards + * and stored in a page. Be carefull when increasing this buffer due to size + * limitations for AP requests. + */ +#define ZCRYPT_RNG_BUFFER_SIZE 4096 + struct zcrypt_device; struct zcrypt_ops { @@ -107,6 +114,7 @@ struct zcrypt_ops { long (*rsa_modexpo_crt)(struct zcrypt_device *, struct ica_rsa_modexpo_crt *); long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); + long (*rng)(struct zcrypt_device *, char *); }; struct zcrypt_device { diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index 8dbcf0eef3e..ed82f2f59b1 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h @@ -174,7 +174,7 @@ static inline int zcrypt_type6_mex_key_de(struct ica_rsa_modexpo *mex, key->pvtMeHdr = static_pvt_me_hdr; key->pvtMeSec = static_pvt_me_sec; key->pubMeSec = static_pub_me_sec; - /** + /* * In a private key, the modulus doesn't appear in the public * section. So, an arbitrary public exponent of 0x010001 will be * used. @@ -338,7 +338,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, pub = (struct cca_public_sec *)(key->key_parts + key_len); *pub = static_cca_pub_sec; pub->modulus_bit_len = 8 * crt->inputdatalength; - /** + /* * In a private key, the modulus doesn't appear in the public * section. So, an arbitrary public exponent of 0x010001 will be * used. diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 2cb616ba8be..3e27fe77d20 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -108,7 +108,7 @@ static inline int convert_error(struct zcrypt_device *zdev, return -EINVAL; case REP82_ERROR_MESSAGE_TYPE: // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A - /** + /* * To sent a message of the wrong type is a bug in the * device driver. Warn about it, disable the device * and then repeat the request. diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index d6d59bf9ac3..17ea56ce1c1 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c @@ -42,7 +42,7 @@ #define PCICC_MAX_MOD_SIZE_OLD 128 /* 1024 bits */ #define PCICC_MAX_MOD_SIZE 256 /* 2048 bits */ -/** +/* * PCICC cards need a speed rating of 0. This keeps them at the end of * the zcrypt device list (see zcrypt_api.c). PCICC cards are only * used if no other cards are present because they are slow and can only @@ -388,7 +388,7 @@ static int convert_type86(struct zcrypt_device *zdev, reply_len = le16_to_cpu(msg->length) - 2; if (reply_len > outputdatalength) return -EINVAL; - /** + /* * For all encipher requests, the length of the ciphertext (reply_len) * will always equal the modulus length. For MEX decipher requests * the output needs to get padded. Minimum pad size is 10. diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 70b9ddc8cf9..0bc9b3188e6 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -356,6 +356,55 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, } /** + * Prepare a type6 CPRB message for random number generation + * + * @ap_dev: AP device pointer + * @ap_msg: pointer to AP message + */ +static void rng_type6CPRB_msgX(struct ap_device *ap_dev, + struct ap_message *ap_msg, + unsigned random_number_length) +{ + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __attribute__((packed)) *msg = ap_msg->message; + static struct type6_hdr static_type6_hdrX = { + .type = 0x06, + .offset1 = 0x00000058, + .agent_id = {'C', 'A'}, + .function_code = {'R', 'L'}, + .ToCardLen1 = sizeof *msg - sizeof(msg->hdr), + .FromCardLen1 = sizeof *msg - sizeof(msg->hdr), + }; + static struct CPRBX static_cprbx = { + .cprb_len = 0x00dc, + .cprb_ver_id = 0x02, + .func_id = {0x54, 0x32}, + .req_parml = sizeof *msg - sizeof(msg->hdr) - + sizeof(msg->cprbx), + .rpl_msgbl = sizeof *msg - sizeof(msg->hdr), + }; + + msg->hdr = static_type6_hdrX; + msg->hdr.FromCardLen2 = random_number_length, + msg->cprbx = static_cprbx; + msg->cprbx.rpl_datal = random_number_length, + msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); + memcpy(msg->function_code, msg->hdr.function_code, 0x02); + msg->rule_length = 0x0a; + memcpy(msg->rule, "RANDOM ", 8); + msg->verb_length = 0x02; + msg->key_length = 0x02; + ap_msg->length = sizeof *msg; +} + +/** * Copy results from a type 86 ICA reply message back to user space. * * @zdev: crypto device pointer @@ -452,7 +501,7 @@ static int convert_type86_ica(struct zcrypt_device *zdev, reply_len = msg->length - 2; if (reply_len > outputdatalength) return -EINVAL; - /** + /* * For all encipher requests, the length of the ciphertext (reply_len) * will always equal the modulus length. For MEX decipher requests * the output needs to get padded. Minimum pad size is 10. @@ -509,6 +558,26 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev, return 0; } +static int convert_type86_rng(struct zcrypt_device *zdev, + struct ap_message *reply, + char *buffer) +{ + struct { + struct type86_hdr hdr; + struct type86_fmt2_ext fmt2; + struct CPRBX cprbx; + } __attribute__((packed)) *msg = reply->message; + char *data = reply->message; + + if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) { + PDEBUG("RNG response error on PCIXCC/CEX2C rc=%hu/rs=%hu\n", + rc, rs); + return -EINVAL; + } + memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); + return msg->fmt2.count2; +} + static int convert_response_ica(struct zcrypt_device *zdev, struct ap_message *reply, char __user *outputdata, @@ -567,6 +636,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, } } +static int convert_response_rng(struct zcrypt_device *zdev, + struct ap_message *reply, + char *data) +{ + struct type86x_reply *msg = reply->message; + + switch (msg->hdr.type) { + case TYPE82_RSP_CODE: + case TYPE88_RSP_CODE: + return -EINVAL; + case TYPE86_RSP_CODE: + if (msg->hdr.reply_code) + return -EINVAL; + if (msg->cprbx.cprb_ver_id == 0x02) + return convert_type86_rng(zdev, reply, data); + /* no break, incorrect cprb version is an unknown response */ + default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); + zdev->online = 0; + return -EAGAIN; /* repeat the request on a different device. */ + } +} + /** * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". @@ -736,6 +830,42 @@ out_free: } /** + * The request distributor calls this function if it picked the PCIXCC/CEX2C + * device to generate random data. + * @zdev: pointer to zcrypt_device structure that identifies the + * PCIXCC/CEX2C device to the request distributor + * @buffer: pointer to a memory page to return random data + */ + +static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev, + char *buffer) +{ + struct ap_message ap_msg; + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + int rc; + + ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); + if (!ap_msg.message) + return -ENOMEM; + ap_msg.psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg.private = &resp_type; + rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + init_completion(&resp_type.work); + ap_queue_message(zdev->ap_dev, &ap_msg); + rc = wait_for_completion_interruptible(&resp_type.work); + if (rc == 0) + rc = convert_response_rng(zdev, &ap_msg, buffer); + else + /* Signal pending. */ + ap_cancel_message(zdev->ap_dev, &ap_msg); + kfree(ap_msg.message); + return rc; +} + +/** * The crypto operations for a PCIXCC/CEX2C card. */ static struct zcrypt_ops zcrypt_pcixcc_ops = { @@ -744,6 +874,13 @@ static struct zcrypt_ops zcrypt_pcixcc_ops = { .send_cprb = zcrypt_pcixcc_send_cprb, }; +static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = { + .rsa_modexpo = zcrypt_pcixcc_modexpo, + .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, + .send_cprb = zcrypt_pcixcc_send_cprb, + .rng = zcrypt_pcixcc_rng, +}; + /** * Micro-code detection function. Its sends a message to a pcixcc card * to find out the microcode level. @@ -859,6 +996,58 @@ out_free: } /** + * Large random number detection function. Its sends a message to a pcixcc + * card to find out if large random numbers are supported. + * @ap_dev: pointer to the AP device. + * + * Returns 1 if large random numbers are supported, 0 if not and < 0 on error. + */ +static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) +{ + struct ap_message ap_msg; + unsigned long long psmid; + struct { + struct type86_hdr hdr; + struct type86_fmt2_ext fmt2; + struct CPRBX cprbx; + } __attribute__((packed)) *reply; + int rc, i; + + ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); + if (!ap_msg.message) + return -ENOMEM; + + rng_type6CPRB_msgX(ap_dev, &ap_msg, 4); + rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, + ap_msg.length); + if (rc) + goto out_free; + + /* Wait for the test message to complete. */ + for (i = 0; i < 2 * HZ; i++) { + msleep(1000 / HZ); + rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096); + if (rc == 0 && psmid == 0x0102030405060708ULL) + break; + } + + if (i >= 2 * HZ) { + /* Got no answer. */ + rc = -ENODEV; + goto out_free; + } + + reply = ap_msg.message; + if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0) + rc = 1; + else + rc = 0; +out_free: + free_page((unsigned long) ap_msg.message); + return rc; +} + +/** * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device * since the bus_match already checked the hardware type. The PCIXCC * cards come in two flavours: micro code level 2 and micro code level 3. @@ -874,7 +1063,6 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) if (!zdev) return -ENOMEM; zdev->ap_dev = ap_dev; - zdev->ops = &zcrypt_pcixcc_ops; zdev->online = 1; if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) { rc = zcrypt_pcixcc_mcl(ap_dev); @@ -901,6 +1089,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; } + rc = zcrypt_pcixcc_rng_supported(ap_dev); + if (rc < 0) { + zcrypt_device_free(zdev); + return rc; + } + if (rc) + zdev->ops = &zcrypt_pcixcc_with_rng_ops; + else + zdev->ops = &zcrypt_pcixcc_ops; ap_dev->reply = &zdev->reply; ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index d8a5c229c5a..04a1d7bf678 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -299,7 +299,7 @@ claw_probe(struct ccwgroup_device *cgdev) struct claw_privbk *privptr=NULL; #ifdef FUNCTRACE - printk(KERN_INFO "%s Enter\n",__FUNCTION__); + printk(KERN_INFO "%s Enter\n",__func__); #endif CLAW_DBF_TEXT(2,setup,"probe"); if (!get_device(&cgdev->dev)) @@ -313,7 +313,7 @@ claw_probe(struct ccwgroup_device *cgdev) probe_error(cgdev); put_device(&cgdev->dev); printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n", - cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__); + cgdev->cdev[0]->dev.bus_id,__func__,__LINE__); CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); return -ENOMEM; } @@ -323,7 +323,7 @@ claw_probe(struct ccwgroup_device *cgdev) probe_error(cgdev); put_device(&cgdev->dev); printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n", - cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__); + cgdev->cdev[0]->dev.bus_id,__func__,__LINE__); CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); return -ENOMEM; } @@ -340,7 +340,7 @@ claw_probe(struct ccwgroup_device *cgdev) probe_error(cgdev); put_device(&cgdev->dev); printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n", - cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__); + cgdev->cdev[0]->dev.bus_id,__func__,__LINE__); CLAW_DBF_TEXT_(2,setup,"probex%d",rc); return rc; } @@ -351,7 +351,7 @@ claw_probe(struct ccwgroup_device *cgdev) cgdev->dev.driver_data = privptr; #ifdef FUNCTRACE printk(KERN_INFO "claw:%s exit on line %d, " - "rc = 0\n",__FUNCTION__,__LINE__); + "rc = 0\n",__func__,__LINE__); #endif CLAW_DBF_TEXT(2,setup,"prbext 0"); @@ -371,7 +371,7 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) struct chbk *p_ch; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"claw_tx"); p_ch=&privptr->channel[WRITE]; @@ -381,7 +381,7 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) privptr->stats.tx_dropped++; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() exit on line %d, rc = EIO\n", - dev->name,__FUNCTION__, __LINE__); + dev->name,__func__, __LINE__); #endif CLAW_DBF_TEXT_(2,trace,"clawtx%d",-EIO); return -EIO; @@ -398,7 +398,7 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s exit on line %d, rc = %d\n", - dev->name, __FUNCTION__, __LINE__, rc); + dev->name, __func__, __LINE__, rc); #endif CLAW_DBF_TEXT_(4,trace,"clawtx%d",rc); return rc; @@ -460,7 +460,7 @@ claw_pack_skb(struct claw_privbk *privptr) #ifdef IOTRACE printk(KERN_INFO "%s: %s() Packed %d len %d\n", p_env->ndev->name, - __FUNCTION__,pkt_cnt,new_skb->len); + __func__,pkt_cnt,new_skb->len); #endif } CLAW_DBF_TEXT(4,trace,"PackSKBx"); @@ -478,7 +478,7 @@ claw_change_mtu(struct net_device *dev, int new_mtu) struct claw_privbk *privptr=dev->priv; int buff_size; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif #ifdef DEBUGMSG printk(KERN_INFO "variable dev =\n"); @@ -491,14 +491,14 @@ claw_change_mtu(struct net_device *dev, int new_mtu) #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc=EINVAL\n", dev->name, - __FUNCTION__, __LINE__); + __func__, __LINE__); #endif return -EINVAL; } dev->mtu = new_mtu; #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n",dev->name, - __FUNCTION__, __LINE__); + __func__, __LINE__); #endif return 0; } /* end of claw_change_mtu */ @@ -522,7 +522,7 @@ claw_open(struct net_device *dev) struct ccwbk *p_buf; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"open"); if (!dev || (dev->name[0] == 0x00)) { @@ -537,7 +537,7 @@ claw_open(struct net_device *dev) if (rc) { printk(KERN_INFO "%s:%s Exit on line %d, rc=ENOMEM\n", dev->name, - __FUNCTION__, __LINE__); + __func__, __LINE__); CLAW_DBF_TEXT(2,trace,"openmem"); return -ENOMEM; } @@ -661,7 +661,7 @@ claw_open(struct net_device *dev) claw_clear_busy(dev); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc=EIO\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(2,trace,"open EIO"); return -EIO; @@ -673,7 +673,7 @@ claw_open(struct net_device *dev) #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc=0\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"openok"); return 0; @@ -696,7 +696,7 @@ claw_irq_handler(struct ccw_device *cdev, #ifdef FUNCTRACE - printk(KERN_INFO "%s enter \n",__FUNCTION__); + printk(KERN_INFO "%s enter \n",__func__); #endif CLAW_DBF_TEXT(4,trace,"clawirq"); /* Bypass all 'unsolicited interrupts' */ @@ -706,7 +706,7 @@ claw_irq_handler(struct ccw_device *cdev, cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat); #ifdef FUNCTRACE printk(KERN_INFO "claw: %s() " - "exit on line %d\n",__FUNCTION__,__LINE__); + "exit on line %d\n",__func__,__LINE__); #endif CLAW_DBF_TEXT(2,trace,"badirq"); return; @@ -752,7 +752,7 @@ claw_irq_handler(struct ccw_device *cdev, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(2,trace,"chanchk"); /* return; */ @@ -777,7 +777,7 @@ claw_irq_handler(struct ccw_device *cdev, (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; } @@ -788,7 +788,7 @@ claw_irq_handler(struct ccw_device *cdev, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"stop"); return; @@ -804,7 +804,7 @@ claw_irq_handler(struct ccw_device *cdev, (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"haltio"); return; @@ -838,7 +838,7 @@ claw_irq_handler(struct ccw_device *cdev, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"haltio"); return; @@ -858,7 +858,7 @@ claw_irq_handler(struct ccw_device *cdev, } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"notrdy"); return; @@ -874,7 +874,7 @@ claw_irq_handler(struct ccw_device *cdev, } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"PCI_read"); return; @@ -885,7 +885,7 @@ claw_irq_handler(struct ccw_device *cdev, (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"SPend_rd"); return; @@ -906,7 +906,7 @@ claw_irq_handler(struct ccw_device *cdev, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"RdIRQXit"); return; @@ -929,7 +929,7 @@ claw_irq_handler(struct ccw_device *cdev, } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"rstrtwrt"); return; @@ -946,7 +946,7 @@ claw_irq_handler(struct ccw_device *cdev, (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"writeUE"); return; @@ -969,7 +969,7 @@ claw_irq_handler(struct ccw_device *cdev, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"StWtExit"); return; @@ -978,7 +978,7 @@ claw_irq_handler(struct ccw_device *cdev, "state=%d\n",dev->name,p_ch->claw_state); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(2,trace,"badIRQ"); return; @@ -1001,7 +1001,7 @@ claw_irq_tasklet ( unsigned long data ) p_ch = (struct chbk *) data; dev = (struct net_device *)p_ch->ndev; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif #ifdef DEBUGMSG printk(KERN_INFO "%s: variable p_ch =\n",dev->name); @@ -1021,7 +1021,7 @@ claw_irq_tasklet ( unsigned long data ) CLAW_DBF_TEXT(4,trace,"TskletXt"); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; } /* end of claw_irq_bh */ @@ -1048,7 +1048,7 @@ claw_release(struct net_device *dev) if (!privptr) return 0; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"release"); #ifdef DEBUGMSG @@ -1090,7 +1090,7 @@ claw_release(struct net_device *dev) if(privptr->buffs_alloc != 1) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"none2fre"); return 0; @@ -1171,7 +1171,7 @@ claw_release(struct net_device *dev) } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"rlsexit"); return 0; @@ -1192,7 +1192,7 @@ claw_write_retry ( struct chbk *p_ch ) #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); printk(KERN_INFO "claw: variable p_ch =\n"); dumpit((char *) p_ch, sizeof(struct chbk)); #endif @@ -1200,20 +1200,20 @@ claw_write_retry ( struct chbk *p_ch ) if (p_ch->claw_state == CLAW_STOP) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; } #ifdef DEBUGMSG printk( KERN_INFO "%s:%s state-%02x\n" , dev->name, - __FUNCTION__, + __func__, p_ch->claw_state); #endif claw_strt_out_IO( dev ); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"rtry_xit"); return; @@ -1235,7 +1235,7 @@ claw_write_next ( struct chbk * p_ch ) int rc; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",p_ch->ndev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",p_ch->ndev->name,__func__); printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name); dumpit((char *) p_ch, sizeof(struct chbk)); #endif @@ -1262,7 +1262,7 @@ claw_write_next ( struct chbk * p_ch ) #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; } /* end of claw_write_next */ @@ -1276,7 +1276,7 @@ static void claw_timer ( struct chbk * p_ch ) { #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Entry\n",p_ch->ndev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Entry\n",p_ch->ndev->name,__func__); printk(KERN_INFO "%s: variable p_ch =\n",p_ch->ndev->name); dumpit((char *) p_ch, sizeof(struct chbk)); #endif @@ -1285,7 +1285,7 @@ claw_timer ( struct chbk * p_ch ) wake_up(&p_ch->wait); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - p_ch->ndev->name,__FUNCTION__,__LINE__); + p_ch->ndev->name,__func__,__LINE__); #endif return; } /* end of claw_timer */ @@ -1312,7 +1312,7 @@ pages_to_order_of_mag(int num_of_pages) int order_of_mag=1; /* assume 2 pages */ int nump=2; #ifdef FUNCTRACE - printk(KERN_INFO "%s Enter pages = %d \n",__FUNCTION__,num_of_pages); + printk(KERN_INFO "%s Enter pages = %d \n",__func__,num_of_pages); #endif CLAW_DBF_TEXT_(5,trace,"pages%d",num_of_pages); if (num_of_pages == 1) {return 0; } /* magnitude of 0 = 1 page */ @@ -1327,7 +1327,7 @@ pages_to_order_of_mag(int num_of_pages) if (order_of_mag > 9) { order_of_mag = 9; } /* I know it's paranoid */ #ifdef FUNCTRACE printk(KERN_INFO "%s Exit on line %d, order = %d\n", - __FUNCTION__,__LINE__, order_of_mag); + __func__,__LINE__, order_of_mag); #endif CLAW_DBF_TEXT_(5,trace,"mag%d",order_of_mag); return order_of_mag; @@ -1349,7 +1349,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, struct ccwbk* p_buf; #endif #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif #ifdef DEBUGMSG printk(KERN_INFO "dev\n"); @@ -1369,7 +1369,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, if ( p_first==NULL) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"addexit"); return 0; @@ -1400,9 +1400,9 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, if ( privptr-> p_read_active_first ==NULL ) { #ifdef DEBUGMSG printk(KERN_INFO "%s:%s p_read_active_first == NULL \n", - dev->name,__FUNCTION__); + dev->name,__func__); printk(KERN_INFO "%s:%s Read active first/last changed \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif privptr-> p_read_active_first= p_first; /* set new first */ privptr-> p_read_active_last = p_last; /* set new last */ @@ -1411,7 +1411,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, #ifdef DEBUGMSG printk(KERN_INFO "%s:%s Read in progress \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif /* set up TIC ccw */ temp_ccw.cda= (__u32)__pa(&p_first->read); @@ -1450,15 +1450,15 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, privptr->p_read_active_last=p_last; } /* end of if ( privptr-> p_read_active_first ==NULL) */ #ifdef IOTRACE - printk(KERN_INFO "%s:%s dump p_last CCW BK \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s dump p_last CCW BK \n",dev->name,__func__); dumpit((char *)p_last, sizeof(struct ccwbk)); - printk(KERN_INFO "%s:%s dump p_end CCW BK \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s dump p_end CCW BK \n",dev->name,__func__); dumpit((char *)p_end, sizeof(struct endccw)); - printk(KERN_INFO "%s:%s dump p_first CCW BK \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s dump p_first CCW BK \n",dev->name,__func__); dumpit((char *)p_first, sizeof(struct ccwbk)); printk(KERN_INFO "%s:%s Dump Active CCW chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); p_buf=privptr->p_read_active_first; while (p_buf!=NULL) { dumpit((char *)p_buf, sizeof(struct ccwbk)); @@ -1467,7 +1467,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, #endif #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"addexit"); return 0; @@ -1483,7 +1483,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) { #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > enter \n", - cdev->dev.bus_id,__FUNCTION__); + cdev->dev.bus_id,__func__); #endif CLAW_DBF_TEXT(4,trace,"ccwret"); #ifdef DEBUGMSG @@ -1516,7 +1516,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) } #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > exit on line %d\n", - cdev->dev.bus_id,__FUNCTION__,__LINE__); + cdev->dev.bus_id,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"ccwret"); } /* end of ccw_check_return_code */ @@ -1531,7 +1531,7 @@ ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) struct net_device *dev = p_ch->ndev; #ifdef FUNCTRACE - printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s: %s() > enter\n",dev->name,__func__); #endif #ifdef DEBUGMSG printk(KERN_INFO "%s: variable dev =\n",dev->name); @@ -1578,7 +1578,7 @@ ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif } /* end of ccw_check_unit_check */ @@ -1706,7 +1706,7 @@ find_link(struct net_device *dev, char *host_name, char *ws_name ) int rc=0; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s > enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s > enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"findlink"); #ifdef DEBUGMSG @@ -1739,7 +1739,7 @@ find_link(struct net_device *dev, char *host_name, char *ws_name ) #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return 0; } /* end of find_link */ @@ -1773,7 +1773,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) struct ccwbk *p_buf; #endif #ifdef FUNCTRACE - printk(KERN_INFO "%s: %s() > enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s: %s() > enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"hw_tx"); #ifdef DEBUGMSG @@ -1787,7 +1787,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) p_ch=(struct chbk *)&privptr->channel[WRITE]; p_env =privptr->p_env; #ifdef IOTRACE - printk(KERN_INFO "%s: %s() dump sk_buff \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s: %s() dump sk_buff \n",dev->name,__func__); dumpit((char *)skb ,sizeof(struct sk_buff)); #endif claw_free_wrt_buf(dev); /* Clean up free chain if posible */ @@ -1877,7 +1877,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) while (len_of_data > 0) { #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() length-of-data is %ld \n", - dev->name ,__FUNCTION__,len_of_data); + dev->name ,__func__,len_of_data); dumpit((char *)pDataAddress ,64); #endif p_this_ccw=privptr->p_write_free_chain; /* get a block */ @@ -1913,7 +1913,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) p_last_ccw=p_this_ccw; /* save new last block */ #ifdef IOTRACE printk(KERN_INFO "%s: %s() > CCW and Buffer %ld bytes long \n", - dev->name,__FUNCTION__,bytesInThisBuffer); + dev->name,__func__,bytesInThisBuffer); dumpit((char *)p_this_ccw, sizeof(struct ccwbk)); dumpit((char *)p_this_ccw->p_buffer, 64); #endif @@ -1998,7 +1998,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) #ifdef IOTRACE printk(KERN_INFO "%s: %s() > Dump Active CCW chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); p_buf=privptr->p_write_active_first; while (p_buf!=NULL) { dumpit((char *)p_buf, sizeof(struct ccwbk)); @@ -2018,7 +2018,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) /* if write free count is zero , set NOBUFFER */ #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() > free_count is %d\n", - dev->name,__FUNCTION__, + dev->name,__func__, (int) privptr->write_free_count ); #endif if (privptr->write_free_count==0) { @@ -2029,7 +2029,7 @@ Done2: Done: #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > exit on line %d, rc = %d \n", - dev->name,__FUNCTION__,__LINE__, rc); + dev->name,__func__,__LINE__, rc); #endif return(rc); } /* end of claw_hw_tx */ @@ -2063,7 +2063,7 @@ init_ccw_bk(struct net_device *dev) addr_t real_TIC_address; int i,j; #ifdef FUNCTRACE - printk(KERN_INFO "%s: %s() enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s: %s() enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"init_ccw"); #ifdef DEBUGMSG @@ -2097,15 +2097,15 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() " "ccw_blocks_required=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, ccw_blocks_required); printk(KERN_INFO "%s: %s() " "PAGE_SIZE=0x%x\n", - dev->name,__FUNCTION__, + dev->name,__func__, (unsigned int)PAGE_SIZE); printk(KERN_INFO "%s: %s() > " "PAGE_MASK=0x%x\n", - dev->name,__FUNCTION__, + dev->name,__func__, (unsigned int)PAGE_MASK); #endif /* @@ -2117,10 +2117,10 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() > ccw_blocks_perpage=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, ccw_blocks_perpage); printk(KERN_INFO "%s: %s() > ccw_pages_required=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, ccw_pages_required); #endif /* @@ -2156,29 +2156,29 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG if (privptr->p_env->read_size < PAGE_SIZE) { printk(KERN_INFO "%s: %s() reads_perpage=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, claw_reads_perpage); } else { printk(KERN_INFO "%s: %s() pages_perread=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, privptr->p_buff_pages_perread); } printk(KERN_INFO "%s: %s() read_pages=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, claw_read_pages); if (privptr->p_env->write_size < PAGE_SIZE) { printk(KERN_INFO "%s: %s() writes_perpage=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, claw_writes_perpage); } else { printk(KERN_INFO "%s: %s() pages_perwrite=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, privptr->p_buff_pages_perwrite); } printk(KERN_INFO "%s: %s() write_pages=%d\n", - dev->name,__FUNCTION__, + dev->name,__func__, claw_write_pages); #endif @@ -2194,12 +2194,12 @@ init_ccw_bk(struct net_device *dev) printk(KERN_INFO "%s: %s() " "__get_free_pages for CCWs failed : " "pages is %d\n", - dev->name,__FUNCTION__, + dev->name,__func__, ccw_pages_required ); #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > " "exit on line %d, rc = ENOMEM\n", - dev->name,__FUNCTION__, + dev->name,__func__, __LINE__); #endif return -ENOMEM; @@ -2218,7 +2218,7 @@ init_ccw_bk(struct net_device *dev) /* Initialize ending CCW block */ #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() begin initialize ending CCW blocks\n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif p_endccw=privptr->p_end_ccw; @@ -2276,7 +2276,7 @@ init_ccw_bk(struct net_device *dev) #ifdef IOTRACE printk(KERN_INFO "%s: %s() dump claw ending CCW BK \n", - dev->name,__FUNCTION__); + dev->name,__func__); dumpit((char *)p_endccw, sizeof(struct endccw)); #endif @@ -2287,7 +2287,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() Begin build a chain of CCW buffer \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif p_buff=privptr->p_buff_ccw; @@ -2306,7 +2306,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() " "End build a chain of CCW buffer \n", - dev->name,__FUNCTION__); + dev->name,__func__); p_buf=p_free_chain; while (p_buf!=NULL) { dumpit((char *)p_buf, sizeof(struct ccwbk)); @@ -2321,7 +2321,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() " "Begin initialize ClawSignalBlock \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif if (privptr->p_claw_signal_blk==NULL) { privptr->p_claw_signal_blk=p_free_chain; @@ -2334,7 +2334,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() > End initialize " "ClawSignalBlock\n", - dev->name,__FUNCTION__); + dev->name,__func__); dumpit((char *)privptr->p_claw_signal_blk, sizeof(struct ccwbk)); #endif @@ -2349,14 +2349,14 @@ init_ccw_bk(struct net_device *dev) if (privptr->p_buff_write==NULL) { printk(KERN_INFO "%s: %s() __get_free_pages for write" " bufs failed : get is for %d pages\n", - dev->name,__FUNCTION__,claw_write_pages ); + dev->name,__func__,claw_write_pages ); free_pages((unsigned long)privptr->p_buff_ccw, (int)pages_to_order_of_mag(privptr->p_buff_ccw_num)); privptr->p_buff_ccw=NULL; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > exit on line %d," "rc = ENOMEM\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return -ENOMEM; } @@ -2369,7 +2369,7 @@ init_ccw_bk(struct net_device *dev) ccw_pages_required * PAGE_SIZE); #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() Begin build claw write free " - "chain \n",dev->name,__FUNCTION__); + "chain \n",dev->name,__func__); #endif privptr->p_write_free_chain=NULL; @@ -2409,14 +2409,14 @@ init_ccw_bk(struct net_device *dev) #ifdef IOTRACE printk(KERN_INFO "%s:%s __get_free_pages " "for writes buf: get for %d pages\n", - dev->name,__FUNCTION__, + dev->name,__func__, privptr->p_buff_pages_perwrite); #endif if (p_buff==NULL) { printk(KERN_INFO "%s:%s __get_free_pages " "for writes buf failed : get is for %d pages\n", dev->name, - __FUNCTION__, + __func__, privptr->p_buff_pages_perwrite ); free_pages((unsigned long)privptr->p_buff_ccw, (int)pages_to_order_of_mag( @@ -2433,7 +2433,7 @@ init_ccw_bk(struct net_device *dev) #ifdef FUNCTRACE printk(KERN_INFO "%s: %s exit on line %d, rc = ENOMEM\n", dev->name, - __FUNCTION__, + __func__, __LINE__); #endif return -ENOMEM; @@ -2466,7 +2466,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s:%s End build claw write free chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); p_buf=privptr->p_write_free_chain; while (p_buf!=NULL) { dumpit((char *)p_buf, sizeof(struct ccwbk)); @@ -2485,7 +2485,7 @@ init_ccw_bk(struct net_device *dev) printk(KERN_INFO "%s: %s() " "__get_free_pages for read buf failed : " "get is for %d pages\n", - dev->name,__FUNCTION__,claw_read_pages ); + dev->name,__func__,claw_read_pages ); free_pages((unsigned long)privptr->p_buff_ccw, (int)pages_to_order_of_mag( privptr->p_buff_ccw_num)); @@ -2497,7 +2497,7 @@ init_ccw_bk(struct net_device *dev) privptr->p_buff_write=NULL; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > exit on line %d, rc =" - " ENOMEM\n",dev->name,__FUNCTION__,__LINE__); + " ENOMEM\n",dev->name,__func__,__LINE__); #endif return -ENOMEM; } @@ -2509,7 +2509,7 @@ init_ccw_bk(struct net_device *dev) */ #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() Begin build claw read free chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif p_buff=privptr->p_buff_read; for (i=0 ; i< privptr->p_env->read_buffers ; i++) { @@ -2590,7 +2590,7 @@ init_ccw_bk(struct net_device *dev) #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() Begin build claw read free chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif for (i=0 ; i< privptr->p_env->read_buffers ; i++) { p_buff = (void *)__get_free_pages(__GFP_DMA, @@ -2598,7 +2598,7 @@ init_ccw_bk(struct net_device *dev) if (p_buff==NULL) { printk(KERN_INFO "%s: %s() __get_free_pages for read " "buf failed : get is for %d pages\n", - dev->name,__FUNCTION__, + dev->name,__func__, privptr->p_buff_pages_perread ); free_pages((unsigned long)privptr->p_buff_ccw, (int)pages_to_order_of_mag(privptr->p_buff_ccw_num)); @@ -2622,7 +2622,7 @@ init_ccw_bk(struct net_device *dev) privptr->p_buff_write=NULL; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() exit on line %d, rc = ENOMEM\n", - dev->name,__FUNCTION__, + dev->name,__func__, __LINE__); #endif return -ENOMEM; @@ -2695,7 +2695,7 @@ init_ccw_bk(struct net_device *dev) } /* pBuffread = NULL */ #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() > End build claw read free chain \n", - dev->name,__FUNCTION__); + dev->name,__func__); p_buf=p_first_CCWB; while (p_buf!=NULL) { dumpit((char *)p_buf, sizeof(struct ccwbk)); @@ -2707,7 +2707,7 @@ init_ccw_bk(struct net_device *dev) privptr->buffs_alloc = 1; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return 0; } /* end of init_ccw_bk */ @@ -2723,11 +2723,11 @@ probe_error( struct ccwgroup_device *cgdev) { struct claw_privbk *privptr; #ifdef FUNCTRACE - printk(KERN_INFO "%s enter \n",__FUNCTION__); + printk(KERN_INFO "%s enter \n",__func__); #endif CLAW_DBF_TEXT(4,trace,"proberr"); #ifdef DEBUGMSG - printk(KERN_INFO "%s variable cgdev =\n",__FUNCTION__); + printk(KERN_INFO "%s variable cgdev =\n",__func__); dumpit((char *) cgdev, sizeof(struct ccwgroup_device)); #endif privptr=(struct claw_privbk *)cgdev->dev.driver_data; @@ -2741,7 +2741,7 @@ probe_error( struct ccwgroup_device *cgdev) } #ifdef FUNCTRACE printk(KERN_INFO "%s > exit on line %d\n", - __FUNCTION__,__LINE__); + __func__,__LINE__); #endif return; @@ -2772,7 +2772,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) struct chbk *p_ch = NULL; #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > enter \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"clw_cntl"); #ifdef DEBUGMSG @@ -2794,7 +2794,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() > " "exit on line %d, rc=0\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return 0; } @@ -3057,7 +3057,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) #ifdef FUNCTRACE printk(KERN_INFO "%s: %s() exit on line %d, rc = 0\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return 0; @@ -3080,7 +3080,7 @@ claw_send_control(struct net_device *dev, __u8 type, __u8 link, struct sk_buff *skb; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s > enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s > enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"sndcntl"); #ifdef DEBUGMSG @@ -3143,10 +3143,10 @@ claw_send_control(struct net_device *dev, __u8 type, __u8 link, skb = dev_alloc_skb(sizeof(struct clawctl)); if (!skb) { printk( "%s:%s low on mem, returning...\n", - dev->name,__FUNCTION__); + dev->name,__func__); #ifdef DEBUG printk(KERN_INFO "%s:%s Exit, rc = ENOMEM\n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif return -ENOMEM; } @@ -3162,7 +3162,7 @@ claw_send_control(struct net_device *dev, __u8 type, __u8 link, claw_hw_tx(skb, dev, 0); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return 0; @@ -3180,7 +3180,7 @@ claw_snd_conn_req(struct net_device *dev, __u8 link) struct clawctl *p_ctl; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"snd_conn"); #ifdef DEBUGMSG @@ -3193,7 +3193,7 @@ claw_snd_conn_req(struct net_device *dev, __u8 link) if ( privptr->system_validate_comp==0x00 ) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc = 1\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return rc; } @@ -3209,7 +3209,7 @@ claw_snd_conn_req(struct net_device *dev, __u8 link) HOST_APPL_NAME, privptr->p_env->api_type); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n", - dev->name,__FUNCTION__,__LINE__, rc); + dev->name,__func__,__LINE__, rc); #endif return rc; @@ -3228,7 +3228,7 @@ claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl) struct conncmd * p_connect; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"snd_dsc"); #ifdef DEBUGMSG @@ -3244,7 +3244,7 @@ claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl) p_connect->host_name, p_connect->WS_name); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n", - dev->name,__FUNCTION__, __LINE__, rc); + dev->name,__func__, __LINE__, rc); #endif return rc; } /* end of claw_snd_disc */ @@ -3265,7 +3265,7 @@ claw_snd_sys_validate_rsp(struct net_device *dev, #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Enter\n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"chkresp"); #ifdef DEBUGMSG @@ -3285,7 +3285,7 @@ claw_snd_sys_validate_rsp(struct net_device *dev, p_env->adapter_name ); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n", - dev->name,__FUNCTION__,__LINE__, rc); + dev->name,__func__,__LINE__, rc); #endif return rc; } /* end of claw_snd_sys_validate_rsp */ @@ -3301,7 +3301,7 @@ claw_strt_conn_req(struct net_device *dev ) int rc; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"conn_req"); #ifdef DEBUGMSG @@ -3311,7 +3311,7 @@ claw_strt_conn_req(struct net_device *dev ) rc=claw_snd_conn_req(dev, 1); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d, rc = %d\n", - dev->name,__FUNCTION__,__LINE__, rc); + dev->name,__func__,__LINE__, rc); #endif return rc; } /* end of claw_strt_conn_req */ @@ -3327,13 +3327,13 @@ net_device_stats *claw_stats(struct net_device *dev) { struct claw_privbk *privptr; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"stats"); privptr = dev->priv; #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return &privptr->stats; } /* end of claw_stats */ @@ -3366,7 +3366,7 @@ unpack_read(struct net_device *dev ) int p=0; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s enter \n",dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"unpkread"); p_first_ccw=NULL; @@ -3408,7 +3408,7 @@ unpack_read(struct net_device *dev ) if ((p_this_ccw->header.opcode & MORE_to_COME_FLAG)!=0) { #ifdef DEBUGMSG printk(KERN_INFO "%s: %s > More_to_come is ON\n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif mtc_this_frm=1; if (p_this_ccw->header.length!= @@ -3435,7 +3435,7 @@ unpack_read(struct net_device *dev ) #ifdef DEBUGMSG printk(KERN_INFO "%s:%s goto next " "frame from MoretoComeSkip \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif goto NextFrame; } @@ -3445,7 +3445,7 @@ unpack_read(struct net_device *dev ) #ifdef DEBUGMSG printk(KERN_INFO "%s:%s goto next " "frame from claw_process_control \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif CLAW_DBF_TEXT(4,trace,"UnpkCntl"); goto NextFrame; @@ -3468,7 +3468,7 @@ unpack_next: if (privptr->mtc_logical_link<0) { #ifdef DEBUGMSG printk(KERN_INFO "%s: %s mtc_logical_link < 0 \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif /* @@ -3487,7 +3487,7 @@ unpack_next: printk(KERN_INFO "%s: %s > goto next " "frame from MoretoComeSkip \n", dev->name, - __FUNCTION__); + __func__); printk(KERN_INFO " bytes_to_mov %d > (MAX_ENVELOPE_" "SIZE-privptr->mtc_offset %d)\n", bytes_to_mov,(MAX_ENVELOPE_SIZE- privptr->mtc_offset)); @@ -3505,13 +3505,13 @@ unpack_next: } #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() received data \n", - dev->name,__FUNCTION__); + dev->name,__func__); if (p_env->packing == DO_PACKED) dumpit((char *)p_packd+sizeof(struct clawph),32); else dumpit((char *)p_this_ccw->p_buffer, 32); printk(KERN_INFO "%s: %s() bytelength %d \n", - dev->name,__FUNCTION__,bytes_to_mov); + dev->name,__func__,bytes_to_mov); #endif if (mtc_this_frm==0) { len_of_data=privptr->mtc_offset+bytes_to_mov; @@ -3530,13 +3530,13 @@ unpack_next: #ifdef DEBUGMSG printk(KERN_INFO "%s: %s() netif_" "rx(skb) completed \n", - dev->name,__FUNCTION__); + dev->name,__func__); #endif } else { privptr->stats.rx_dropped++; printk(KERN_WARNING "%s: %s() low on memory\n", - dev->name,__FUNCTION__); + dev->name,__func__); } privptr->mtc_offset=0; privptr->mtc_logical_link=-1; @@ -3575,10 +3575,10 @@ NextFrame: #ifdef IOTRACE printk(KERN_INFO "%s:%s processed frame is %d \n", - dev->name,__FUNCTION__,i); + dev->name,__func__,i); printk(KERN_INFO "%s:%s F:%lx L:%lx\n", dev->name, - __FUNCTION__, + __func__, (unsigned long)p_first_ccw, (unsigned long)p_last_ccw); #endif @@ -3588,7 +3588,7 @@ NextFrame: claw_strt_read(dev, LOCK_YES); #ifdef FUNCTRACE printk(KERN_INFO "%s: %s exit on line %d\n", - dev->name, __FUNCTION__, __LINE__); + dev->name, __func__, __LINE__); #endif return; } /* end of unpack_read */ @@ -3610,7 +3610,7 @@ claw_strt_read (struct net_device *dev, int lock ) p_ch=&privptr->channel[READ]; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter \n",dev->name,__func__); printk(KERN_INFO "%s: variable lock = %d, dev =\n",dev->name, lock); dumpit((char *) dev, sizeof(struct net_device)); #endif @@ -3626,7 +3626,7 @@ claw_strt_read (struct net_device *dev, int lock ) } #ifdef DEBUGMSG printk(KERN_INFO "%s:%s state-%02x\n" , - dev->name,__FUNCTION__, p_ch->claw_state); + dev->name,__func__, p_ch->claw_state); #endif if (lock==LOCK_YES) { spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); @@ -3634,7 +3634,7 @@ claw_strt_read (struct net_device *dev, int lock ) if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) { #ifdef DEBUGMSG printk(KERN_INFO "%s: HOT READ started in %s\n" , - dev->name,__FUNCTION__); + dev->name,__func__); p_clawh=(struct clawh *)privptr->p_claw_signal_blk; dumpit((char *)&p_clawh->flag , 1); #endif @@ -3650,7 +3650,7 @@ claw_strt_read (struct net_device *dev, int lock ) else { #ifdef DEBUGMSG printk(KERN_INFO "%s: No READ started by %s() In progress\n" , - dev->name,__FUNCTION__); + dev->name,__func__); #endif CLAW_DBF_TEXT(2,trace,"ReadAct"); } @@ -3660,7 +3660,7 @@ claw_strt_read (struct net_device *dev, int lock ) } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif CLAW_DBF_TEXT(4,trace,"StRdExit"); return; @@ -3681,7 +3681,7 @@ claw_strt_out_IO( struct net_device *dev ) struct ccwbk *p_first_ccw; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif if (!dev) { return; @@ -3691,7 +3691,7 @@ claw_strt_out_IO( struct net_device *dev ) #ifdef DEBUGMSG printk(KERN_INFO "%s:%s state-%02x\n" , - dev->name,__FUNCTION__,p_ch->claw_state); + dev->name,__func__,p_ch->claw_state); #endif CLAW_DBF_TEXT(4,trace,"strt_io"); p_first_ccw=privptr->p_write_active_first; @@ -3701,14 +3701,14 @@ claw_strt_out_IO( struct net_device *dev ) if (p_first_ccw == NULL) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; } if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) { parm = (unsigned long) p_ch; #ifdef DEBUGMSG - printk(KERN_INFO "%s:%s do_io \n" ,dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s do_io \n" ,dev->name,__func__); dumpit((char *)p_first_ccw, sizeof(struct ccwbk)); #endif CLAW_DBF_TEXT(2,trace,"StWrtIO"); @@ -3721,7 +3721,7 @@ claw_strt_out_IO( struct net_device *dev ) dev->trans_start = jiffies; #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - dev->name,__FUNCTION__,__LINE__); + dev->name,__func__,__LINE__); #endif return; @@ -3745,7 +3745,7 @@ claw_free_wrt_buf( struct net_device *dev ) struct ccwbk*p_buf; #endif #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); printk(KERN_INFO "%s: free count = %d variable dev =\n", dev->name,privptr->write_free_count); #endif @@ -3798,7 +3798,7 @@ claw_free_wrt_buf( struct net_device *dev ) privptr->p_write_active_last=NULL; #ifdef DEBUGMSG printk(KERN_INFO "%s:%s p_write_" - "active_first==NULL\n",dev->name,__FUNCTION__); + "active_first==NULL\n",dev->name,__func__); #endif } #ifdef IOTRACE @@ -3819,7 +3819,7 @@ claw_free_wrt_buf( struct net_device *dev ) CLAW_DBF_TEXT_(4,trace,"FWC=%d",privptr->write_free_count); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d free_count =%d\n", - dev->name,__FUNCTION__, __LINE__,privptr->write_free_count); + dev->name,__func__, __LINE__,privptr->write_free_count); #endif return; } @@ -3833,7 +3833,7 @@ claw_free_netdevice(struct net_device * dev, int free_dev) { struct claw_privbk *privptr; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"free_dev"); @@ -3854,7 +3854,7 @@ claw_free_netdevice(struct net_device * dev, int free_dev) #endif CLAW_DBF_TEXT(2,setup,"feee_ok"); #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Exit\n",dev->name,__func__); #endif } @@ -3867,13 +3867,13 @@ static void claw_init_netdevice(struct net_device * dev) { #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"init_dev"); CLAW_DBF_TEXT_(2,setup,"%s",dev->name); if (!dev) { printk(KERN_WARNING "claw:%s BAD Device exit line %d\n", - __FUNCTION__,__LINE__); + __func__,__LINE__); CLAW_DBF_TEXT(2,setup,"baddev"); return; } @@ -3889,7 +3889,7 @@ claw_init_netdevice(struct net_device * dev) dev->tx_queue_len = 1300; dev->flags = IFF_POINTOPOINT | IFF_NOARP; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__); + printk(KERN_INFO "%s:%s Exit\n",dev->name,__func__); #endif CLAW_DBF_TEXT(2,setup,"initok"); return; @@ -3909,7 +3909,7 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr) struct ccw_dev_id dev_id; #ifdef FUNCTRACE - printk(KERN_INFO "%s:%s Enter\n",cdev->dev.bus_id,__FUNCTION__); + printk(KERN_INFO "%s:%s Enter\n",cdev->dev.bus_id,__func__); #endif CLAW_DBF_TEXT_(2,setup,"%s",cdev->dev.bus_id); privptr->channel[i].flag = i+1; /* Read is 1 Write is 2 */ @@ -3920,16 +3920,16 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr) p_ch->devno = dev_id.devno; if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) { printk(KERN_WARNING "%s Out of memory in %s for irb\n", - p_ch->id,__FUNCTION__); + p_ch->id,__func__); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - p_ch->id,__FUNCTION__,__LINE__); + p_ch->id,__func__,__LINE__); #endif return -ENOMEM; } #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", - cdev->dev.bus_id,__FUNCTION__,__LINE__); + cdev->dev.bus_id,__func__,__LINE__); #endif return 0; } @@ -3952,7 +3952,7 @@ claw_new_device(struct ccwgroup_device *cgdev) int ret; struct ccw_dev_id dev_id; - pr_debug("%s() called\n", __FUNCTION__); + pr_debug("%s() called\n", __func__); printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id); CLAW_DBF_TEXT(2,setup,"new_dev"); privptr = cgdev->dev.driver_data; @@ -3990,7 +3990,7 @@ claw_new_device(struct ccwgroup_device *cgdev) } dev = alloc_netdev(0,"claw%d",claw_init_netdevice); if (!dev) { - printk(KERN_WARNING "%s:alloc_netdev failed\n",__FUNCTION__); + printk(KERN_WARNING "%s:alloc_netdev failed\n",__func__); goto out; } dev->priv = privptr; @@ -4065,7 +4065,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) struct net_device *ndev; int ret; - pr_debug("%s() called\n", __FUNCTION__); + pr_debug("%s() called\n", __func__); CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id); priv = cgdev->dev.driver_data; if (!priv) @@ -4095,15 +4095,15 @@ claw_remove_device(struct ccwgroup_device *cgdev) { struct claw_privbk *priv; - pr_debug("%s() called\n", __FUNCTION__); + pr_debug("%s() called\n", __func__); CLAW_DBF_TEXT_(2,setup,"%s",cgdev->dev.bus_id); priv = cgdev->dev.driver_data; if (!priv) { - printk(KERN_WARNING "claw: %s() no Priv exiting\n",__FUNCTION__); + printk(KERN_WARNING "claw: %s() no Priv exiting\n",__func__); return; } printk(KERN_INFO "claw: %s() called %s will be removed.\n", - __FUNCTION__,cgdev->cdev[0]->dev.bus_id); + __func__,cgdev->cdev[0]->dev.bus_id); if (cgdev->state == CCWGROUP_ONLINE) claw_shutdown_device(cgdev); claw_remove_files(&cgdev->dev); @@ -4346,7 +4346,7 @@ static struct attribute_group claw_attr_group = { static int claw_add_files(struct device *dev) { - pr_debug("%s() called\n", __FUNCTION__); + pr_debug("%s() called\n", __func__); CLAW_DBF_TEXT(2,setup,"add_file"); return sysfs_create_group(&dev->kobj, &claw_attr_group); } @@ -4354,7 +4354,7 @@ claw_add_files(struct device *dev) static void claw_remove_files(struct device *dev) { - pr_debug("%s() called\n", __FUNCTION__); + pr_debug("%s() called\n", __func__); CLAW_DBF_TEXT(2,setup,"rem_file"); sysfs_remove_group(&dev->kobj, &claw_attr_group); } @@ -4385,12 +4385,12 @@ claw_init(void) printk(KERN_INFO "claw: starting driver\n"); #ifdef FUNCTRACE - printk(KERN_INFO "claw: %s() enter \n",__FUNCTION__); + printk(KERN_INFO "claw: %s() enter \n",__func__); #endif ret = claw_register_debug_facility(); if (ret) { printk(KERN_WARNING "claw: %s() debug_register failed %d\n", - __FUNCTION__,ret); + __func__,ret); return ret; } CLAW_DBF_TEXT(2,setup,"init_mod"); @@ -4398,10 +4398,10 @@ claw_init(void) if (ret) { claw_unregister_debug_facility(); printk(KERN_WARNING "claw; %s() cu3088 register failed %d\n", - __FUNCTION__,ret); + __func__,ret); } #ifdef FUNCTRACE - printk(KERN_INFO "claw: %s() exit \n",__FUNCTION__); + printk(KERN_INFO "claw: %s() exit \n",__func__); #endif return ret; } diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 874a1999448..8f876f6ab36 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -670,7 +670,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) struct netiucv_priv *privptr = netdev_priv(conn->netdev); int rc; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); if (!conn->netdev) { iucv_message_reject(conn->path, msg); @@ -718,7 +718,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) struct ll_header header; int rc; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); if (conn && conn->netdev) privptr = netdev_priv(conn->netdev); @@ -799,7 +799,7 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) struct netiucv_priv *privptr = netdev_priv(netdev); int rc; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); conn->path = path; path->msglim = NETIUCV_QUEUELEN_DEFAULT; @@ -821,7 +821,7 @@ static void conn_action_connreject(fsm_instance *fi, int event, void *arg) struct iucv_event *ev = arg; struct iucv_path *path = ev->data; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); iucv_path_sever(path, NULL); } @@ -831,7 +831,7 @@ static void conn_action_connack(fsm_instance *fi, int event, void *arg) struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = netdev_priv(netdev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); netdev->tx_queue_len = conn->path->msglim; @@ -842,7 +842,7 @@ static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) { struct iucv_connection *conn = arg; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_deltimer(&conn->timer); iucv_path_sever(conn->path, NULL); fsm_newstate(fi, CONN_STATE_STARTWAIT); @@ -854,7 +854,7 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = netdev_priv(netdev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_deltimer(&conn->timer); iucv_path_sever(conn->path, NULL); @@ -870,7 +870,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) struct iucv_connection *conn = arg; int rc; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, CONN_STATE_STARTWAIT); PRINT_DEBUG("%s('%s'): connecting ...\n", @@ -948,7 +948,7 @@ static void conn_action_stop(fsm_instance *fi, int event, void *arg) struct net_device *netdev = conn->netdev; struct netiucv_priv *privptr = netdev_priv(netdev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); @@ -1024,7 +1024,7 @@ static void dev_action_start(fsm_instance *fi, int event, void *arg) struct net_device *dev = arg; struct netiucv_priv *privptr = netdev_priv(dev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, DEV_STATE_STARTWAIT); fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); @@ -1044,7 +1044,7 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) struct netiucv_priv *privptr = netdev_priv(dev); struct iucv_event ev; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); ev.conn = privptr->conn; @@ -1066,7 +1066,7 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) struct net_device *dev = arg; struct netiucv_priv *privptr = netdev_priv(dev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); switch (fsm_getstate(fi)) { case DEV_STATE_STARTWAIT: @@ -1097,7 +1097,7 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) static void dev_action_conndown(fsm_instance *fi, int event, void *arg) { - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); switch (fsm_getstate(fi)) { case DEV_STATE_RUNNING: @@ -1288,7 +1288,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) struct netiucv_priv *privptr = netdev_priv(dev); int rc; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); /** * Some sanity checks ... */ @@ -1344,7 +1344,7 @@ static struct net_device_stats *netiucv_stats (struct net_device * dev) { struct netiucv_priv *priv = netdev_priv(dev); - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return &priv->stats; } @@ -1360,7 +1360,7 @@ static struct net_device_stats *netiucv_stats (struct net_device * dev) */ static int netiucv_change_mtu(struct net_device * dev, int new_mtu) { - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); return -EINVAL; @@ -1378,7 +1378,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } @@ -1393,7 +1393,7 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, int i; struct iucv_connection *cp; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (count > 9) { PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, @@ -1449,7 +1449,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); } @@ -1461,7 +1461,7 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, char *e; int bs1; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (count >= 39) return -EINVAL; @@ -1513,7 +1513,7 @@ static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm)); } @@ -1524,7 +1524,7 @@ static ssize_t conn_fsm_show (struct device *dev, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); } @@ -1535,7 +1535,7 @@ static ssize_t maxmulti_show (struct device *dev, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); } @@ -1545,7 +1545,7 @@ static ssize_t maxmulti_write (struct device *dev, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.maxmulti = 0; return count; } @@ -1557,7 +1557,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); } @@ -1566,7 +1566,7 @@ static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.maxcqueue = 0; return count; } @@ -1578,7 +1578,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); } @@ -1587,7 +1587,7 @@ static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.doios_single = 0; return count; } @@ -1599,7 +1599,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); } @@ -1608,7 +1608,7 @@ static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); priv->conn->prof.doios_multi = 0; return count; } @@ -1620,7 +1620,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.txlen); } @@ -1629,7 +1629,7 @@ static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.txlen = 0; return count; } @@ -1641,7 +1641,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); } @@ -1650,7 +1650,7 @@ static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_time = 0; return count; } @@ -1662,7 +1662,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); } @@ -1671,7 +1671,7 @@ static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_pending = 0; return count; } @@ -1683,7 +1683,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 5, __FUNCTION__); + IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); } @@ -1692,7 +1692,7 @@ static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, { struct netiucv_priv *priv = dev->driver_data; - IUCV_DBF_TEXT(trace, 4, __FUNCTION__); + IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_max_pending = 0; return count; } @@ -1732,7 +1732,7 @@ static int netiucv_add_files(struct device *dev) { int ret; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); ret = sysfs_create_group(&dev->kobj, &netiucv_attr_group); if (ret) return ret; @@ -1744,7 +1744,7 @@ static int netiucv_add_files(struct device *dev) static void netiucv_remove_files(struct device *dev) { - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } @@ -1756,7 +1756,7 @@ static int netiucv_register_device(struct net_device *ndev) int ret; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (dev) { snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name); @@ -1792,7 +1792,7 @@ out_unreg: static void netiucv_unregister_device(struct device *dev) { - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); netiucv_remove_files(dev); device_unregister(dev); } @@ -1857,7 +1857,7 @@ out: */ static void netiucv_remove_connection(struct iucv_connection *conn) { - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); write_lock_bh(&iucv_connection_rwlock); list_del_init(&conn->list); write_unlock_bh(&iucv_connection_rwlock); @@ -1881,7 +1881,7 @@ static void netiucv_free_netdevice(struct net_device *dev) { struct netiucv_priv *privptr = netdev_priv(dev); - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (!dev) return; @@ -1963,7 +1963,7 @@ static ssize_t conn_write(struct device_driver *drv, struct netiucv_priv *priv; struct iucv_connection *cp; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (count>9) { PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); @@ -2048,7 +2048,7 @@ static ssize_t remove_write (struct device_driver *drv, const char *p; int i; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); if (count >= IFNAMSIZ) count = IFNAMSIZ - 1;; @@ -2116,7 +2116,7 @@ static void __exit netiucv_exit(void) struct netiucv_priv *priv; struct device *dev; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + IUCV_DBF_TEXT(trace, 3, __func__); while (!list_empty(&iucv_connection_list)) { cp = list_entry(iucv_connection_list.next, struct iucv_connection, list); @@ -2146,8 +2146,7 @@ static int __init netiucv_init(void) rc = iucv_register(&netiucv_handler, 1); if (rc) goto out_dbf; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - netiucv_driver.groups = netiucv_drv_attr_groups; + IUCV_DBF_TEXT(trace, 3, __func__); rc = driver_register(&netiucv_driver); if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 644a06eba82..4d4b54277c4 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -59,15 +59,15 @@ repeat: printk(KERN_WARNING"%s: Code does not support more " "than two chained crws; please report to " - "linux390@de.ibm.com!\n", __FUNCTION__); + "linux390@de.ibm.com!\n", __func__); ccode = stcrw(&tmp_crw); printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - __FUNCTION__, tmp_crw.slct, tmp_crw.oflw, + __func__, tmp_crw.slct, tmp_crw.oflw, tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, tmp_crw.erc, tmp_crw.rsid); printk(KERN_WARNING"%s: This was crw number %x in the " - "chain\n", __FUNCTION__, chain); + "chain\n", __func__, chain); if (ccode != 0) break; chain = tmp_crw.chn ? chain + 1 : 0; @@ -83,7 +83,7 @@ repeat: crw[chain].rsid); /* Check for overflows. */ if (crw[chain].oflw) { - pr_debug("%s: crw overflow detected!\n", __FUNCTION__); + pr_debug("%s: crw overflow detected!\n", __func__); css_schedule_eval_all(); chain = 0; continue; diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index d3ca4281a49..ca681f9b67f 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -105,4 +105,8 @@ static inline int stcrw(struct crw *pcrw ) #define ED_ETR_SYNC 12 /* External damage ETR sync check */ #define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ +struct pt_regs; + +void s390_handle_mcck(void); +void s390_do_machine_check(struct pt_regs *regs); #endif /* __s390mach */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9e9f6c1e4e5..45a7cd98c14 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -539,7 +539,7 @@ struct zfcp_rc_entry { /* logging routine for zfcp */ #define _ZFCP_LOG(fmt, args...) \ - printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __FUNCTION__, \ + printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __func__, \ __LINE__ , ##args) #define ZFCP_LOG(level, fmt, args...) \ diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 291ff6235fe..c3e4ab07b9c 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -11,111 +11,13 @@ #include <linux/init.h> #include <linux/delay.h> #include <asm/ebcdic.h> +#include <asm/sysinfo.h> /* Sigh, math-emu. Don't ask. */ #include <asm/sfp-util.h> #include <math-emu/soft-fp.h> #include <math-emu/single.h> -struct sysinfo_1_1_1 { - char reserved_0[32]; - char manufacturer[16]; - char type[4]; - char reserved_1[12]; - char model_capacity[16]; - char sequence[16]; - char plant[4]; - char model[16]; -}; - -struct sysinfo_1_2_1 { - char reserved_0[80]; - char sequence[16]; - char plant[4]; - char reserved_1[2]; - unsigned short cpu_address; -}; - -struct sysinfo_1_2_2 { - char format; - char reserved_0[1]; - unsigned short acc_offset; - char reserved_1[24]; - unsigned int secondary_capability; - unsigned int capability; - unsigned short cpus_total; - unsigned short cpus_configured; - unsigned short cpus_standby; - unsigned short cpus_reserved; - unsigned short adjustment[0]; -}; - -struct sysinfo_1_2_2_extension { - unsigned int alt_capability; - unsigned short alt_adjustment[0]; -}; - -struct sysinfo_2_2_1 { - char reserved_0[80]; - char sequence[16]; - char plant[4]; - unsigned short cpu_id; - unsigned short cpu_address; -}; - -struct sysinfo_2_2_2 { - char reserved_0[32]; - unsigned short lpar_number; - char reserved_1; - unsigned char characteristics; - unsigned short cpus_total; - unsigned short cpus_configured; - unsigned short cpus_standby; - unsigned short cpus_reserved; - char name[8]; - unsigned int caf; - char reserved_2[16]; - unsigned short cpus_dedicated; - unsigned short cpus_shared; -}; - -#define LPAR_CHAR_DEDICATED (1 << 7) -#define LPAR_CHAR_SHARED (1 << 6) -#define LPAR_CHAR_LIMITED (1 << 5) - -struct sysinfo_3_2_2 { - char reserved_0[31]; - unsigned char count; - struct { - char reserved_0[4]; - unsigned short cpus_total; - unsigned short cpus_configured; - unsigned short cpus_standby; - unsigned short cpus_reserved; - char name[8]; - unsigned int caf; - char cpi[16]; - char reserved_1[24]; - - } vm[8]; -}; - -static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) -{ - register int r0 asm("0") = (fc << 28) | sel1; - register int r1 asm("1") = sel2; - - asm volatile( - " stsi 0(%2)\n" - "0: jz 2f\n" - "1: lhi %0,%3\n" - "2:\n" - EX_TABLE(0b,1b) - : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS) - : "cc", "memory" ); - return r0; -} - static inline int stsi_0(void) { int rc = stsi (NULL, 0, 0, 0); @@ -133,6 +35,8 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) EBCASC(info->sequence, sizeof(info->sequence)); EBCASC(info->plant, sizeof(info->plant)); EBCASC(info->model_capacity, sizeof(info->model_capacity)); + EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); + EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); len += sprintf(page + len, "Manufacturer: %-16.16s\n", info->manufacturer); len += sprintf(page + len, "Type: %-4.4s\n", @@ -155,8 +59,18 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) info->sequence); len += sprintf(page + len, "Plant: %-4.4s\n", info->plant); - len += sprintf(page + len, "Model Capacity: %-16.16s\n", - info->model_capacity); + len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", + info->model_capacity, *(u32 *) info->model_cap_rating); + if (info->model_perm_cap[0] != '\0') + len += sprintf(page + len, + "Model Perm. Capacity: %-16.16s %08u\n", + info->model_perm_cap, + *(u32 *) info->model_perm_cap_rating); + if (info->model_temp_cap[0] != '\0') + len += sprintf(page + len, + "Model Temp. Capacity: %-16.16s %08u\n", + info->model_temp_cap, + *(u32 *) info->model_temp_cap_rating); return len; } diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 123b557c3ff..0818ecd30ca 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -397,6 +397,10 @@ struct cio_iplinfo { extern int cio_get_iplinfo(struct cio_iplinfo *iplinfo); +/* Function from drivers/s390/cio/chsc.c */ +int chsc_sstpc(void *page, unsigned int op, u16 ctrl); +int chsc_sstpi(void *page, void *result, size_t size); + #endif #endif diff --git a/include/asm-s390/cpu.h b/include/asm-s390/cpu.h index 352dde194f3..e5a6a9ba3ad 100644 --- a/include/asm-s390/cpu.h +++ b/include/asm-s390/cpu.h @@ -22,4 +22,12 @@ struct s390_idle_data { DECLARE_PER_CPU(struct s390_idle_data, s390_idle); +void s390_idle_leave(void); + +static inline void s390_idle_check(void) +{ + if ((&__get_cpu_var(s390_idle))->in_idle) + s390_idle_leave(); +} + #endif /* _ASM_S390_CPU_H_ */ diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h index c00dd2b3dc5..335baf4fc64 100644 --- a/include/asm-s390/debug.h +++ b/include/asm-s390/debug.h @@ -73,6 +73,7 @@ typedef struct debug_info { struct dentry* debugfs_entries[DEBUG_MAX_VIEWS]; struct debug_view* views[DEBUG_MAX_VIEWS]; char name[DEBUG_MAX_NAME_LEN]; + mode_t mode; } debug_info_t; typedef int (debug_header_proc_t) (debug_info_t* id, @@ -122,6 +123,10 @@ debug_entry_t* debug_exception_common(debug_info_t* id, int level, debug_info_t* debug_register(char* name, int pages, int nr_areas, int buf_size); +debug_info_t *debug_register_mode(char *name, int pages, int nr_areas, + int buf_size, mode_t mode, uid_t uid, + gid_t gid); + void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); diff --git a/include/asm-s390/extmem.h b/include/asm-s390/extmem.h index c8802c934b7..33837d75618 100644 --- a/include/asm-s390/extmem.h +++ b/include/asm-s390/extmem.h @@ -22,11 +22,12 @@ #define SEGMENT_SHARED 0 #define SEGMENT_EXCLUSIVE 1 -extern int segment_load (char *name,int segtype,unsigned long *addr,unsigned long *length); -extern void segment_unload(char *name); -extern void segment_save(char *name); -extern int segment_type (char* name); -extern int segment_modify_shared (char *name, int do_nonshared); +int segment_load (char *name, int segtype, unsigned long *addr, unsigned long *length); +void segment_unload(char *name); +void segment_save(char *name); +int segment_type (char* name); +int segment_modify_shared (char *name, int do_nonshared); +void segment_warning(int rc, char *seg_name); #endif #endif diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index 31beb18cb3d..4b7cb964ff3 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -32,6 +32,6 @@ typedef struct { #define HARDIRQ_BITS 8 -extern void account_ticks(u64 time); +void clock_comparator_work(void); #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 801a6fd35b5..5de3efb3144 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -56,6 +56,8 @@ #define __LC_IO_INT_WORD 0x0C0 #define __LC_MCCK_CODE 0x0E8 +#define __LC_LAST_BREAK 0x110 + #define __LC_RETURN_PSW 0x200 #define __LC_SAVE_AREA 0xC00 @@ -80,7 +82,6 @@ #define __LC_CPUID 0xC60 #define __LC_CPUADDR 0xC68 #define __LC_IPLDEV 0xC7C -#define __LC_JIFFY_TIMER 0xC80 #define __LC_CURRENT 0xC90 #define __LC_INT_CLOCK 0xC98 #else /* __s390x__ */ @@ -103,7 +104,6 @@ #define __LC_CPUID 0xD80 #define __LC_CPUADDR 0xD88 #define __LC_IPLDEV 0xDB8 -#define __LC_JIFFY_TIMER 0xDC0 #define __LC_CURRENT 0xDD8 #define __LC_INT_CLOCK 0xDE8 #endif /* __s390x__ */ @@ -276,7 +276,7 @@ struct _lowcore /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ - __u64 jiffy_timer; /* 0xc80 */ + __u64 clock_comparator; /* 0xc80 */ __u32 ext_call_fast; /* 0xc88 */ __u32 percpu_offset; /* 0xc8c */ __u32 current_task; /* 0xc90 */ @@ -368,11 +368,12 @@ struct _lowcore /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ - __u64 jiffy_timer; /* 0xdc0 */ + __u64 clock_comparator; /* 0xdc0 */ __u64 ext_call_fast; /* 0xdc8 */ __u64 percpu_offset; /* 0xdd0 */ __u64 current_task; /* 0xdd8 */ - __u64 softirq_pending; /* 0xde0 */ + __u32 softirq_pending; /* 0xde0 */ + __u32 pad_0x0de4; /* 0xde4 */ __u64 int_clock; /* 0xde8 */ __u8 pad12[0xe00-0xdf0]; /* 0xdf0 */ diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 51d88912aa2..8eaf343a12a 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -175,6 +175,13 @@ extern void task_show_regs(struct seq_file *m, struct task_struct *task); extern void show_registers(struct pt_regs *regs); extern void show_code(struct pt_regs *regs); extern void show_trace(struct task_struct *task, unsigned long *sp); +#ifdef CONFIG_64BIT +extern void show_last_breaking_event(struct pt_regs *regs); +#else +static inline void show_last_breaking_event(struct pt_regs *regs) +{ +} +#endif unsigned long get_wchan(struct task_struct *p); #define task_pt_regs(tsk) ((struct pt_regs *) \ diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index c7b74326a52..6f3821a6a90 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -90,6 +90,9 @@ extern void __cpu_die (unsigned int cpu); extern void cpu_die (void) __attribute__ ((noreturn)); extern int __cpu_up (unsigned int cpu); +extern struct mutex smp_cpu_state_mutex; +extern int smp_cpu_polarization[]; + extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, int wait); #endif diff --git a/include/asm-s390/sysinfo.h b/include/asm-s390/sysinfo.h new file mode 100644 index 00000000000..abe10ae15e4 --- /dev/null +++ b/include/asm-s390/sysinfo.h @@ -0,0 +1,116 @@ +/* + * definition for store system information stsi + * + * Copyright IBM Corp. 2001,2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + * + * Author(s): Ulrich Weigand <weigand@de.ibm.com> + * Christian Borntraeger <borntraeger@de.ibm.com> + */ + +struct sysinfo_1_1_1 { + char reserved_0[32]; + char manufacturer[16]; + char type[4]; + char reserved_1[12]; + char model_capacity[16]; + char sequence[16]; + char plant[4]; + char model[16]; + char model_perm_cap[16]; + char model_temp_cap[16]; + char model_cap_rating[4]; + char model_perm_cap_rating[4]; + char model_temp_cap_rating[4]; +}; + +struct sysinfo_1_2_1 { + char reserved_0[80]; + char sequence[16]; + char plant[4]; + char reserved_1[2]; + unsigned short cpu_address; +}; + +struct sysinfo_1_2_2 { + char format; + char reserved_0[1]; + unsigned short acc_offset; + char reserved_1[24]; + unsigned int secondary_capability; + unsigned int capability; + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + unsigned short adjustment[0]; +}; + +struct sysinfo_1_2_2_extension { + unsigned int alt_capability; + unsigned short alt_adjustment[0]; +}; + +struct sysinfo_2_2_1 { + char reserved_0[80]; + char sequence[16]; + char plant[4]; + unsigned short cpu_id; + unsigned short cpu_address; +}; + +struct sysinfo_2_2_2 { + char reserved_0[32]; + unsigned short lpar_number; + char reserved_1; + unsigned char characteristics; + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + char name[8]; + unsigned int caf; + char reserved_2[16]; + unsigned short cpus_dedicated; + unsigned short cpus_shared; +}; + +#define LPAR_CHAR_DEDICATED (1 << 7) +#define LPAR_CHAR_SHARED (1 << 6) +#define LPAR_CHAR_LIMITED (1 << 5) + +struct sysinfo_3_2_2 { + char reserved_0[31]; + unsigned char count; + struct { + char reserved_0[4]; + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + char name[8]; + unsigned int caf; + char cpi[16]; + char reserved_1[24]; + + } vm[8]; +}; + +static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) +{ + register int r0 asm("0") = (fc << 28) | sel1; + register int r1 asm("1") = sel2; + + asm volatile( + " stsi 0(%2)\n" + "0: jz 2f\n" + "1: lhi %0,%3\n" + "2:\n" + EX_TABLE(0b, 1b) + : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS) + : "cc", "memory"); + return r0; +} diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 15aba30601a..92098df4d6e 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -406,6 +406,8 @@ __set_psw_mask(unsigned long mask) #define local_mcck_enable() __set_psw_mask(psw_kernel_bits) #define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK) +int stfle(unsigned long long *list, int doublewords); + #ifdef CONFIG_SMP extern void smp_ctl_set_bit(int cr, int bit); diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h index 98229db2431..d744c3d62de 100644 --- a/include/asm-s390/timex.h +++ b/include/asm-s390/timex.h @@ -62,16 +62,18 @@ static inline unsigned long long get_clock (void) return clk; } -static inline void get_clock_extended(void *dest) +static inline unsigned long long get_clock_xt(void) { - typedef struct { unsigned long long clk[2]; } __clock_t; + unsigned char clk[16]; #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - asm volatile("stcke %0" : "=Q" (*((__clock_t *)dest)) : : "cc"); + asm volatile("stcke %0" : "=Q" (clk) : : "cc"); #else /* __GNUC__ */ - asm volatile("stcke 0(%1)" : "=m" (*((__clock_t *)dest)) - : "a" ((__clock_t *)dest) : "cc"); + asm volatile("stcke 0(%1)" : "=m" (clk) + : "a" (clk) : "cc"); #endif /* __GNUC__ */ + + return *((unsigned long long *)&clk[1]); } static inline cycles_t get_cycles(void) @@ -81,5 +83,6 @@ static inline cycles_t get_cycles(void) int get_sync_clock(unsigned long long *clock); void init_cpu_timer(void); +unsigned long long monotonic_clock(void); #endif diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h index 35fb4f9127b..9e57a93d7de 100644 --- a/include/asm-s390/tlbflush.h +++ b/include/asm-s390/tlbflush.h @@ -13,12 +13,14 @@ static inline void __tlb_flush_local(void) asm volatile("ptlb" : : : "memory"); } +#ifdef CONFIG_SMP /* * Flush all tlb entries on all cpus. */ +void smp_ptlb_all(void); + static inline void __tlb_flush_global(void) { - extern void smp_ptlb_all(void); register unsigned long reg2 asm("2"); register unsigned long reg3 asm("3"); register unsigned long reg4 asm("4"); @@ -39,6 +41,25 @@ static inline void __tlb_flush_global(void) : : "d" (reg2), "d" (reg3), "d" (reg4), "m" (dummy) : "cc" ); } +static inline void __tlb_flush_full(struct mm_struct *mm) +{ + cpumask_t local_cpumask; + + preempt_disable(); + /* + * If the process only ran on the local cpu, do a local flush. + */ + local_cpumask = cpumask_of_cpu(smp_processor_id()); + if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) + __tlb_flush_local(); + else + __tlb_flush_global(); + preempt_enable(); +} +#else +#define __tlb_flush_full(mm) __tlb_flush_local() +#endif + /* * Flush all tlb entries of a page table on all cpus. */ @@ -51,8 +72,6 @@ static inline void __tlb_flush_idte(unsigned long asce) static inline void __tlb_flush_mm(struct mm_struct * mm) { - cpumask_t local_cpumask; - if (unlikely(cpus_empty(mm->cpu_vm_mask))) return; /* @@ -69,16 +88,7 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) mm->context.asce_bits); return; } - preempt_disable(); - /* - * If the process only ran on the local cpu, do a local flush. - */ - local_cpumask = cpumask_of_cpu(smp_processor_id()); - if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) - __tlb_flush_local(); - else - __tlb_flush_global(); - preempt_enable(); + __tlb_flush_full(mm); } static inline void __tlb_flush_mm_cond(struct mm_struct * mm) diff --git a/include/asm-s390/topology.h b/include/asm-s390/topology.h index 613aa64019d..8e97b06f298 100644 --- a/include/asm-s390/topology.h +++ b/include/asm-s390/topology.h @@ -1,6 +1,29 @@ #ifndef _ASM_S390_TOPOLOGY_H #define _ASM_S390_TOPOLOGY_H +#include <linux/cpumask.h> + +#define mc_capable() (1) + +cpumask_t cpu_coregroup_map(unsigned int cpu); + +int topology_set_cpu_management(int fc); +void topology_schedule_update(void); + +#define POLARIZATION_UNKNWN (-1) +#define POLARIZATION_HRZ (0) +#define POLARIZATION_VL (1) +#define POLARIZATION_VM (2) +#define POLARIZATION_VH (3) + +#ifdef CONFIG_SMP +void s390_init_cpu_topology(void); +#else +static inline void s390_init_cpu_topology(void) +{ +}; +#endif + #include <asm-generic/topology.h> #endif /* _ASM_S390_TOPOLOGY_H */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f8ab4ce7056..b5fef13148b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -102,6 +102,25 @@ extern void disable_irq_nosync(unsigned int irq); extern void disable_irq(unsigned int irq); extern void enable_irq(unsigned int irq); +#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) + +extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); +extern int irq_can_set_affinity(unsigned int irq); + +#else /* CONFIG_SMP */ + +static inline int irq_set_affinity(unsigned int irq, cpumask_t cpumask) +{ + return -EINVAL; +} + +static inline int irq_can_set_affinity(unsigned int irq) +{ + return 0; +} + +#endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */ + #ifdef CONFIG_GENERIC_HARDIRQS /* * Special lockdep variants of irq disabling/enabling. diff --git a/include/linux/irq.h b/include/linux/irq.h index 176e5e790a4..1883a85625d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -228,21 +228,11 @@ static inline void set_pending_irq(unsigned int irq, cpumask_t mask) #endif /* CONFIG_GENERIC_PENDING_IRQ */ -extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); -extern int irq_can_set_affinity(unsigned int irq); - #else /* CONFIG_SMP */ #define move_native_irq(x) #define move_masked_irq(x) -static inline int irq_set_affinity(unsigned int irq, cpumask_t cpumask) -{ - return -EINVAL; -} - -static inline int irq_can_set_affinity(unsigned int irq) { return 0; } - #endif /* CONFIG_SMP */ #ifdef CONFIG_IRQBALANCE diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index b00c1c73eb0..79d59c937fa 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -45,9 +45,9 @@ struct kmem_cache_cpu { struct kmem_cache_node { spinlock_t list_lock; /* Protect partial list and nr_partial */ unsigned long nr_partial; - atomic_long_t nr_slabs; struct list_head partial; #ifdef CONFIG_SLUB_DEBUG + atomic_long_t nr_slabs; struct list_head full; #endif }; diff --git a/init/Kconfig b/init/Kconfig index a97924bc5b8..7fccf09bb95 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -763,7 +763,7 @@ endmenu # General setup config SLABINFO bool depends on PROC_FS - depends on SLAB || SLUB + depends on SLAB || SLUB_DEBUG default y config RT_MUTEXES diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2727f923835..6d8de051382 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1722,7 +1722,12 @@ void cgroup_enable_task_cg_lists(void) use_task_css_set_links = 1; do_each_thread(g, p) { task_lock(p); - if (list_empty(&p->cg_list)) + /* + * We should check if the process is exiting, otherwise + * it will race with cgroup_exit() in that the list + * entry won't be deleted though the process has exited. + */ + if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list)) list_add(&p->cg_list, &p->cgroups->tasks); task_unlock(p); } while_each_thread(g, p); diff --git a/kernel/signal.c b/kernel/signal.c index 6af1210092c..cc8303cd093 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1757,6 +1757,45 @@ static int do_signal_stop(int signr) return 1; } +static int ptrace_signal(int signr, siginfo_t *info, + struct pt_regs *regs, void *cookie) +{ + if (!(current->ptrace & PT_PTRACED)) + return signr; + + ptrace_signal_deliver(regs, cookie); + + /* Let the debugger run. */ + ptrace_stop(signr, 0, info); + + /* We're back. Did the debugger cancel the sig? */ + signr = current->exit_code; + if (signr == 0) + return signr; + + current->exit_code = 0; + + /* Update the siginfo structure if the signal has + changed. If the debugger wanted something + specific in the siginfo structure then it should + have updated *info via PTRACE_SETSIGINFO. */ + if (signr != info->si_signo) { + info->si_signo = signr; + info->si_errno = 0; + info->si_code = SI_USER; + info->si_pid = task_pid_vnr(current->parent); + info->si_uid = current->parent->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + specific_send_sig_info(signr, info, current); + signr = 0; + } + + return signr; +} + int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie) { @@ -1785,36 +1824,10 @@ relock: if (!signr) break; /* will return 0 */ - if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { - ptrace_signal_deliver(regs, cookie); - - /* Let the debugger run. */ - ptrace_stop(signr, 0, info); - - /* We're back. Did the debugger cancel the sig? */ - signr = current->exit_code; - if (signr == 0) - continue; - - current->exit_code = 0; - - /* Update the siginfo structure if the signal has - changed. If the debugger wanted something - specific in the siginfo structure then it should - have updated *info via PTRACE_SETSIGINFO. */ - if (signr != info->si_signo) { - info->si_signo = signr; - info->si_errno = 0; - info->si_code = SI_USER; - info->si_pid = task_pid_vnr(current->parent); - info->si_uid = current->parent->uid; - } - - /* If the (new) signal is now blocked, requeue it. */ - if (sigismember(¤t->blocked, signr)) { - specific_send_sig_info(signr, info, current); + if (signr != SIGKILL) { + signr = ptrace_signal(signr, info, regs, cookie); + if (!signr) continue; - } } ka = ¤t->sighand->action[signr-1]; diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index e1bd50cbbf5..fdfa0c745bb 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -14,7 +14,7 @@ #include <linux/cpu.h> #include <linux/err.h> #include <linux/hrtimer.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 1bea399a9ef..4f3886562b8 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -14,12 +14,14 @@ #include <linux/cpu.h> #include <linux/err.h> #include <linux/hrtimer.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> #include <linux/tick.h> +#include <asm/irq_regs.h> + #include "tick-internal.h" /* diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 0258d3115d5..450c04935b6 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -14,7 +14,7 @@ #include <linux/cpu.h> #include <linux/err.h> #include <linux/hrtimer.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0796c1a090c..eef557dc46c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -211,7 +211,7 @@ config SLUB_DEBUG_ON config SLUB_STATS default n bool "Enable SLUB performance statistics" - depends on SLUB + depends on SLUB && SLUB_DEBUG && SYSFS help SLUB statistics are useful to debug SLUBs allocation behavior in order find ways to optimize the allocator. This should never be diff --git a/mm/slub.c b/mm/slub.c index acc975fcc8c..7f8aaa291a4 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -837,6 +837,35 @@ static void remove_full(struct kmem_cache *s, struct page *page) spin_unlock(&n->list_lock); } +/* Tracking of the number of slabs for debugging purposes */ +static inline unsigned long slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + return atomic_long_read(&n->nr_slabs); +} + +static inline void inc_slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + /* + * May be called early in order to allocate a slab for the + * kmem_cache_node structure. Solve the chicken-egg + * dilemma by deferring the increment of the count during + * bootstrap (see early_kmem_cache_node_alloc). + */ + if (!NUMA_BUILD || n) + atomic_long_inc(&n->nr_slabs); +} +static inline void dec_slabs_node(struct kmem_cache *s, int node) +{ + struct kmem_cache_node *n = get_node(s, node); + + atomic_long_dec(&n->nr_slabs); +} + +/* Object debug checks for alloc/free paths */ static void setup_object_debug(struct kmem_cache *s, struct page *page, void *object) { @@ -1028,6 +1057,11 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize, return flags; } #define slub_debug 0 + +static inline unsigned long slabs_node(struct kmem_cache *s, int node) + { return 0; } +static inline void inc_slabs_node(struct kmem_cache *s, int node) {} +static inline void dec_slabs_node(struct kmem_cache *s, int node) {} #endif /* * Slab allocation and freeing @@ -1066,7 +1100,6 @@ static void setup_object(struct kmem_cache *s, struct page *page, static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) { struct page *page; - struct kmem_cache_node *n; void *start; void *last; void *p; @@ -1078,9 +1111,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) if (!page) goto out; - n = get_node(s, page_to_nid(page)); - if (n) - atomic_long_inc(&n->nr_slabs); + inc_slabs_node(s, page_to_nid(page)); page->slab = s; page->flags |= 1 << PG_slab; if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON | @@ -1125,6 +1156,8 @@ static void __free_slab(struct kmem_cache *s, struct page *page) NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, -pages); + __ClearPageSlab(page); + reset_page_mapcount(page); __free_pages(page, s->order); } @@ -1151,11 +1184,7 @@ static void free_slab(struct kmem_cache *s, struct page *page) static void discard_slab(struct kmem_cache *s, struct page *page) { - struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - - atomic_long_dec(&n->nr_slabs); - reset_page_mapcount(page); - __ClearPageSlab(page); + dec_slabs_node(s, page_to_nid(page)); free_slab(s, page); } @@ -1886,15 +1915,18 @@ static void init_kmem_cache_cpu(struct kmem_cache *s, c->node = 0; c->offset = s->offset / sizeof(void *); c->objsize = s->objsize; +#ifdef CONFIG_SLUB_STATS + memset(c->stat, 0, NR_SLUB_STAT_ITEMS * sizeof(unsigned)); +#endif } static void init_kmem_cache_node(struct kmem_cache_node *n) { n->nr_partial = 0; - atomic_long_set(&n->nr_slabs, 0); spin_lock_init(&n->list_lock); INIT_LIST_HEAD(&n->partial); #ifdef CONFIG_SLUB_DEBUG + atomic_long_set(&n->nr_slabs, 0); INIT_LIST_HEAD(&n->full); #endif } @@ -2063,7 +2095,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags, init_tracking(kmalloc_caches, n); #endif init_kmem_cache_node(n); - atomic_long_inc(&n->nr_slabs); + inc_slabs_node(kmalloc_caches, node); /* * lockdep requires consistent irq usage for each lock @@ -2376,7 +2408,7 @@ static inline int kmem_cache_close(struct kmem_cache *s) struct kmem_cache_node *n = get_node(s, node); n->nr_partial -= free_list(s, n, &n->partial); - if (atomic_long_read(&n->nr_slabs)) + if (slabs_node(s, node)) return 1; } free_kmem_cache_nodes(s); @@ -2409,10 +2441,6 @@ EXPORT_SYMBOL(kmem_cache_destroy); struct kmem_cache kmalloc_caches[PAGE_SHIFT + 1] __cacheline_aligned; EXPORT_SYMBOL(kmalloc_caches); -#ifdef CONFIG_ZONE_DMA -static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT + 1]; -#endif - static int __init setup_slub_min_order(char *str) { get_option(&str, &slub_min_order); @@ -2472,6 +2500,7 @@ panic: } #ifdef CONFIG_ZONE_DMA +static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT + 1]; static void sysfs_add_func(struct work_struct *w) { @@ -2688,21 +2717,6 @@ void kfree(const void *x) } EXPORT_SYMBOL(kfree); -#if defined(CONFIG_SLUB_DEBUG) || defined(CONFIG_SLABINFO) -static unsigned long count_partial(struct kmem_cache_node *n) -{ - unsigned long flags; - unsigned long x = 0; - struct page *page; - - spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->partial, lru) - x += page->inuse; - spin_unlock_irqrestore(&n->list_lock, flags); - return x; -} -#endif - /* * kmem_cache_shrink removes empty slabs from the partial lists and sorts * the remaining slabs by the number of items in use. The slabs with the @@ -2816,7 +2830,7 @@ static void slab_mem_offline_callback(void *arg) * and offline_pages() function shoudn't call this * callback. So, we must fail. */ - BUG_ON(atomic_long_read(&n->nr_slabs)); + BUG_ON(slabs_node(s, offline_node)); s->node[offline_node] = NULL; kmem_cache_free(kmalloc_caches, n); @@ -3181,6 +3195,21 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, return slab_alloc(s, gfpflags, node, caller); } +#if (defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)) || defined(CONFIG_SLABINFO) +static unsigned long count_partial(struct kmem_cache_node *n) +{ + unsigned long flags; + unsigned long x = 0; + struct page *page; + + spin_lock_irqsave(&n->list_lock, flags); + list_for_each_entry(page, &n->partial, lru) + x += page->inuse; + spin_unlock_irqrestore(&n->list_lock, flags); + return x; +} +#endif + #if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG) static int validate_slab(struct kmem_cache *s, struct page *page, unsigned long *map) @@ -3979,10 +4008,12 @@ static int show_stat(struct kmem_cache *s, char *buf, enum stat_item si) len = sprintf(buf, "%lu", sum); +#ifdef CONFIG_SMP for_each_online_cpu(cpu) { if (data[cpu] && len < PAGE_SIZE - 20) - len += sprintf(buf + len, " c%d=%u", cpu, data[cpu]); + len += sprintf(buf + len, " C%d=%u", cpu, data[cpu]); } +#endif kfree(data); return len + sprintf(buf + len, "\n"); } diff --git a/security/Kconfig b/security/Kconfig index 5dfc206748c..49b51f96489 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -113,10 +113,12 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR from userspace allocation. Keeping a user from writing to low pages can help reduce the impact of kernel NULL pointer bugs. - For most users with lots of address space a value of 65536 is - reasonable and should cause no problems. Programs which use vm86 - functionality would either need additional permissions from either - the LSM or the capabilities module or have this protection disabled. + For most ia64, ppc64 and x86 users with lots of address space + a value of 65536 is reasonable and should cause no problems. + On arm and other archs it should not be higher than 32768. + Programs which use vm86 functionality would either need additional + permissions from either the LSM or the capabilities module or have + this protection disabled. This value can be changed after boot using the /proc/sys/vm/mmap_min_addr tunable. diff --git a/security/commoncap.c b/security/commoncap.c index 06d5c9469ba..852905789ca 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -267,7 +267,7 @@ static int get_file_caps(struct linux_binprm *bprm) rc = cap_from_disk(&vcaps, bprm, rc); if (rc) printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", - __FUNCTION__, rc, bprm->filename); + __func__, rc, bprm->filename); out: dput(dentry); @@ -302,7 +302,7 @@ int cap_bprm_set_security (struct linux_binprm *bprm) ret = get_file_caps(bprm); if (ret) printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n", - __FUNCTION__, ret, bprm->filename); + __func__, ret, bprm->filename); /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise all three diff --git a/security/keys/internal.h b/security/keys/internal.h index d36d6939335..7d894ef7037 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -22,16 +22,16 @@ void no_printk(const char *fmt, ...) #ifdef __KDEBUG #define kenter(FMT, ...) \ - printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) + printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) #define kleave(FMT, ...) \ - printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) + printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) #define kdebug(FMT, ...) \ printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__) #else #define kenter(FMT, ...) \ - no_printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) + no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) #define kleave(FMT, ...) \ - no_printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) + no_printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) #define kdebug(FMT, ...) \ no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__) #endif diff --git a/security/root_plug.c b/security/root_plug.c index 870f13095bb..6112d1404c8 100644 --- a/security/root_plug.c +++ b/security/root_plug.c @@ -49,7 +49,7 @@ module_param(debug, bool, 0600); do { \ if (debug) \ printk(KERN_DEBUG "%s: %s: " fmt , \ - MY_NAME , __FUNCTION__ , \ + MY_NAME , __func__ , \ ## arg); \ } while (0) diff --git a/security/security.c b/security/security.c index b1387a6b416..9beecac933b 100644 --- a/security/security.c +++ b/security/security.c @@ -57,7 +57,7 @@ int __init security_init(void) if (verify(&dummy_security_ops)) { printk(KERN_ERR "%s could not verify " - "dummy_security_ops structure.\n", __FUNCTION__); + "dummy_security_ops structure.\n", __func__); return -EIO; } @@ -82,7 +82,7 @@ int register_security(struct security_operations *ops) { if (verify(ops)) { printk(KERN_DEBUG "%s could not verify " - "security_operations structure.\n", __FUNCTION__); + "security_operations structure.\n", __func__); return -EINVAL; } @@ -110,13 +110,13 @@ int mod_reg_security(const char *name, struct security_operations *ops) { if (verify(ops)) { printk(KERN_INFO "%s could not verify " - "security operations.\n", __FUNCTION__); + "security operations.\n", __func__); return -EINVAL; } if (ops == security_ops) { printk(KERN_INFO "%s security operations " - "already registered.\n", __FUNCTION__); + "already registered.\n", __func__); return -EINVAL; } diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 2b517d61867..a436d1cfa88 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE int "NSA SELinux maximum supported policy format version value" depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX - range 15 22 + range 15 23 default 19 help This option sets the value for the maximum policy format version diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 00afd85f1ed..d47fc5e545e 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -11,6 +11,7 @@ selinux-y := avc.o \ nlmsgtab.o \ netif.o \ netnode.o \ + netport.o \ exports.o selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 187964e88af..a4fc6e6d038 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -871,6 +871,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, int rc = 0; u32 denied; + BUG_ON(!requested); + rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass, requested); @@ -890,13 +892,14 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, denied = requested & ~(p_ae->avd.allowed); - if (!requested || denied) { - if (selinux_enforcing || (flags & AVC_STRICT)) + if (denied) { + if (flags & AVC_STRICT) rc = -EACCES; + else if (!selinux_enforcing || security_permissive_sid(ssid)) + avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, + tsid, tclass); else - if (node) - avc_update_node(AVC_CALLBACK_GRANT,requested, - ssid,tsid,tclass); + rc = -EACCES; } rcu_read_unlock(); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d39b59cf8a0..34f2d46c798 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -80,6 +80,7 @@ #include "objsec.h" #include "netif.h" #include "netnode.h" +#include "netport.h" #include "xfrm.h" #include "netlabel.h" @@ -161,8 +162,7 @@ static int task_alloc_security(struct task_struct *task) if (!tsec) return -ENOMEM; - tsec->task = task; - tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; + tsec->osid = tsec->sid = SECINITSID_UNLABELED; task->security = tsec; return 0; @@ -218,7 +218,6 @@ static int file_alloc_security(struct file *file) if (!fsec) return -ENOMEM; - fsec->file = file; fsec->sid = tsec->sid; fsec->fown_sid = tsec->sid; file->f_security = fsec; @@ -275,12 +274,11 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) if (!ssec) return -ENOMEM; - ssec->sk = sk; ssec->peer_sid = SECINITSID_UNLABELED; ssec->sid = SECINITSID_UNLABELED; sk->sk_security = ssec; - selinux_netlbl_sk_security_init(ssec, family); + selinux_netlbl_sk_security_reset(ssec, family); return 0; } @@ -324,10 +322,10 @@ enum { }; static match_table_t tokens = { - {Opt_context, "context=%s"}, - {Opt_fscontext, "fscontext=%s"}, - {Opt_defcontext, "defcontext=%s"}, - {Opt_rootcontext, "rootcontext=%s"}, + {Opt_context, CONTEXT_STR "%s"}, + {Opt_fscontext, FSCONTEXT_STR "%s"}, + {Opt_defcontext, DEFCONTEXT_STR "%s"}, + {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, {Opt_error, NULL}, }; @@ -671,7 +669,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", - __FUNCTION__, sb->s_type->name, rc); + __func__, sb->s_type->name, rc); goto out; } @@ -1137,7 +1135,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent } if (!dentry) { printk(KERN_WARNING "%s: no dentry for dev=%s " - "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id, + "ino=%ld\n", __func__, inode->i_sb->s_id, inode->i_ino); goto out_unlock; } @@ -1175,7 +1173,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent if (rc < 0) { if (rc != -ENODATA) { printk(KERN_WARNING "%s: getxattr returned " - "%d for dev=%s ino=%ld\n", __FUNCTION__, + "%d for dev=%s ino=%ld\n", __func__, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); goto out_unlock; @@ -1190,7 +1188,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent if (rc) { printk(KERN_WARNING "%s: context_to_sid(%s) " "returned %d for dev=%s ino=%ld\n", - __FUNCTION__, context, -rc, + __func__, context, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); /* Leave with the unlabeled SID */ @@ -1618,6 +1616,35 @@ static inline u32 file_mask_to_av(int mode, int mask) return av; } +/* + * Convert a file mask to an access vector and include the correct open + * open permission. + */ +static inline u32 open_file_mask_to_av(int mode, int mask) +{ + u32 av = file_mask_to_av(mode, mask); + + if (selinux_policycap_openperm) { + /* + * lnk files and socks do not really have an 'open' + */ + if (S_ISREG(mode)) + av |= FILE__OPEN; + else if (S_ISCHR(mode)) + av |= CHR_FILE__OPEN; + else if (S_ISBLK(mode)) + av |= BLK_FILE__OPEN; + else if (S_ISFIFO(mode)) + av |= FIFO_FILE__OPEN; + else if (S_ISDIR(mode)) + av |= DIR__OPEN; + else + printk(KERN_ERR "SELinux: WARNING: inside open_file_to_av " + "with unknown mode:%x\n", mode); + } + return av; +} + /* Convert a Linux file to an access vector. */ static inline u32 file_to_av(struct file *file) { @@ -1645,19 +1672,13 @@ static inline u32 file_to_av(struct file *file) static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) { - struct task_security_struct *psec = parent->security; - struct task_security_struct *csec = child->security; int rc; rc = secondary_ops->ptrace(parent,child); if (rc) return rc; - rc = task_has_perm(parent, child, PROCESS__PTRACE); - /* Save the SID of the tracing process for later use in apply_creds. */ - if (!(child->ptrace & PT_PTRACED) && !rc) - csec->ptrace_sid = psec->sid; - return rc; + return task_has_perm(parent, child, PROCESS__PTRACE); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, @@ -1879,6 +1900,22 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) return __vm_enough_memory(mm, pages, cap_sys_admin); } +/** + * task_tracer_task - return the task that is tracing the given task + * @task: task to consider + * + * Returns NULL if noone is tracing @task, or the &struct task_struct + * pointer to its tracer. + * + * Must be called under rcu_read_lock(). + */ +static struct task_struct *task_tracer_task(struct task_struct *task) +{ + if (task->ptrace & PT_PTRACED) + return rcu_dereference(task->parent); + return NULL; +} + /* binprm security operations */ static int selinux_bprm_alloc_security(struct linux_binprm *bprm) @@ -1889,7 +1926,6 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm) if (!bsec) return -ENOMEM; - bsec->bprm = bprm; bsec->sid = SECINITSID_UNLABELED; bsec->set = 0; @@ -2126,12 +2162,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and kill. */ if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - rc = avc_has_perm(tsec->ptrace_sid, sid, - SECCLASS_PROCESS, PROCESS__PTRACE, - NULL); - if (rc) { - bsec->unsafe = 1; - return; + struct task_struct *tracer; + struct task_security_struct *sec; + u32 ptsid = 0; + + rcu_read_lock(); + tracer = task_tracer_task(current); + if (likely(tracer != NULL)) { + sec = tracer->security; + ptsid = sec->sid; + } + rcu_read_unlock(); + + if (ptsid != 0) { + rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, + PROCESS__PTRACE, NULL); + if (rc) { + bsec->unsafe = 1; + return; + } } } tsec->sid = sid; @@ -2239,10 +2288,10 @@ static inline int match_prefix(char *prefix, int plen, char *option, int olen) static inline int selinux_option(char *option, int len) { - return (match_prefix("context=", sizeof("context=")-1, option, len) || - match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || - match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || - match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); + return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || + match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || + match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || + match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len)); } static inline void take_option(char **to, char *from, int *first, int len) @@ -2412,7 +2461,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, printk(KERN_WARNING "%s: " "security_transition_sid failed, rc=%d (dev=%s " "ino=%ld)\n", - __FUNCTION__, + __func__, -rc, inode->i_sb->s_id, inode->i_ino); return rc; } @@ -2536,7 +2585,7 @@ static int selinux_inode_permission(struct inode *inode, int mask, } return inode_has_perm(current, inode, - file_mask_to_av(inode->i_mode, mask), NULL); + open_file_mask_to_av(inode->i_mode, mask), NULL); } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) @@ -2646,7 +2695,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, rc = security_context_to_sid(value, size, &newsid); if (rc) { printk(KERN_WARNING "%s: unable to obtain SID for context " - "%s, rc=%d\n", __FUNCTION__, (char*)value, -rc); + "%s, rc=%d\n", __func__, (char *)value, -rc); return; } @@ -3087,11 +3136,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk) tsec2->keycreate_sid = tsec1->keycreate_sid; tsec2->sockcreate_sid = tsec1->sockcreate_sid; - /* Retain ptracer SID across fork, if any. - This will be reset by the ptrace hook upon any - subsequent ptrace_attach operations. */ - tsec2->ptrace_sid = tsec1->ptrace_sid; - return 0; } @@ -3627,10 +3671,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in inet_get_local_port_range(&low, &high); if (snum < max(PROT_SOCK, low) || snum > high) { - err = security_port_sid(sk->sk_family, - sk->sk_type, - sk->sk_protocol, snum, - &sid); + err = sel_netport_sid(sk->sk_protocol, + snum, &sid); if (err) goto out; AVC_AUDIT_DATA_INIT(&ad,NET); @@ -3718,8 +3760,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, snum = ntohs(addr6->sin6_port); } - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); + err = sel_netport_sid(sk->sk_protocol, snum, &sid); if (err) goto out; @@ -3950,9 +3991,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, if (!recv_perm) return 0; - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, ntohs(ad->u.net.sport), - &port_sid); + err = sel_netport_sid(sk->sk_protocol, + ntohs(ad->u.net.sport), &port_sid); if (unlikely(err)) { printk(KERN_WARNING "SELinux: failure in" @@ -4139,7 +4179,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) newssec->peer_sid = ssec->peer_sid; newssec->sclass = ssec->sclass; - selinux_netlbl_sk_security_clone(ssec, newssec); + selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); } static void selinux_sk_getsecid(struct sock *sk, u32 *secid) @@ -4373,9 +4413,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, if (send_perm != 0) return 0; - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, ntohs(ad->u.net.dport), - &port_sid); + err = sel_netport_sid(sk->sk_protocol, + ntohs(ad->u.net.dport), &port_sid); if (unlikely(err)) { printk(KERN_WARNING "SELinux: failure in" @@ -4561,7 +4600,6 @@ static int ipc_alloc_security(struct task_struct *task, return -ENOMEM; isec->sclass = sclass; - isec->ipc_perm = perm; isec->sid = tsec->sid; perm->security = isec; @@ -4583,7 +4621,6 @@ static int msg_msg_alloc_security(struct msg_msg *msg) if (!msec) return -ENOMEM; - msec->msg = msg; msec->sid = SECINITSID_UNLABELED; msg->security = msec; @@ -4994,14 +5031,14 @@ static int selinux_register_security (const char *name, struct security_operatio { if (secondary_ops != original_ops) { printk(KERN_ERR "%s: There is already a secondary security " - "module registered.\n", __FUNCTION__); + "module registered.\n", __func__); return -EINVAL; } secondary_ops = ops; printk(KERN_INFO "%s: Registering secondary module %s\n", - __FUNCTION__, + __func__, name); return 0; @@ -5057,6 +5094,7 @@ static int selinux_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { struct task_security_struct *tsec; + struct task_struct *tracer; u32 sid = 0; int error; char *str = value; @@ -5145,18 +5183,24 @@ static int selinux_setprocattr(struct task_struct *p, /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ task_lock(p); - if (p->ptrace & PT_PTRACED) { - error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, + rcu_read_lock(); + tracer = task_tracer_task(p); + if (tracer != NULL) { + struct task_security_struct *ptsec = tracer->security; + u32 ptsid = ptsec->sid; + rcu_read_unlock(); + error = avc_has_perm_noaudit(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, 0, &avd); if (!error) tsec->sid = sid; task_unlock(p); - avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, + avc_audit(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd, error, NULL); if (error) return error; } else { + rcu_read_unlock(); tsec->sid = sid; task_unlock(p); } @@ -5194,7 +5238,6 @@ static int selinux_key_alloc(struct key *k, struct task_struct *tsk, if (!ksec) return -ENOMEM; - ksec->obj = k; if (tsec->keycreate_sid) ksec->sid = tsec->keycreate_sid; else @@ -5631,5 +5674,3 @@ int selinux_disable(void) return 0; } #endif - - diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index d5696690d3a..1223b4ff9be 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -14,12 +14,17 @@ S_(SECCLASS_DIR, DIR__REPARENT, "reparent") S_(SECCLASS_DIR, DIR__SEARCH, "search") S_(SECCLASS_DIR, DIR__RMDIR, "rmdir") + S_(SECCLASS_DIR, DIR__OPEN, "open") S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans") S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint") S_(SECCLASS_FILE, FILE__EXECMOD, "execmod") + S_(SECCLASS_FILE, FILE__OPEN, "open") S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans") S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint") S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod") + S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open") + S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open") + S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open") S_(SECCLASS_FD, FD__USE, "use") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 75b41311ab8..c4c51165c50 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -79,6 +79,7 @@ #define DIR__REPARENT 0x00080000UL #define DIR__SEARCH 0x00100000UL #define DIR__RMDIR 0x00200000UL +#define DIR__OPEN 0x00400000UL #define FILE__IOCTL 0x00000001UL #define FILE__READ 0x00000002UL #define FILE__WRITE 0x00000004UL @@ -99,6 +100,7 @@ #define FILE__EXECUTE_NO_TRANS 0x00020000UL #define FILE__ENTRYPOINT 0x00040000UL #define FILE__EXECMOD 0x00080000UL +#define FILE__OPEN 0x00100000UL #define LNK_FILE__IOCTL 0x00000001UL #define LNK_FILE__READ 0x00000002UL #define LNK_FILE__WRITE 0x00000004UL @@ -136,6 +138,7 @@ #define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL #define CHR_FILE__ENTRYPOINT 0x00040000UL #define CHR_FILE__EXECMOD 0x00080000UL +#define CHR_FILE__OPEN 0x00100000UL #define BLK_FILE__IOCTL 0x00000001UL #define BLK_FILE__READ 0x00000002UL #define BLK_FILE__WRITE 0x00000004UL @@ -153,6 +156,7 @@ #define BLK_FILE__SWAPON 0x00004000UL #define BLK_FILE__QUOTAON 0x00008000UL #define BLK_FILE__MOUNTON 0x00010000UL +#define BLK_FILE__OPEN 0x00020000UL #define SOCK_FILE__IOCTL 0x00000001UL #define SOCK_FILE__READ 0x00000002UL #define SOCK_FILE__WRITE 0x00000004UL @@ -187,6 +191,7 @@ #define FIFO_FILE__SWAPON 0x00004000UL #define FIFO_FILE__QUOTAON 0x00008000UL #define FIFO_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__OPEN 0x00020000UL #define FD__USE 0x00000001UL #define SOCKET__IOCTL 0x00000001UL #define SOCKET__READ 0x00000002UL diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 00a2809c850..9a9e7cd9a37 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -41,10 +41,6 @@ void selinux_netlbl_cache_invalidate(void); void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, int family); -void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, - int family); -void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, - struct sk_security_struct *newssec); int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, @@ -73,18 +69,6 @@ static inline void selinux_netlbl_sk_security_reset( { return; } -static inline void selinux_netlbl_sk_security_init( - struct sk_security_struct *ssec, - int family) -{ - return; -} -static inline void selinux_netlbl_sk_security_clone( - struct sk_security_struct *ssec, - struct sk_security_struct *newssec) -{ - return; -} static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h new file mode 100644 index 00000000000..8991752eaf9 --- /dev/null +++ b/security/selinux/include/netport.h @@ -0,0 +1,31 @@ +/* + * Network port table + * + * SELinux must keep a mapping of network ports to labels/SIDs. This + * mapping is maintained as part of the normal policy but a fast cache is + * needed to reduce the lookup overhead. + * + * Author: Paul Moore <paul.moore@hp.com> + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 + * + * 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 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. + * + */ + +#ifndef _SELINUX_NETPORT_H +#define _SELINUX_NETPORT_H + +int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); + +#endif diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c6c2bb4ebac..300b61bad7b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -28,14 +28,12 @@ #include "avc.h" struct task_security_struct { - struct task_struct *task; /* back pointer to task object */ u32 osid; /* SID prior to last execve */ u32 sid; /* current SID */ u32 exec_sid; /* exec SID */ u32 create_sid; /* fscreate SID */ u32 keycreate_sid; /* keycreate SID */ u32 sockcreate_sid; /* fscreate SID */ - u32 ptrace_sid; /* SID of ptrace parent */ }; struct inode_security_struct { @@ -50,7 +48,6 @@ struct inode_security_struct { }; struct file_security_struct { - struct file *file; /* back pointer to file object */ u32 sid; /* SID of open file description */ u32 fown_sid; /* SID of file owner (for SIGIO) */ u32 isid; /* SID of inode at the time of file open */ @@ -73,18 +70,15 @@ struct superblock_security_struct { }; struct msg_security_struct { - struct msg_msg *msg; /* back pointer */ u32 sid; /* SID of message */ }; struct ipc_security_struct { - struct kern_ipc_perm *ipc_perm; /* back pointer */ u16 sclass; /* security class of this object */ u32 sid; /* SID of IPC resource */ }; struct bprm_security_struct { - struct linux_binprm *bprm; /* back pointer to bprm object */ u32 sid; /* SID for transformed process */ unsigned char set; @@ -109,8 +103,13 @@ struct netnode_security_struct { u16 family; /* address family */ }; +struct netport_security_struct { + u32 sid; /* SID for this node */ + u16 port; /* port number */ + u8 protocol; /* transport protocol */ +}; + struct sk_security_struct { - struct sock *sk; /* back pointer to sk object */ u32 sid; /* SID of this object */ u32 peer_sid; /* SID of peer */ u16 sclass; /* sock security class */ @@ -120,12 +119,10 @@ struct sk_security_struct { NLBL_REQUIRE, NLBL_LABELED, } nlbl_state; - spinlock_t nlbl_lock; /* protects nlbl_state */ #endif }; struct key_security_struct { - struct key *obj; /* back pointer */ u32 sid; /* SID of key */ }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 44e12ec8809..1904c462a60 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -26,13 +26,14 @@ #define POLICYDB_VERSION_AVTAB 20 #define POLICYDB_VERSION_RANGETRANS 21 #define POLICYDB_VERSION_POLCAP 22 +#define POLICYDB_VERSION_PERMISSIVE 23 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE #endif #define CONTEXT_MNT 0x01 @@ -40,6 +41,11 @@ #define ROOTCONTEXT_MNT 0x04 #define DEFCONTEXT_MNT 0x08 +#define CONTEXT_STR "context=" +#define FSCONTEXT_STR "fscontext=" +#define ROOTCONTEXT_STR "rootcontext=" +#define DEFCONTEXT_STR "defcontext=" + struct netlbl_lsm_secattr; extern int selinux_enabled; @@ -48,11 +54,13 @@ extern int selinux_mls_enabled; /* Policy capabilities */ enum { POLICYDB_CAPABILITY_NETPEER, + POLICYDB_CAPABILITY_OPENPERM, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) extern int selinux_policycap_netpeer; +extern int selinux_policycap_openperm; int security_load_policy(void * data, size_t len); @@ -67,6 +75,8 @@ struct av_decision { u32 seqno; }; +int security_permissive_sid(u32 sid); + int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd); @@ -92,8 +102,7 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len, int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); -int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port, - u32 *out_sid); +int security_port_sid(u8 protocol, u16 port, u32 *out_sid); int security_netif_sid(char *name, u32 *if_sid); diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 0fa2be4149e..e8ee91ac12e 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -34,6 +34,7 @@ #include "objsec.h" #include "security.h" +#include "netlabel.h" /** * selinux_netlbl_sidlookup_cached - Cache a SID lookup @@ -69,9 +70,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, * * Description: * Attempt to label a socket using the NetLabel mechanism using the given - * SID. Returns zero values on success, negative values on failure. The - * caller is responsibile for calling rcu_read_lock() before calling this - * this function and rcu_read_unlock() after this function returns. + * SID. Returns zero values on success, negative values on failure. * */ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) @@ -86,11 +85,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) if (rc != 0) goto sock_setsid_return; rc = netlbl_sock_setattr(sk, &secattr); - if (rc == 0) { - spin_lock_bh(&sksec->nlbl_lock); + if (rc == 0) sksec->nlbl_state = NLBL_LABELED; - spin_unlock_bh(&sksec->nlbl_lock); - } sock_setsid_return: netlbl_secattr_destroy(&secattr); @@ -129,45 +125,6 @@ void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, } /** - * selinux_netlbl_sk_security_init - Setup the NetLabel fields - * @ssec: the sk_security_struct - * @family: the socket family - * - * Description: - * Called when a new sk_security_struct is allocated to initialize the NetLabel - * fields. - * - */ -void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, - int family) -{ - /* No locking needed, we are the only one who has access to ssec */ - selinux_netlbl_sk_security_reset(ssec, family); - spin_lock_init(&ssec->nlbl_lock); -} - -/** - * selinux_netlbl_sk_security_clone - Copy the NetLabel fields - * @ssec: the original sk_security_struct - * @newssec: the cloned sk_security_struct - * - * Description: - * Clone the NetLabel specific sk_security_struct fields from @ssec to - * @newssec. - * - */ -void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, - struct sk_security_struct *newssec) -{ - /* We don't need to take newssec->nlbl_lock because we are the only - * thread with access to newssec, but we do need to take the RCU read - * lock as other threads could have access to ssec */ - rcu_read_lock(); - selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); - rcu_read_unlock(); -} - -/** * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel * @skb: the packet * @family: protocol family @@ -221,12 +178,8 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) struct netlbl_lsm_secattr secattr; u32 nlbl_peer_sid; - rcu_read_lock(); - - if (sksec->nlbl_state != NLBL_REQUIRE) { - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) return; - } netlbl_secattr_init(&secattr); if (netlbl_sock_getattr(sk, &secattr) == 0 && @@ -239,8 +192,6 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) * here we will pick up the pieces in later calls to * selinux_netlbl_inode_permission(). */ selinux_netlbl_sock_setsid(sk, sksec->sid); - - rcu_read_unlock(); } /** @@ -254,16 +205,13 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) */ int selinux_netlbl_socket_post_create(struct socket *sock) { - int rc = 0; struct sock *sk = sock->sk; struct sk_security_struct *sksec = sk->sk_security; - rcu_read_lock(); - if (sksec->nlbl_state == NLBL_REQUIRE) - rc = selinux_netlbl_sock_setsid(sk, sksec->sid); - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) + return 0; - return rc; + return selinux_netlbl_sock_setsid(sk, sksec->sid); } /** @@ -288,21 +236,21 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) if (!S_ISSOCK(inode->i_mode) || ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) return 0; + sock = SOCKET_I(inode); sk = sock->sk; sksec = sk->sk_security; - - rcu_read_lock(); - if (sksec->nlbl_state != NLBL_REQUIRE) { - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) return 0; - } + local_bh_disable(); bh_lock_sock_nested(sk); - rc = selinux_netlbl_sock_setsid(sk, sksec->sid); + if (likely(sksec->nlbl_state == NLBL_REQUIRE)) + rc = selinux_netlbl_sock_setsid(sk, sksec->sid); + else + rc = 0; bh_unlock_sock(sk); local_bh_enable(); - rcu_read_unlock(); return rc; } @@ -385,7 +333,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr secattr; - rcu_read_lock(); if (level == IPPROTO_IP && optname == IP_OPTIONS && sksec->nlbl_state == NLBL_LABELED) { netlbl_secattr_init(&secattr); @@ -396,7 +343,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, rc = -EACCES; netlbl_secattr_destroy(&secattr); } - rcu_read_unlock(); return rc; } diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index b59871d74da..6214a7a7314 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -89,7 +89,7 @@ out: nlmsg_failure: kfree_skb(skb); oom: - printk(KERN_ERR "SELinux: OOM in %s\n", __FUNCTION__); + printk(KERN_ERR "SELinux: OOM in %s\n", __func__); goto out; } diff --git a/security/selinux/netport.c b/security/selinux/netport.c new file mode 100644 index 00000000000..68ede3c498a --- /dev/null +++ b/security/selinux/netport.c @@ -0,0 +1,286 @@ +/* + * Network port table + * + * SELinux must keep a mapping of network ports to labels/SIDs. This + * mapping is maintained as part of the normal policy but a fast cache is + * needed to reduce the lookup overhead. + * + * Author: Paul Moore <paul.moore@hp.com> + * + * This code is heavily based on the "netif" concept originally developed by + * James Morris <jmorris@redhat.com> + * (see security/selinux/netif.c for more information) + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 + * + * 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 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. + * + */ + +#include <linux/types.h> +#include <linux/rcupdate.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/in.h> +#include <linux/in6.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <asm/bug.h> + +#include "netport.h" +#include "objsec.h" + +#define SEL_NETPORT_HASH_SIZE 256 +#define SEL_NETPORT_HASH_BKT_LIMIT 16 + +struct sel_netport_bkt { + int size; + struct list_head list; +}; + +struct sel_netport { + struct netport_security_struct psec; + + struct list_head list; + struct rcu_head rcu; +}; + +/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason + * for this is that I suspect most users will not make heavy use of both + * address families at the same time so one table will usually end up wasted, + * if this becomes a problem we can always add a hash table for each address + * family later */ + +static LIST_HEAD(sel_netport_list); +static DEFINE_SPINLOCK(sel_netport_lock); +static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; + +/** + * sel_netport_free - Frees a port entry + * @p: the entry's RCU field + * + * Description: + * This function is designed to be used as a callback to the call_rcu() + * function so that memory allocated to a hash table port entry can be + * released safely. + * + */ +static void sel_netport_free(struct rcu_head *p) +{ + struct sel_netport *port = container_of(p, struct sel_netport, rcu); + kfree(port); +} + +/** + * sel_netport_hashfn - Hashing function for the port table + * @pnum: port number + * + * Description: + * This is the hashing function for the port table, it returns the bucket + * number for the given port. + * + */ +static unsigned int sel_netport_hashfn(u16 pnum) +{ + return (pnum & (SEL_NETPORT_HASH_SIZE - 1)); +} + +/** + * sel_netport_find - Search for a port record + * @protocol: protocol + * @port: pnum + * + * Description: + * Search the network port table and return the matching record. If an entry + * can not be found in the table return NULL. + * + */ +static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) +{ + unsigned int idx; + struct sel_netport *port; + + idx = sel_netport_hashfn(pnum); + list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) + if (port->psec.port == pnum && + port->psec.protocol == protocol) + return port; + + return NULL; +} + +/** + * sel_netport_insert - Insert a new port into the table + * @port: the new port record + * + * Description: + * Add a new port record to the network address hash table. Returns zero on + * success, negative values on failure. + * + */ +static int sel_netport_insert(struct sel_netport *port) +{ + unsigned int idx; + + /* we need to impose a limit on the growth of the hash table so check + * this bucket to make sure it is within the specified bounds */ + idx = sel_netport_hashfn(port->psec.port); + list_add_rcu(&port->list, &sel_netport_hash[idx].list); + if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { + struct sel_netport *tail; + tail = list_entry(port->list.prev, struct sel_netport, list); + list_del_rcu(port->list.prev); + call_rcu(&tail->rcu, sel_netport_free); + } else + sel_netport_hash[idx].size++; + + return 0; +} + +/** + * sel_netport_sid_slow - Lookup the SID of a network address using the policy + * @protocol: protocol + * @pnum: port + * @sid: port SID + * + * Description: + * This function determines the SID of a network port by quering the security + * policy. The result is added to the network port table to speedup future + * queries. Returns zero on success, negative values on failure. + * + */ +static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) +{ + int ret; + struct sel_netport *port; + struct sel_netport *new = NULL; + + spin_lock_bh(&sel_netport_lock); + port = sel_netport_find(protocol, pnum); + if (port != NULL) { + *sid = port->psec.sid; + ret = 0; + goto out; + } + new = kzalloc(sizeof(*new), GFP_ATOMIC); + if (new == NULL) { + ret = -ENOMEM; + goto out; + } + ret = security_port_sid(protocol, pnum, &new->psec.sid); + if (ret != 0) + goto out; + new->psec.port = pnum; + new->psec.protocol = protocol; + ret = sel_netport_insert(new); + if (ret != 0) + goto out; + *sid = new->psec.sid; + +out: + spin_unlock_bh(&sel_netport_lock); + if (unlikely(ret)) { + printk(KERN_WARNING + "SELinux: failure in sel_netport_sid_slow()," + " unable to determine network port label\n"); + kfree(new); + } + return ret; +} + +/** + * sel_netport_sid - Lookup the SID of a network port + * @protocol: protocol + * @pnum: port + * @sid: port SID + * + * Description: + * This function determines the SID of a network port using the fastest method + * possible. First the port table is queried, but if an entry can't be found + * then the policy is queried and the result is added to the table to speedup + * future queries. Returns zero on success, negative values on failure. + * + */ +int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) +{ + struct sel_netport *port; + + rcu_read_lock(); + port = sel_netport_find(protocol, pnum); + if (port != NULL) { + *sid = port->psec.sid; + rcu_read_unlock(); + return 0; + } + rcu_read_unlock(); + + return sel_netport_sid_slow(protocol, pnum, sid); +} + +/** + * sel_netport_flush - Flush the entire network port table + * + * Description: + * Remove all entries from the network address table. + * + */ +static void sel_netport_flush(void) +{ + unsigned int idx; + struct sel_netport *port; + + spin_lock_bh(&sel_netport_lock); + for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { + list_for_each_entry(port, &sel_netport_hash[idx].list, list) { + list_del_rcu(&port->list); + call_rcu(&port->rcu, sel_netport_free); + } + sel_netport_hash[idx].size = 0; + } + spin_unlock_bh(&sel_netport_lock); +} + +static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid, + u16 class, u32 perms, u32 *retained) +{ + if (event == AVC_CALLBACK_RESET) { + sel_netport_flush(); + synchronize_net(); + } + return 0; +} + +static __init int sel_netport_init(void) +{ + int iter; + int ret; + + if (!selinux_enabled) + return 0; + + for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) { + INIT_LIST_HEAD(&sel_netport_hash[iter].list); + sel_netport_hash[iter].size = 0; + } + + ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + if (ret != 0) + panic("avc_add_callback() failed, error %d\n", ret); + + return ret; +} + +__initcall(sel_netport_init); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 0341567665b..26fabad0976 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -42,7 +42,8 @@ /* Policy capability filenames */ static char *policycap_names[] = { - "network_peer_controls" + "network_peer_controls", + "open_perms" }; unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; @@ -391,7 +392,7 @@ static ssize_t sel_write_context(struct file * file, char *buf, size_t size) if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + "max\n", __func__, len); length = -ERANGE; goto out; } @@ -644,7 +645,7 @@ static ssize_t sel_write_create(struct file * file, char *buf, size_t size) if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + "max\n", __func__, len); length = -ERANGE; goto out3; } @@ -821,7 +822,7 @@ static ssize_t sel_write_member(struct file * file, char *buf, size_t size) if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + "max\n", __func__, len); length = -ERANGE; goto out3; } @@ -1760,7 +1761,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) out: return ret; err: - printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); + printk(KERN_ERR "%s: failed while creating inodes\n", __func__); goto out; } diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index cd10e27fc9e..916e73a18bc 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -280,8 +280,8 @@ int avtab_alloc(struct avtab *h, u32 nrules) h->nel = 0; h->nslot = nslot; h->mask = mask; - printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. " - "Num of rules:%d\n", h->nslot, nrules); + printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n", + h->nslot, nrules); return 0; } @@ -345,18 +345,18 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, if (vers < POLICYDB_VERSION_AVTAB) { rc = next_entry(buf32, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } items2 = le32_to_cpu(buf32[0]); if (items2 > ARRAY_SIZE(buf32)) { - printk(KERN_ERR "security: avtab: entry overflow\n"); + printk(KERN_ERR "SELinux: avtab: entry overflow\n"); return -1; } rc = next_entry(buf32, fp, sizeof(u32)*items2); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } items = 0; @@ -364,19 +364,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, val = le32_to_cpu(buf32[items++]); key.source_type = (u16)val; if (key.source_type != val) { - printk("security: avtab: truncated source type\n"); + printk("SELinux: avtab: truncated source type\n"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_type = (u16)val; if (key.target_type != val) { - printk("security: avtab: truncated target type\n"); + printk("SELinux: avtab: truncated target type\n"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_class = (u16)val; if (key.target_class != val) { - printk("security: avtab: truncated target class\n"); + printk("SELinux: avtab: truncated target class\n"); return -1; } @@ -384,12 +384,12 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; if (!(val & (AVTAB_AV | AVTAB_TYPE))) { - printk("security: avtab: null entry\n"); + printk("SELinux: avtab: null entry\n"); return -1; } if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { - printk("security: avtab: entry has both access vectors and types\n"); + printk("SELinux: avtab: entry has both access vectors and types\n"); return -1; } @@ -403,7 +403,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, } if (items != items2) { - printk("security: avtab: entry only had %d items, expected %d\n", items2, items); + printk("SELinux: avtab: entry only had %d items, expected %d\n", items2, items); return -1; } return 0; @@ -411,7 +411,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, rc = next_entry(buf16, fp, sizeof(u16)*4); if (rc < 0) { - printk("security: avtab: truncated entry\n"); + printk("SELinux: avtab: truncated entry\n"); return -1; } @@ -424,7 +424,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, if (!policydb_type_isvalid(pol, key.source_type) || !policydb_type_isvalid(pol, key.target_type) || !policydb_class_isvalid(pol, key.target_class)) { - printk(KERN_WARNING "security: avtab: invalid type or class\n"); + printk(KERN_WARNING "SELinux: avtab: invalid type or class\n"); return -1; } @@ -435,19 +435,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, } if (!set || set > 1) { printk(KERN_WARNING - "security: avtab: more than one specifier\n"); + "SELinux: avtab: more than one specifier\n"); return -1; } rc = next_entry(buf32, fp, sizeof(u32)); if (rc < 0) { - printk("security: avtab: truncated entry\n"); + printk("SELinux: avtab: truncated entry\n"); return -1; } datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && !policydb_type_isvalid(pol, datum.data)) { - printk(KERN_WARNING "security: avtab: invalid type\n"); + printk(KERN_WARNING "SELinux: avtab: invalid type\n"); return -1; } return insertf(a, &key, &datum, p); @@ -468,12 +468,12 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) rc = next_entry(buf, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated table\n"); + printk(KERN_ERR "SELinux: avtab: truncated table\n"); goto bad; } nel = le32_to_cpu(buf[0]); if (!nel) { - printk(KERN_ERR "security: avtab: table is empty\n"); + printk(KERN_ERR "SELinux: avtab: table is empty\n"); rc = -EINVAL; goto bad; } @@ -486,9 +486,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL); if (rc) { if (rc == -ENOMEM) - printk(KERN_ERR "security: avtab: out of memory\n"); + printk(KERN_ERR "SELinux: avtab: out of memory\n"); else if (rc == -EEXIST) - printk(KERN_ERR "security: avtab: duplicate entry\n"); + printk(KERN_ERR "SELinux: avtab: duplicate entry\n"); else rc = -EINVAL; goto bad; diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 50ad85d4b77..a996cf1d378 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -96,7 +96,7 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node) if (new_state != node->cur_state) { node->cur_state = new_state; if (new_state == -1) - printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n"); + printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); /* turn the rules on or off */ for (cur = node->true_list; cur != NULL; cur = cur->next) { if (new_state <= 0) { @@ -276,7 +276,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum */ if (k->specified & AVTAB_TYPE) { if (avtab_search(&p->te_avtab, k)) { - printk("security: type rule already exists outside of a conditional."); + printk("SELinux: type rule already exists outside of a conditional."); goto err; } /* @@ -291,7 +291,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum node_ptr = avtab_search_node(&p->te_cond_avtab, k); if (node_ptr) { if (avtab_search_node_next(node_ptr, k->specified)) { - printk("security: too many conflicting type rules."); + printk("SELinux: too many conflicting type rules."); goto err; } found = 0; @@ -302,13 +302,13 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum } } if (!found) { - printk("security: conflicting type rules.\n"); + printk("SELinux: conflicting type rules.\n"); goto err; } } } else { if (avtab_search(&p->te_cond_avtab, k)) { - printk("security: conflicting type rules when adding type rule for true.\n"); + printk("SELinux: conflicting type rules when adding type rule for true.\n"); goto err; } } @@ -316,7 +316,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); if (!node_ptr) { - printk("security: could not insert rule."); + printk("SELinux: could not insert rule."); goto err; } @@ -376,12 +376,12 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list * static int expr_isvalid(struct policydb *p, struct cond_expr *expr) { if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { - printk("security: conditional expressions uses unknown operator.\n"); + printk("SELinux: conditional expressions uses unknown operator.\n"); return 0; } if (expr->bool > p->p_bools.nprim) { - printk("security: conditional expressions uses unknown bool.\n"); + printk("SELinux: conditional expressions uses unknown bool.\n"); return 0; } return 1; diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 920b5e36a1a..e499af474b3 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -364,7 +364,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) count = le32_to_cpu(buf[2]); if (mapunit != sizeof(u64) * 8) { - printk(KERN_ERR "security: ebitmap: map size %u does not " + printk(KERN_ERR "SELinux: ebitmap: map size %u does not " "match my size %Zd (high bit was %d)\n", mapunit, sizeof(u64) * 8, e->highbit); goto bad; @@ -382,19 +382,19 @@ int ebitmap_read(struct ebitmap *e, void *fp) for (i = 0; i < count; i++) { rc = next_entry(&startbit, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: ebitmap: truncated map\n"); + printk(KERN_ERR "SELinux: ebitmap: truncated map\n"); goto bad; } startbit = le32_to_cpu(startbit); if (startbit & (mapunit - 1)) { - printk(KERN_ERR "security: ebitmap start bit (%d) is " + printk(KERN_ERR "SELinux: ebitmap start bit (%d) is " "not a multiple of the map unit size (%u)\n", startbit, mapunit); goto bad; } if (startbit > e->highbit - mapunit) { - printk(KERN_ERR "security: ebitmap start bit (%d) is " + printk(KERN_ERR "SELinux: ebitmap start bit (%d) is " "beyond the end of the bitmap (%u)\n", startbit, (e->highbit - mapunit)); goto bad; @@ -405,7 +405,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { printk(KERN_ERR - "security: ebitmap: out of memory\n"); + "SELinux: ebitmap: out of memory\n"); rc = -ENOMEM; goto bad; } @@ -418,7 +418,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) } n = tmp; } else if (startbit <= n->startbit) { - printk(KERN_ERR "security: ebitmap: start bit %d" + printk(KERN_ERR "SELinux: ebitmap: start bit %d" " comes after start bit %d\n", startbit, n->startbit); goto bad; @@ -426,7 +426,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) rc = next_entry(&map, fp, sizeof(u64)); if (rc < 0) { - printk(KERN_ERR "security: ebitmap: truncated map\n"); + printk(KERN_ERR "SELinux: ebitmap: truncated map\n"); goto bad; } map = le64_to_cpu(map); diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index bd7d6a00342..6bdb0ff6a92 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -111,6 +111,11 @@ static struct policydb_compat_info policydb_compat[] = { .version = POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_PERMISSIVE, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, } }; @@ -194,6 +199,7 @@ static int policydb_init(struct policydb *p) goto out_free_symtab; ebitmap_init(&p->policycaps); + ebitmap_init(&p->permissive_map); out: return rc; @@ -401,14 +407,14 @@ static int policydb_index_others(struct policydb *p) { int i, rc = 0; - printk(KERN_DEBUG "security: %d users, %d roles, %d types, %d bools", + printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); if (selinux_mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); - printk(KERN_DEBUG "security: %d classes, %d rules\n", + printk(KERN_DEBUG "SELinux: %d classes, %d rules\n", p->p_classes.nprim, p->te_avtab.nel); #ifdef DEBUG_HASHES @@ -687,6 +693,7 @@ void policydb_destroy(struct policydb *p) kfree(p->type_attr_map); kfree(p->undefined_perms); ebitmap_destroy(&p->policycaps); + ebitmap_destroy(&p->permissive_map); return; } @@ -702,20 +709,20 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) rc = sidtab_init(s); if (rc) { - printk(KERN_ERR "security: out of memory on SID table init\n"); + printk(KERN_ERR "SELinux: out of memory on SID table init\n"); goto out; } head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { if (!c->context[0].user) { - printk(KERN_ERR "security: SID %s was never " + printk(KERN_ERR "SELinux: SID %s was never " "defined.\n", c->u.name); rc = -EINVAL; goto out; } if (sidtab_insert(s, c->sid[0], &c->context[0])) { - printk(KERN_ERR "security: unable to load initial " + printk(KERN_ERR "SELinux: unable to load initial " "SID %s.\n", c->u.name); rc = -EINVAL; goto out; @@ -809,13 +816,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) items = le32_to_cpu(buf[0]); if (items > ARRAY_SIZE(buf)) { - printk(KERN_ERR "security: mls: range overflow\n"); + printk(KERN_ERR "SELinux: mls: range overflow\n"); rc = -EINVAL; goto out; } rc = next_entry(buf, fp, sizeof(u32) * items); if (rc < 0) { - printk(KERN_ERR "security: mls: truncated range\n"); + printk(KERN_ERR "SELinux: mls: truncated range\n"); goto out; } r->level[0].sens = le32_to_cpu(buf[0]); @@ -826,21 +833,21 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) rc = ebitmap_read(&r->level[0].cat, fp); if (rc) { - printk(KERN_ERR "security: mls: error reading low " + printk(KERN_ERR "SELinux: mls: error reading low " "categories\n"); goto out; } if (items > 1) { rc = ebitmap_read(&r->level[1].cat, fp); if (rc) { - printk(KERN_ERR "security: mls: error reading high " + printk(KERN_ERR "SELinux: mls: error reading high " "categories\n"); goto bad_high; } } else { rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); if (rc) { - printk(KERN_ERR "security: mls: out of memory\n"); + printk(KERN_ERR "SELinux: mls: out of memory\n"); goto bad_high; } } @@ -866,7 +873,7 @@ static int context_read_and_validate(struct context *c, rc = next_entry(buf, fp, sizeof buf); if (rc < 0) { - printk(KERN_ERR "security: context truncated\n"); + printk(KERN_ERR "SELinux: context truncated\n"); goto out; } c->user = le32_to_cpu(buf[0]); @@ -874,7 +881,7 @@ static int context_read_and_validate(struct context *c, c->type = le32_to_cpu(buf[2]); if (p->policyvers >= POLICYDB_VERSION_MLS) { if (mls_read_range_helper(&c->range, fp)) { - printk(KERN_ERR "security: error reading MLS range of " + printk(KERN_ERR "SELinux: error reading MLS range of " "context\n"); rc = -EINVAL; goto out; @@ -882,7 +889,7 @@ static int context_read_and_validate(struct context *c, } if (!policydb_context_isvalid(p, c)) { - printk(KERN_ERR "security: invalid security context\n"); + printk(KERN_ERR "SELinux: invalid security context\n"); context_destroy(c); rc = -EINVAL; } @@ -1128,7 +1135,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); if (!cladatum->comdatum) { - printk(KERN_ERR "security: unknown common %s\n", + printk(KERN_ERR "SELinux: unknown common %s\n", cladatum->comkey); rc = -EINVAL; goto bad; @@ -1283,13 +1290,13 @@ static int mls_read_level(struct mls_level *lp, void *fp) rc = next_entry(buf, fp, sizeof buf); if (rc < 0) { - printk(KERN_ERR "security: mls: truncated level\n"); + printk(KERN_ERR "SELinux: mls: truncated level\n"); goto bad; } lp->sens = le32_to_cpu(buf[0]); if (ebitmap_read(&lp->cat, fp)) { - printk(KERN_ERR "security: mls: error reading level " + printk(KERN_ERR "SELinux: mls: error reading level " "categories\n"); goto bad; } @@ -1491,7 +1498,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) { - printk(KERN_ERR "security: policydb magic number 0x%x does " + printk(KERN_ERR "SELinux: policydb magic number 0x%x does " "not match expected magic number 0x%x\n", le32_to_cpu(buf[0]), POLICYDB_MAGIC); goto bad; @@ -1499,27 +1506,27 @@ int policydb_read(struct policydb *p, void *fp) len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_STRING)) { - printk(KERN_ERR "security: policydb string length %d does not " + printk(KERN_ERR "SELinux: policydb string length %d does not " "match expected length %Zu\n", len, strlen(POLICYDB_STRING)); goto bad; } policydb_str = kmalloc(len + 1,GFP_KERNEL); if (!policydb_str) { - printk(KERN_ERR "security: unable to allocate memory for policydb " + printk(KERN_ERR "SELinux: unable to allocate memory for policydb " "string of length %d\n", len); rc = -ENOMEM; goto bad; } rc = next_entry(policydb_str, fp, len); if (rc < 0) { - printk(KERN_ERR "security: truncated policydb string identifier\n"); + printk(KERN_ERR "SELinux: truncated policydb string identifier\n"); kfree(policydb_str); goto bad; } policydb_str[len] = 0; if (strcmp(policydb_str, POLICYDB_STRING)) { - printk(KERN_ERR "security: policydb string %s does not match " + printk(KERN_ERR "SELinux: policydb string %s does not match " "my string %s\n", policydb_str, POLICYDB_STRING); kfree(policydb_str); goto bad; @@ -1536,7 +1543,7 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers = le32_to_cpu(buf[0]); if (p->policyvers < POLICYDB_VERSION_MIN || p->policyvers > POLICYDB_VERSION_MAX) { - printk(KERN_ERR "security: policydb version %d does not match " + printk(KERN_ERR "SELinux: policydb version %d does not match " "my version range %d-%d\n", le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); goto bad; @@ -1570,16 +1577,20 @@ int policydb_read(struct policydb *p, void *fp) ebitmap_read(&p->policycaps, fp) != 0) goto bad; + if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && + ebitmap_read(&p->permissive_map, fp) != 0) + goto bad; + info = policydb_lookup_compat(p->policyvers); if (!info) { - printk(KERN_ERR "security: unable to find policy compat info " + printk(KERN_ERR "SELinux: unable to find policy compat info " "for version %d\n", p->policyvers); goto bad; } if (le32_to_cpu(buf[2]) != info->sym_num || le32_to_cpu(buf[3]) != info->ocon_num) { - printk(KERN_ERR "security: policydb table sizes (%d,%d) do " + printk(KERN_ERR "SELinux: policydb table sizes (%d,%d) do " "not match mine (%d,%d)\n", le32_to_cpu(buf[2]), le32_to_cpu(buf[3]), info->sym_num, info->ocon_num); @@ -1823,7 +1834,7 @@ int policydb_read(struct policydb *p, void *fp) for (genfs_p = NULL, genfs = p->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { if (strcmp(newgenfs->fstype, genfs->fstype) == 0) { - printk(KERN_ERR "security: dup genfs " + printk(KERN_ERR "SELinux: dup genfs " "fstype %s\n", newgenfs->fstype); kfree(newgenfs->fstype); kfree(newgenfs); @@ -1873,7 +1884,7 @@ int policydb_read(struct policydb *p, void *fp) if (!strcmp(newc->u.name, c->u.name) && (!c->v.sclass || !newc->v.sclass || newc->v.sclass == c->v.sclass)) { - printk(KERN_ERR "security: dup genfs " + printk(KERN_ERR "SELinux: dup genfs " "entry (%s,%s)\n", newgenfs->fstype, c->u.name); goto bad_newc; @@ -1931,7 +1942,7 @@ int policydb_read(struct policydb *p, void *fp) if (rc) goto bad; if (!mls_range_isvalid(p, &rt->target_range)) { - printk(KERN_WARNING "security: rangetrans: invalid range\n"); + printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); goto bad; } lrt = rt; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index c4ce996e202..ba593a3da87 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -243,6 +243,8 @@ struct policydb { struct ebitmap policycaps; + struct ebitmap permissive_map; + unsigned int policyvers; unsigned int reject_unknown : 1; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 3f2bad28ee7..d75050819b0 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -40,6 +40,7 @@ #include <linux/sched.h> #include <linux/audit.h> #include <linux/mutex.h> +#include <linux/selinux.h> #include <net/netlabel.h> #include "flask.h" @@ -61,6 +62,7 @@ extern void selnl_notify_policyload(u32 seqno); unsigned int policydb_loaded_version; int selinux_policycap_netpeer; +int selinux_policycap_openperm; /* * This is declared in avc.c @@ -412,10 +414,35 @@ static int context_struct_compute_av(struct context *scontext, return 0; inval_class: - printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass); + printk(KERN_ERR "%s: unrecognized class %d\n", __func__, tclass); return -EINVAL; } +/* + * Given a sid find if the type has the permissive flag set + */ +int security_permissive_sid(u32 sid) +{ + struct context *context; + u32 type; + int rc; + + POLICY_RDLOCK; + + context = sidtab_search(&sidtab, sid); + BUG_ON(!context); + + type = context->type; + /* + * we are intentionally using type here, not type-1, the 0th bit may + * someday indicate that we are globally setting permissive in policy. + */ + rc = ebitmap_get_bit(&policydb.permissive_map, type); + + POLICY_RDUNLOCK; + return rc; +} + static int security_validtrans_handle_fail(struct context *ocontext, struct context *ncontext, struct context *tcontext, @@ -1096,7 +1123,7 @@ static int validate_classes(struct policydb *p) continue; if (i > p->p_classes.nprim) { printk(KERN_INFO - "security: class %s not defined in policy\n", + "SELinux: class %s not defined in policy\n", def_class); if (p->reject_unknown) return -EINVAL; @@ -1107,7 +1134,7 @@ static int validate_classes(struct policydb *p) pol_class = p->p_class_val_to_name[i-1]; if (strcmp(pol_class, def_class)) { printk(KERN_ERR - "security: class %d is incorrect, found %s but should be %s\n", + "SELinux: class %d is incorrect, found %s but should be %s\n", i, pol_class, def_class); return -EINVAL; } @@ -1125,7 +1152,7 @@ static int validate_classes(struct policydb *p) nprim = 1 << (perms->nprim - 1); if (perm_val > nprim) { printk(KERN_INFO - "security: permission %s in class %s not defined in policy\n", + "SELinux: permission %s in class %s not defined in policy\n", def_perm, pol_class); if (p->reject_unknown) return -EINVAL; @@ -1136,14 +1163,14 @@ static int validate_classes(struct policydb *p) perdatum = hashtab_search(perms->table, def_perm); if (perdatum == NULL) { printk(KERN_ERR - "security: permission %s in class %s not found in policy, bad policy\n", + "SELinux: permission %s in class %s not found in policy, bad policy\n", def_perm, pol_class); return -EINVAL; } pol_val = 1 << (perdatum->value - 1); if (pol_val != perm_val) { printk(KERN_ERR - "security: permission %s in class %s has incorrect value\n", + "SELinux: permission %s in class %s has incorrect value\n", def_perm, pol_class); return -EINVAL; } @@ -1157,7 +1184,7 @@ static int validate_classes(struct policydb *p) BUG_ON(!cladatum); if (!cladatum->comdatum) { printk(KERN_ERR - "security: class %s should have an inherits clause but does not\n", + "SELinux: class %s should have an inherits clause but does not\n", pol_class); return -EINVAL; } @@ -1172,7 +1199,7 @@ static int validate_classes(struct policydb *p) def_perm = kdefs->av_inherit[i].common_pts[j]; if (j >= perms->nprim) { printk(KERN_INFO - "security: permission %s in class %s not defined in policy\n", + "SELinux: permission %s in class %s not defined in policy\n", def_perm, pol_class); if (p->reject_unknown) return -EINVAL; @@ -1183,13 +1210,13 @@ static int validate_classes(struct policydb *p) perdatum = hashtab_search(perms->table, def_perm); if (perdatum == NULL) { printk(KERN_ERR - "security: permission %s in class %s not found in policy, bad policy\n", + "SELinux: permission %s in class %s not found in policy, bad policy\n", def_perm, pol_class); return -EINVAL; } if (perdatum->value != j + 1) { printk(KERN_ERR - "security: permission %s in class %s has incorrect value\n", + "SELinux: permission %s in class %s has incorrect value\n", def_perm, pol_class); return -EINVAL; } @@ -1219,7 +1246,7 @@ static inline int convert_context_handle_invalid_context(struct context *context u32 len; context_struct_to_string(context, &s, &len); - printk(KERN_ERR "security: context %s is invalid\n", s); + printk(KERN_ERR "SELinux: context %s is invalid\n", s); kfree(s); } return rc; @@ -1299,7 +1326,7 @@ out: bad: context_struct_to_string(&oldc, &s, &len); context_destroy(&oldc); - printk(KERN_ERR "security: invalidating context %s\n", s); + printk(KERN_ERR "SELinux: invalidating context %s\n", s); kfree(s); goto out; } @@ -1308,6 +1335,8 @@ static void security_load_policycaps(void) { selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_NETPEER); + selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, + POLICYDB_CAPABILITY_OPENPERM); } extern void selinux_complete_init(void); @@ -1350,7 +1379,7 @@ int security_load_policy(void *data, size_t len) /* Verify that the kernel defined classes are correct. */ if (validate_classes(&policydb)) { printk(KERN_ERR - "security: the definition of a class is incorrect\n"); + "SELinux: the definition of a class is incorrect\n"); LOAD_UNLOCK; sidtab_destroy(&sidtab); policydb_destroy(&policydb); @@ -1384,14 +1413,14 @@ int security_load_policy(void *data, size_t len) /* Verify that the kernel defined classes are correct. */ if (validate_classes(&newpolicydb)) { printk(KERN_ERR - "security: the definition of a class is incorrect\n"); + "SELinux: the definition of a class is incorrect\n"); rc = -EINVAL; goto err; } rc = security_preserve_bools(&newpolicydb); if (rc) { - printk(KERN_ERR "security: unable to preserve booleans\n"); + printk(KERN_ERR "SELinux: unable to preserve booleans\n"); goto err; } @@ -1443,17 +1472,11 @@ err: /** * security_port_sid - Obtain the SID for a port. - * @domain: communication domain aka address family - * @type: socket type * @protocol: protocol number * @port: port number * @out_sid: security identifier */ -int security_port_sid(u16 domain, - u16 type, - u8 protocol, - u16 port, - u32 *out_sid) +int security_port_sid(u8 protocol, u16 port, u32 *out_sid) { struct ocontext *c; int rc = 0; @@ -2203,7 +2226,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) match = hashtab_search(policydb.p_classes.table, class); if (!match) { printk(KERN_ERR "%s: unrecognized class %s\n", - __FUNCTION__, class); + __func__, class); rc = -EINVAL; goto out; } |