diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-19 11:33:12 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-19 11:33:12 -0500 |
| commit | ff5f16820f632079d5095884adc5d71ee3249fa4 (patch) | |
| tree | 5f474546110a3c7c3194264978304d268a716840 | |
| parent | 409ee136f28f71cbec518cfc85a379a508ccbaa0 (diff) | |
| parent | 12d319b920fa673a4d5e7c1785c5dc82dcd15257 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Martin Schwidefsky:
"Several bug fixes:
- There are four different stack tracers, and three of them have
bugs. For 4.5 the bugs are fixed and we prepare a cleanup patch
for the next merge window.
- Three bug fixes for the dasd driver in regard to parallel access
volumes and the new max_dev_sectors block device queue limit
- The irq restore optimization needs a fixup for memcpy_real
- The diagnose trace code has a conflict with lockdep"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/dasd: fix performance drop
s390/maccess: reduce stnsm instructions
s390/diag: avoid lockdep recursion
s390/dasd: fix refcount for PAV reassignment
s390/dasd: prevent incorrect length error under z/VM after PAV changes
s390: fix DAT off memory access, e.g. on kdump
s390/oprofile: fix address range for asynchronous stack
s390/perf_event: fix address range for asynchronous stack
s390/stacktrace: add save_stack_trace_regs()
s390/stacktrace: save full stack traces
s390/stacktrace: add missing end marker
s390/stacktrace: fix address ranges for asynchronous and panic stack
s390/stacktrace: fix save_stack_trace_tsk() for current task
| -rw-r--r-- | arch/s390/kernel/perf_event.c | 8 | ||||
| -rw-r--r-- | arch/s390/kernel/stacktrace.c | 47 | ||||
| -rw-r--r-- | arch/s390/kernel/trace.c | 3 | ||||
| -rw-r--r-- | arch/s390/mm/maccess.c | 12 | ||||
| -rw-r--r-- | arch/s390/oprofile/backtrace.c | 8 | ||||
| -rw-r--r-- | drivers/s390/block/dasd.c | 1 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_alias.c | 23 |
7 files changed, 73 insertions, 29 deletions
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index cfcba2dd9bb5..0943b11a2f6e 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c | |||
| @@ -260,12 +260,13 @@ static unsigned long __store_trace(struct perf_callchain_entry *entry, | |||
| 260 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | 260 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
| 261 | struct pt_regs *regs) | 261 | struct pt_regs *regs) |
| 262 | { | 262 | { |
| 263 | unsigned long head; | 263 | unsigned long head, frame_size; |
| 264 | struct stack_frame *head_sf; | 264 | struct stack_frame *head_sf; |
| 265 | 265 | ||
| 266 | if (user_mode(regs)) | 266 | if (user_mode(regs)) |
| 267 | return; | 267 | return; |
| 268 | 268 | ||
| 269 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | ||
| 269 | head = regs->gprs[15]; | 270 | head = regs->gprs[15]; |
| 270 | head_sf = (struct stack_frame *) head; | 271 | head_sf = (struct stack_frame *) head; |
| 271 | 272 | ||
| @@ -273,8 +274,9 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, | |||
| 273 | return; | 274 | return; |
| 274 | 275 | ||
| 275 | head = head_sf->back_chain; | 276 | head = head_sf->back_chain; |
| 276 | head = __store_trace(entry, head, S390_lowcore.async_stack - ASYNC_SIZE, | 277 | head = __store_trace(entry, head, |
| 277 | S390_lowcore.async_stack); | 278 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, |
| 279 | S390_lowcore.async_stack + frame_size); | ||
| 278 | 280 | ||
| 279 | __store_trace(entry, head, S390_lowcore.thread_info, | 281 | __store_trace(entry, head, S390_lowcore.thread_info, |
| 280 | S390_lowcore.thread_info + THREAD_SIZE); | 282 | S390_lowcore.thread_info + THREAD_SIZE); |
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 5acba3cb7220..8f64ebd63767 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c | |||
| @@ -59,26 +59,32 @@ static unsigned long save_context_stack(struct stack_trace *trace, | |||
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | void save_stack_trace(struct stack_trace *trace) | 62 | static void __save_stack_trace(struct stack_trace *trace, unsigned long sp) |
| 63 | { | 63 | { |
| 64 | register unsigned long sp asm ("15"); | 64 | unsigned long new_sp, frame_size; |
| 65 | unsigned long orig_sp, new_sp; | ||
| 66 | 65 | ||
| 67 | orig_sp = sp; | 66 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); |
| 68 | new_sp = save_context_stack(trace, orig_sp, | 67 | new_sp = save_context_stack(trace, sp, |
| 69 | S390_lowcore.panic_stack - PAGE_SIZE, | 68 | S390_lowcore.panic_stack + frame_size - PAGE_SIZE, |
| 70 | S390_lowcore.panic_stack, 1); | 69 | S390_lowcore.panic_stack + frame_size, 1); |
| 71 | if (new_sp != orig_sp) | ||
| 72 | return; | ||
| 73 | new_sp = save_context_stack(trace, new_sp, | 70 | new_sp = save_context_stack(trace, new_sp, |
| 74 | S390_lowcore.async_stack - ASYNC_SIZE, | 71 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, |
| 75 | S390_lowcore.async_stack, 1); | 72 | S390_lowcore.async_stack + frame_size, 1); |
| 76 | if (new_sp != orig_sp) | ||
| 77 | return; | ||
| 78 | save_context_stack(trace, new_sp, | 73 | save_context_stack(trace, new_sp, |
| 79 | S390_lowcore.thread_info, | 74 | S390_lowcore.thread_info, |
| 80 | S390_lowcore.thread_info + THREAD_SIZE, 1); | 75 | S390_lowcore.thread_info + THREAD_SIZE, 1); |
| 81 | } | 76 | } |
| 77 | |||
| 78 | void save_stack_trace(struct stack_trace *trace) | ||
| 79 | { | ||
| 80 | register unsigned long r15 asm ("15"); | ||
| 81 | unsigned long sp; | ||
| 82 | |||
| 83 | sp = r15; | ||
| 84 | __save_stack_trace(trace, sp); | ||
| 85 | if (trace->nr_entries < trace->max_entries) | ||
| 86 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
| 87 | } | ||
| 82 | EXPORT_SYMBOL_GPL(save_stack_trace); | 88 | EXPORT_SYMBOL_GPL(save_stack_trace); |
| 83 | 89 | ||
| 84 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 90 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
| @@ -86,6 +92,10 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
| 86 | unsigned long sp, low, high; | 92 | unsigned long sp, low, high; |
| 87 | 93 | ||
| 88 | sp = tsk->thread.ksp; | 94 | sp = tsk->thread.ksp; |
| 95 | if (tsk == current) { | ||
| 96 | /* Get current stack pointer. */ | ||
| 97 | asm volatile("la %0,0(15)" : "=a" (sp)); | ||
| 98 | } | ||
| 89 | low = (unsigned long) task_stack_page(tsk); | 99 | low = (unsigned long) task_stack_page(tsk); |
| 90 | high = (unsigned long) task_pt_regs(tsk); | 100 | high = (unsigned long) task_pt_regs(tsk); |
| 91 | save_context_stack(trace, sp, low, high, 0); | 101 | save_context_stack(trace, sp, low, high, 0); |
| @@ -93,3 +103,14 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
| 93 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 103 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
| 94 | } | 104 | } |
| 95 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | 105 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
| 106 | |||
| 107 | void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) | ||
| 108 | { | ||
| 109 | unsigned long sp; | ||
| 110 | |||
| 111 | sp = kernel_stack_pointer(regs); | ||
| 112 | __save_stack_trace(trace, sp); | ||
| 113 | if (trace->nr_entries < trace->max_entries) | ||
| 114 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
| 115 | } | ||
| 116 | EXPORT_SYMBOL_GPL(save_stack_trace_regs); | ||
diff --git a/arch/s390/kernel/trace.c b/arch/s390/kernel/trace.c index 21a5df99552b..dde7654f5c68 100644 --- a/arch/s390/kernel/trace.c +++ b/arch/s390/kernel/trace.c | |||
| @@ -18,6 +18,9 @@ void trace_s390_diagnose_norecursion(int diag_nr) | |||
| 18 | unsigned long flags; | 18 | unsigned long flags; |
| 19 | unsigned int *depth; | 19 | unsigned int *depth; |
| 20 | 20 | ||
| 21 | /* Avoid lockdep recursion. */ | ||
| 22 | if (IS_ENABLED(CONFIG_LOCKDEP)) | ||
| 23 | return; | ||
| 21 | local_irq_save(flags); | 24 | local_irq_save(flags); |
| 22 | depth = this_cpu_ptr(&diagnose_trace_depth); | 25 | depth = this_cpu_ptr(&diagnose_trace_depth); |
| 23 | if (*depth == 0) { | 26 | if (*depth == 0) { |
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index fec59c067d0d..792f9c63fbca 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c | |||
| @@ -93,15 +93,19 @@ static int __memcpy_real(void *dest, void *src, size_t count) | |||
| 93 | */ | 93 | */ |
| 94 | int memcpy_real(void *dest, void *src, size_t count) | 94 | int memcpy_real(void *dest, void *src, size_t count) |
| 95 | { | 95 | { |
| 96 | int irqs_disabled, rc; | ||
| 96 | unsigned long flags; | 97 | unsigned long flags; |
| 97 | int rc; | ||
| 98 | 98 | ||
| 99 | if (!count) | 99 | if (!count) |
| 100 | return 0; | 100 | return 0; |
| 101 | local_irq_save(flags); | 101 | flags = __arch_local_irq_stnsm(0xf8UL); |
| 102 | __arch_local_irq_stnsm(0xfbUL); | 102 | irqs_disabled = arch_irqs_disabled_flags(flags); |
| 103 | if (!irqs_disabled) | ||
| 104 | trace_hardirqs_off(); | ||
| 103 | rc = __memcpy_real(dest, src, count); | 105 | rc = __memcpy_real(dest, src, count); |
| 104 | local_irq_restore(flags); | 106 | if (!irqs_disabled) |
| 107 | trace_hardirqs_on(); | ||
| 108 | __arch_local_irq_ssm(flags); | ||
| 105 | return rc; | 109 | return rc; |
| 106 | } | 110 | } |
| 107 | 111 | ||
diff --git a/arch/s390/oprofile/backtrace.c b/arch/s390/oprofile/backtrace.c index fe0bfe370c45..1884e1759529 100644 --- a/arch/s390/oprofile/backtrace.c +++ b/arch/s390/oprofile/backtrace.c | |||
| @@ -54,12 +54,13 @@ __show_trace(unsigned int *depth, unsigned long sp, | |||
| 54 | 54 | ||
| 55 | void s390_backtrace(struct pt_regs * const regs, unsigned int depth) | 55 | void s390_backtrace(struct pt_regs * const regs, unsigned int depth) |
| 56 | { | 56 | { |
| 57 | unsigned long head; | 57 | unsigned long head, frame_size; |
| 58 | struct stack_frame* head_sf; | 58 | struct stack_frame* head_sf; |
| 59 | 59 | ||
| 60 | if (user_mode(regs)) | 60 | if (user_mode(regs)) |
| 61 | return; | 61 | return; |
| 62 | 62 | ||
| 63 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | ||
| 63 | head = regs->gprs[15]; | 64 | head = regs->gprs[15]; |
| 64 | head_sf = (struct stack_frame*)head; | 65 | head_sf = (struct stack_frame*)head; |
| 65 | 66 | ||
| @@ -68,8 +69,9 @@ void s390_backtrace(struct pt_regs * const regs, unsigned int depth) | |||
| 68 | 69 | ||
| 69 | head = head_sf->back_chain; | 70 | head = head_sf->back_chain; |
| 70 | 71 | ||
| 71 | head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE, | 72 | head = __show_trace(&depth, head, |
| 72 | S390_lowcore.async_stack); | 73 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, |
| 74 | S390_lowcore.async_stack + frame_size); | ||
| 73 | 75 | ||
| 74 | __show_trace(&depth, head, S390_lowcore.thread_info, | 76 | __show_trace(&depth, head, S390_lowcore.thread_info, |
| 75 | S390_lowcore.thread_info + THREAD_SIZE); | 77 | S390_lowcore.thread_info + THREAD_SIZE); |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 41605dac8309..c78db05e75b1 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -3035,6 +3035,7 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
| 3035 | max = block->base->discipline->max_blocks << block->s2b_shift; | 3035 | max = block->base->discipline->max_blocks << block->s2b_shift; |
| 3036 | } | 3036 | } |
| 3037 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue); | 3037 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue); |
| 3038 | block->request_queue->limits.max_dev_sectors = max; | ||
| 3038 | blk_queue_logical_block_size(block->request_queue, | 3039 | blk_queue_logical_block_size(block->request_queue, |
| 3039 | block->bp_block); | 3040 | block->bp_block); |
| 3040 | blk_queue_max_hw_sectors(block->request_queue, max); | 3041 | blk_queue_max_hw_sectors(block->request_queue, max); |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 184b1dbeb554..286782c60da4 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
| @@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
| 264 | spin_unlock_irqrestore(&lcu->lock, flags); | 264 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 265 | cancel_work_sync(&lcu->suc_data.worker); | 265 | cancel_work_sync(&lcu->suc_data.worker); |
| 266 | spin_lock_irqsave(&lcu->lock, flags); | 266 | spin_lock_irqsave(&lcu->lock, flags); |
| 267 | if (device == lcu->suc_data.device) | 267 | if (device == lcu->suc_data.device) { |
| 268 | dasd_put_device(device); | ||
| 268 | lcu->suc_data.device = NULL; | 269 | lcu->suc_data.device = NULL; |
| 270 | } | ||
| 269 | } | 271 | } |
| 270 | was_pending = 0; | 272 | was_pending = 0; |
| 271 | if (device == lcu->ruac_data.device) { | 273 | if (device == lcu->ruac_data.device) { |
| @@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
| 273 | was_pending = 1; | 275 | was_pending = 1; |
| 274 | cancel_delayed_work_sync(&lcu->ruac_data.dwork); | 276 | cancel_delayed_work_sync(&lcu->ruac_data.dwork); |
| 275 | spin_lock_irqsave(&lcu->lock, flags); | 277 | spin_lock_irqsave(&lcu->lock, flags); |
| 276 | if (device == lcu->ruac_data.device) | 278 | if (device == lcu->ruac_data.device) { |
| 279 | dasd_put_device(device); | ||
| 277 | lcu->ruac_data.device = NULL; | 280 | lcu->ruac_data.device = NULL; |
| 281 | } | ||
| 278 | } | 282 | } |
| 279 | private->lcu = NULL; | 283 | private->lcu = NULL; |
| 280 | spin_unlock_irqrestore(&lcu->lock, flags); | 284 | spin_unlock_irqrestore(&lcu->lock, flags); |
| @@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work) | |||
| 549 | if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { | 553 | if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { |
| 550 | DBF_DEV_EVENT(DBF_WARNING, device, "could not update" | 554 | DBF_DEV_EVENT(DBF_WARNING, device, "could not update" |
| 551 | " alias data in lcu (rc = %d), retry later", rc); | 555 | " alias data in lcu (rc = %d), retry later", rc); |
| 552 | schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); | 556 | if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ)) |
| 557 | dasd_put_device(device); | ||
| 553 | } else { | 558 | } else { |
| 559 | dasd_put_device(device); | ||
| 554 | lcu->ruac_data.device = NULL; | 560 | lcu->ruac_data.device = NULL; |
| 555 | lcu->flags &= ~UPDATE_PENDING; | 561 | lcu->flags &= ~UPDATE_PENDING; |
| 556 | } | 562 | } |
| @@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, | |||
| 593 | */ | 599 | */ |
| 594 | if (!usedev) | 600 | if (!usedev) |
| 595 | return -EINVAL; | 601 | return -EINVAL; |
| 602 | dasd_get_device(usedev); | ||
| 596 | lcu->ruac_data.device = usedev; | 603 | lcu->ruac_data.device = usedev; |
| 597 | schedule_delayed_work(&lcu->ruac_data.dwork, 0); | 604 | if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0)) |
| 605 | dasd_put_device(usedev); | ||
| 598 | return 0; | 606 | return 0; |
| 599 | } | 607 | } |
| 600 | 608 | ||
| @@ -723,7 +731,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, | |||
| 723 | ASCEBC((char *) &cqr->magic, 4); | 731 | ASCEBC((char *) &cqr->magic, 4); |
| 724 | ccw = cqr->cpaddr; | 732 | ccw = cqr->cpaddr; |
| 725 | ccw->cmd_code = DASD_ECKD_CCW_RSCK; | 733 | ccw->cmd_code = DASD_ECKD_CCW_RSCK; |
| 726 | ccw->flags = 0 ; | 734 | ccw->flags = CCW_FLAG_SLI; |
| 727 | ccw->count = 16; | 735 | ccw->count = 16; |
| 728 | ccw->cda = (__u32)(addr_t) cqr->data; | 736 | ccw->cda = (__u32)(addr_t) cqr->data; |
| 729 | ((char *)cqr->data)[0] = reason; | 737 | ((char *)cqr->data)[0] = reason; |
| @@ -930,6 +938,7 @@ static void summary_unit_check_handling_work(struct work_struct *work) | |||
| 930 | /* 3. read new alias configuration */ | 938 | /* 3. read new alias configuration */ |
| 931 | _schedule_lcu_update(lcu, device); | 939 | _schedule_lcu_update(lcu, device); |
| 932 | lcu->suc_data.device = NULL; | 940 | lcu->suc_data.device = NULL; |
| 941 | dasd_put_device(device); | ||
| 933 | spin_unlock_irqrestore(&lcu->lock, flags); | 942 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 934 | } | 943 | } |
| 935 | 944 | ||
| @@ -989,6 +998,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | |||
| 989 | } | 998 | } |
| 990 | lcu->suc_data.reason = reason; | 999 | lcu->suc_data.reason = reason; |
| 991 | lcu->suc_data.device = device; | 1000 | lcu->suc_data.device = device; |
| 1001 | dasd_get_device(device); | ||
| 992 | spin_unlock(&lcu->lock); | 1002 | spin_unlock(&lcu->lock); |
| 993 | schedule_work(&lcu->suc_data.worker); | 1003 | if (!schedule_work(&lcu->suc_data.worker)) |
| 1004 | dasd_put_device(device); | ||
| 994 | }; | 1005 | }; |
