From a3bee5f1455e5249f3e28313e8b25524637a55c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 16 Mar 2012 17:44:42 -0700 Subject: PM / Sleep: Add wake lock api wrapper on top of wakeup sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Icaad02fe1e8856fdc2e4215f380594a5dde8e002 Signed-off-by: Arve Hjønnevåg --- kernel/power/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'kernel') diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 02e8dfaa1ce2..deb2df6a7129 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -28,6 +28,10 @@ config SUSPEND_SKIP_SYNC of suspend, or they are content with invoking sync() from user-space before invoking suspend. Say Y if that's your case. +config WAKELOCK + bool + default y + config HIBERNATE_CALLBACKS bool -- cgit v1.2.3 From c70fe44edf89b1d70b96540608cac56f81ff5667 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 14 Mar 2012 19:26:53 -0700 Subject: kdb: support new lines without carriage returns kdb expects carriage returns through the serial port to terminate commands. Modify it to accept the first seen carriage return or new line as a terminator, but not treat \r\n as two terminators. Change-Id: I06166017e7703d24310eefcb71c3a7d427088db7 Signed-off-by: Colin Cross --- kernel/debug/kdb/kdb_io.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index fc1ef736253c..0b891286a150 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -216,7 +216,7 @@ static char *kdb_read(char *buffer, size_t bufsize) int i; int diag, dtab_count; int key; - + static int last_crlf; diag = kdbgetintenv("DTABCOUNT", &dtab_count); if (diag) @@ -237,6 +237,9 @@ poll_again: return buffer; if (key != 9) tab = 0; + if (key != 10 && key != 13) + last_crlf = 0; + switch (key) { case 8: /* backspace */ if (cp > buffer) { @@ -254,7 +257,12 @@ poll_again: *cp = tmp; } break; - case 13: /* enter */ + case 10: /* new line */ + case 13: /* carriage return */ + /* handle \n after \r */ + if (last_crlf && last_crlf != key) + break; + last_crlf = key; *lastchar++ = '\n'; *lastchar++ = '\0'; if (!KDB_STATE(KGDB_TRANS)) { -- cgit v1.2.3 From b3bb0e5bbf24780300621d69e6ffbdcc11c72358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Wed, 10 Dec 2008 20:06:28 -0800 Subject: sched: Enable might_sleep before initializing drivers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows detection of init bugs in built-in drivers. Signed-off-by: Arve Hjønnevåg --- kernel/sched/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 732e993b564b..67359c7f35db 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7542,6 +7542,14 @@ static inline int preempt_count_equals(int preempt_offset) return (nested == preempt_offset); } +static int __might_sleep_init_called; +int __init __might_sleep_init(void) +{ + __might_sleep_init_called = 1; + return 0; +} +early_initcall(__might_sleep_init); + void __might_sleep(const char *file, int line, int preempt_offset) { /* @@ -7566,8 +7574,10 @@ void ___might_sleep(const char *file, int line, int preempt_offset) rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */ if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && - !is_idle_task(current)) || - system_state != SYSTEM_RUNNING || oops_in_progress) + !is_idle_task(current)) || oops_in_progress) + return; + if (system_state != SYSTEM_RUNNING && + (!__might_sleep_init_called || system_state != SYSTEM_BOOTING)) return; if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) return; -- cgit v1.2.3 From 7abc800d049ee8e673acab90032e7cfbad1600a6 Mon Sep 17 00:00:00 2001 From: Riley Andrews Date: Fri, 2 Oct 2015 00:39:53 -0700 Subject: sched: add sched blocked tracepoint which dumps out context of sleep. Decare war on uninterruptible sleep. Add a tracepoint which walks the kernel stack and dumps the first non-scheduler function called before the scheduler is invoked. Change-Id: I19e965d5206329360a92cbfe2afcc8c30f65c229 Signed-off-by: Riley Andrews --- kernel/sched/fair.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel') diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index cfdc0e61066c..ba24bfe4ac51 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2931,6 +2931,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) } trace_sched_stat_blocked(tsk, delta); + trace_sched_blocked_reason(tsk); /* * Blocking time is in units of nanosecs, so shift by -- cgit v1.2.3 From 90fbee8f979d91bb43e9923135000424adfdcaf0 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Wed, 15 Jun 2011 17:21:57 -0700 Subject: Move x86_64 idle notifiers to generic Move the x86_64 idle notifiers originally by Andi Kleen and Venkatesh Pallipadi to generic. Change-Id: Idf29cda15be151f494ff245933c12462643388d5 Acked-by: Nicolas Pitre Signed-off-by: Todd Poynor --- kernel/cpu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'kernel') diff --git a/kernel/cpu.c b/kernel/cpu.c index 85ff5e26e23b..74e411acb1f2 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -827,3 +827,23 @@ void init_cpu_online(const struct cpumask *src) { cpumask_copy(to_cpumask(cpu_online_bits), src); } + +static ATOMIC_NOTIFIER_HEAD(idle_notifier); + +void idle_notifier_register(struct notifier_block *n) +{ + atomic_notifier_chain_register(&idle_notifier, n); +} +EXPORT_SYMBOL_GPL(idle_notifier_register); + +void idle_notifier_unregister(struct notifier_block *n) +{ + atomic_notifier_chain_unregister(&idle_notifier, n); +} +EXPORT_SYMBOL_GPL(idle_notifier_unregister); + +void idle_notifier_call_chain(unsigned long val) +{ + atomic_notifier_call_chain(&idle_notifier, val, NULL); +} +EXPORT_SYMBOL_GPL(idle_notifier_call_chain); -- cgit v1.2.3 From e2dba5ee5fa27dace155194163ce970c63e6fe7a Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Thu, 21 Feb 2013 17:55:28 -0800 Subject: trace/events: add gpu trace events Change-Id: I0607b9c776acf61cb796b8572cf8cfb8b2dc1377 Signed-off-by: Jamie Gennis --- kernel/trace/Kconfig | 3 +++ kernel/trace/Makefile | 1 + kernel/trace/gpu-traces.c | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 kernel/trace/gpu-traces.c (limited to 'kernel') diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index e45db6b0d878..5f5b66a2f156 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -77,6 +77,9 @@ config EVENT_TRACING select CONTEXT_SWITCH_TRACER bool +config GPU_TRACEPOINTS + bool + config CONTEXT_SWITCH_TRACER bool diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 9b1044e936a6..ba04bf0c2653 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_KGDB_KDB) += trace_kdb.o endif obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o +obj-$(CONFIG_GPU_TRACEPOINTS) += gpu-traces.o obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o diff --git a/kernel/trace/gpu-traces.c b/kernel/trace/gpu-traces.c new file mode 100644 index 000000000000..a4b3f00faee3 --- /dev/null +++ b/kernel/trace/gpu-traces.c @@ -0,0 +1,23 @@ +/* + * GPU tracepoints + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL(gpu_sched_switch); +EXPORT_TRACEPOINT_SYMBOL(gpu_job_enqueue); -- cgit v1.2.3 From 6019e59489e288c1eb7276387ea45d8ceb69f6b2 Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Wed, 21 Nov 2012 15:04:25 -0800 Subject: trace: Add an option to show tgids in trace output The tgids are tracked along side the saved_cmdlines tracking, and can be included in trace output by enabling the 'print-tgid' trace option. This is useful when doing post-processing of the trace data, as it allows events to be grouped by tgid. Change-Id: I52ed04c3a8ca7fddbb868b792ce5d21ceb76250e Signed-off-by: Jamie Gennis --- kernel/trace/trace.c | 98 +++++++++++++++++++++++++++++++++++++++++++-- kernel/trace/trace.h | 4 +- kernel/trace/trace_output.c | 14 ++++++- 3 files changed, 110 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 87fb9801bd9e..225d450cd84d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1352,6 +1352,7 @@ void tracing_reset_all_online_cpus(void) #define SAVED_CMDLINES_DEFAULT 128 #define NO_CMDLINE_MAP UINT_MAX +static unsigned saved_tgids[SAVED_CMDLINES]; static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; struct saved_cmdlines_buffer { unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; @@ -1590,7 +1591,7 @@ static int trace_save_cmdline(struct task_struct *tsk) } set_cmdline(idx, tsk->comm); - + saved_tgids[idx] = tsk->tgid; arch_spin_unlock(&trace_cmdline_lock); return 1; @@ -1633,6 +1634,25 @@ void trace_find_cmdline(int pid, char comm[]) preempt_enable(); } +int trace_find_tgid(int pid) +{ + unsigned map; + int tgid; + + preempt_disable(); + arch_spin_lock(&trace_cmdline_lock); + map = map_pid_to_cmdline[pid]; + if (map != NO_CMDLINE_MAP) + tgid = saved_tgids[map]; + else + tgid = -1; + + arch_spin_unlock(&trace_cmdline_lock); + preempt_enable(); + + return tgid; +} + void tracing_record_cmdline(struct task_struct *tsk) { if (atomic_read(&trace_record_cmdline_disabled) || !tracing_is_on()) @@ -2583,6 +2603,13 @@ static void print_func_help_header(struct trace_buffer *buf, struct seq_file *m) "# | | | | |\n"); } +static void print_func_help_header_tgid(struct trace_buffer *buf, struct seq_file *m) +{ + print_event_info(buf, m); + seq_puts(m, "# TASK-PID TGID CPU# TIMESTAMP FUNCTION\n"); + seq_puts(m, "# | | | | | |\n"); +} + static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file *m) { print_event_info(buf, m); @@ -2595,6 +2622,18 @@ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file "# | | | |||| | |\n"); } +static void print_func_help_header_irq_tgid(struct trace_buffer *buf, struct seq_file *m) +{ + print_event_info(buf, m); + seq_puts(m, "# _-----=> irqs-off\n"); + seq_puts(m, "# / _----=> need-resched\n"); + seq_puts(m, "# | / _---=> hardirq/softirq\n"); + seq_puts(m, "# || / _--=> preempt-depth\n"); + seq_puts(m, "# ||| / delay\n"); + seq_puts(m, "# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION\n"); + seq_puts(m, "# | | | | |||| | |\n"); +} + void print_trace_header(struct seq_file *m, struct trace_iterator *iter) { @@ -2907,9 +2946,15 @@ void trace_default_header(struct seq_file *m) } else { if (!(trace_flags & TRACE_ITER_VERBOSE)) { if (trace_flags & TRACE_ITER_IRQ_INFO) - print_func_help_header_irq(iter->trace_buffer, m); + if (trace_flags & TRACE_ITER_TGID) + print_func_help_header_irq_tgid(iter->trace_buffer, m); + else + print_func_help_header_irq(iter->trace_buffer, m); else - print_func_help_header(iter->trace_buffer, m); + if (trace_flags & TRACE_ITER_TGID) + print_func_help_header_tgid(iter->trace_buffer, m); + else + print_func_help_header(iter->trace_buffer, m); } } } @@ -4160,6 +4205,50 @@ static void trace_insert_enum_map(struct module *mod, trace_insert_enum_map_file(mod, start, len); } +static ssize_t +tracing_saved_tgids_read(struct file *file, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *file_buf; + char *buf; + int len = 0; + int pid; + int i; + + file_buf = kmalloc(SAVED_CMDLINES*(16+1+16), GFP_KERNEL); + if (!file_buf) + return -ENOMEM; + + buf = file_buf; + + for (i = 0; i < SAVED_CMDLINES; i++) { + int tgid; + int r; + + pid = map_cmdline_to_pid[i]; + if (pid == -1 || pid == NO_CMDLINE_MAP) + continue; + + tgid = trace_find_tgid(pid); + r = sprintf(buf, "%d %d\n", pid, tgid); + buf += r; + len += r; + } + + len = simple_read_from_buffer(ubuf, cnt, ppos, + file_buf, len); + + kfree(file_buf); + + return len; +} + +static const struct file_operations tracing_saved_tgids_fops = { + .open = tracing_open_generic, + .read = tracing_saved_tgids_read, + .llseek = generic_file_llseek, +}; + static ssize_t tracing_set_trace_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) @@ -6784,6 +6873,9 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer) trace_create_file("trace_marker", 0220, d_tracer, tr, &tracing_mark_fops); + trace_create_file("saved_tgids", 0444, d_tracer, + tr, &tracing_saved_tgids_fops); + trace_create_file("trace_clock", 0644, d_tracer, tr, &trace_clock_fops); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 919d9d07686f..e1265f95457f 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -656,6 +656,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags, extern cycle_t ftrace_now(int cpu); extern void trace_find_cmdline(int pid, char comm[]); +extern int trace_find_tgid(int pid); #ifdef CONFIG_DYNAMIC_FTRACE extern unsigned long ftrace_update_tot_cnt; @@ -970,7 +971,8 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf, FUNCTION_FLAGS \ FGRAPH_FLAGS \ STACK_FLAGS \ - BRANCH_FLAGS + BRANCH_FLAGS \ + C(TGID, "print-tgid"), /* * By defining C, we can make TRACE_FLAGS a list of bit names diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 282982195e09..a2fc60a74e27 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -526,11 +526,21 @@ int trace_print_context(struct trace_iterator *iter) unsigned long long t; unsigned long secs, usec_rem; char comm[TASK_COMM_LEN]; + int tgid; trace_find_cmdline(entry->pid, comm); - trace_seq_printf(s, "%16s-%-5d [%03d] ", - comm, entry->pid, iter->cpu); + trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid); + + if (tr->trace_flags & TRACE_ITER_TGID) { + tgid = trace_find_tgid(entry->pid); + if (tgid < 0) + trace_seq_puts(s, "(-----) "); + else + trace_seq_printf(s, "(%5d) ", tgid); + } + + trace_seq_printf(s, "[%03d] ", iter->cpu); if (tr->trace_flags & TRACE_ITER_IRQ_INFO) trace_print_lat_fmt(s, entry); -- cgit v1.2.3 From e33c31a0916861e63c333c815ee5a1afc151bfe3 Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Wed, 21 Nov 2012 20:14:09 -0800 Subject: trace: add non-hierarchical function_graph option Add the 'funcgraph-flat' option to the function_graph tracer to use the default trace printing format rather than the hierarchical formatting normally used. Change-Id: If2900bfb86e6f8f51379f56da4f6fabafa630909 Signed-off-by: Jamie Gennis --- kernel/trace/trace_functions_graph.c | 43 +++------ kernel/trace/trace_output.c | 164 +++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 30 deletions(-) (limited to 'kernel') diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index a663cbb84107..4641bdb40f8f 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -64,6 +64,9 @@ struct fgraph_data { #define TRACE_GRAPH_INDENT 2 +/* Flag options */ +#define TRACE_GRAPH_PRINT_FLAT 0x80 + static unsigned int max_depth; static struct tracer_opt trace_opts[] = { @@ -87,6 +90,8 @@ static struct tracer_opt trace_opts[] = { { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, /* Include time within nested functions */ { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) }, + /* Use standard trace formatting rather than hierarchical */ + { TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) }, { } /* Empty entry */ }; @@ -1165,6 +1170,9 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags) int cpu = iter->cpu; int ret; + if (flags & TRACE_GRAPH_PRINT_FLAT) + return TRACE_TYPE_UNHANDLED; + if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) { per_cpu_ptr(data->cpu_data, cpu)->ignore = 0; return TRACE_TYPE_HANDLED; @@ -1222,13 +1230,6 @@ print_graph_function(struct trace_iterator *iter) return print_graph_function_flags(iter, tracer_flags.val); } -static enum print_line_t -print_graph_function_event(struct trace_iterator *iter, int flags, - struct trace_event *event) -{ - return print_graph_function(iter); -} - static void print_lat_header(struct seq_file *s, u32 flags) { static const char spaces[] = " " /* 16 spaces */ @@ -1297,6 +1298,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags) struct trace_iterator *iter = s->private; struct trace_array *tr = iter->tr; + if (flags & TRACE_GRAPH_PRINT_FLAT) { + trace_default_header(s); + return; + } + if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO)) return; @@ -1378,19 +1384,6 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) return 0; } -static struct trace_event_functions graph_functions = { - .trace = print_graph_function_event, -}; - -static struct trace_event graph_trace_entry_event = { - .type = TRACE_GRAPH_ENT, - .funcs = &graph_functions, -}; - -static struct trace_event graph_trace_ret_event = { - .type = TRACE_GRAPH_RET, - .funcs = &graph_functions -}; static struct tracer graph_trace __tracer_data = { .name = "function_graph", @@ -1467,16 +1460,6 @@ static __init int init_graph_trace(void) { max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); - if (!register_trace_event(&graph_trace_entry_event)) { - pr_warning("Warning: could not register graph trace events\n"); - return 1; - } - - if (!register_trace_event(&graph_trace_ret_event)) { - pr_warning("Warning: could not register graph trace events\n"); - return 1; - } - return register_tracer(&graph_trace); } diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index a2fc60a74e27..d03ecf65ad53 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -855,6 +855,168 @@ static struct trace_event trace_fn_event = { .funcs = &trace_fn_funcs, }; +/* TRACE_GRAPH_ENT */ +static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct trace_seq *s = &iter->seq; + struct ftrace_graph_ent_entry *field; + + trace_assign_type(field, iter->ent); + + if (!trace_seq_puts(s, "graph_ent: func=")) + return TRACE_TYPE_PARTIAL_LINE; + + if (!seq_print_ip_sym(s, field->graph_ent.func, flags)) + return TRACE_TYPE_PARTIAL_LINE; + + if (!trace_seq_puts(s, "\n")) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ent_entry *field; + + trace_assign_type(field, iter->ent); + + if (!trace_seq_printf(&iter->seq, "%lx %d\n", + field->graph_ent.func, + field->graph_ent.depth)) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ent_entry *field; + struct trace_seq *s = &iter->seq; + + trace_assign_type(field, iter->ent); + + SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func); + SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth); + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ent_entry *field; + struct trace_seq *s = &iter->seq; + + trace_assign_type(field, iter->ent); + + SEQ_PUT_FIELD_RET(s, field->graph_ent.func); + SEQ_PUT_FIELD_RET(s, field->graph_ent.depth); + + return TRACE_TYPE_HANDLED; +} + +static struct trace_event_functions trace_graph_ent_funcs = { + .trace = trace_graph_ent_trace, + .raw = trace_graph_ent_raw, + .hex = trace_graph_ent_hex, + .binary = trace_graph_ent_bin, +}; + +static struct trace_event trace_graph_ent_event = { + .type = TRACE_GRAPH_ENT, + .funcs = &trace_graph_ent_funcs, +}; + +/* TRACE_GRAPH_RET */ +static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct trace_seq *s = &iter->seq; + struct trace_entry *entry = iter->ent; + struct ftrace_graph_ret_entry *field; + + trace_assign_type(field, entry); + + if (!trace_seq_puts(s, "graph_ret: func=")) + return TRACE_TYPE_PARTIAL_LINE; + + if (!seq_print_ip_sym(s, field->ret.func, flags)) + return TRACE_TYPE_PARTIAL_LINE; + + if (!trace_seq_puts(s, "\n")) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ret_entry *field; + + trace_assign_type(field, iter->ent); + + if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n", + field->ret.func, + field->ret.calltime, + field->ret.rettime, + field->ret.overrun, + field->ret.depth)); + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ret_entry *field; + struct trace_seq *s = &iter->seq; + + trace_assign_type(field, iter->ent); + + SEQ_PUT_HEX_FIELD_RET(s, field->ret.func); + SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime); + SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime); + SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun); + SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth); + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags, + struct trace_event *event) +{ + struct ftrace_graph_ret_entry *field; + struct trace_seq *s = &iter->seq; + + trace_assign_type(field, iter->ent); + + SEQ_PUT_FIELD_RET(s, field->ret.func); + SEQ_PUT_FIELD_RET(s, field->ret.calltime); + SEQ_PUT_FIELD_RET(s, field->ret.rettime); + SEQ_PUT_FIELD_RET(s, field->ret.overrun); + SEQ_PUT_FIELD_RET(s, field->ret.depth); + + return TRACE_TYPE_HANDLED; +} + +static struct trace_event_functions trace_graph_ret_funcs = { + .trace = trace_graph_ret_trace, + .raw = trace_graph_ret_raw, + .hex = trace_graph_ret_hex, + .binary = trace_graph_ret_bin, +}; + +static struct trace_event trace_graph_ret_event = { + .type = TRACE_GRAPH_RET, + .funcs = &trace_graph_ret_funcs, +}; + /* TRACE_CTX an TRACE_WAKE */ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, char *delim) @@ -1232,6 +1394,8 @@ static struct trace_event trace_print_event = { static struct trace_event *events[] __initdata = { &trace_fn_event, + &trace_graph_ent_event, + &trace_graph_ret_event, &trace_ctx_event, &trace_wake_event, &trace_stack_event, -- cgit v1.2.3 From 99dd30a309b22219bf98146141f27030ab8fff33 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 28 Oct 2015 10:45:04 -0700 Subject: trace: fix compilation for 4.1 Change-Id: Id88b5d30847bc6d3cfe1d8cd00cbdc975c9712d1 Signed-off-by: Dmitry Shmidt --- kernel/trace/trace.c | 10 ++++----- kernel/trace/trace_output.c | 50 +++++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 27 deletions(-) (limited to 'kernel') diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 225d450cd84d..5f375d4c05fb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1352,7 +1352,7 @@ void tracing_reset_all_online_cpus(void) #define SAVED_CMDLINES_DEFAULT 128 #define NO_CMDLINE_MAP UINT_MAX -static unsigned saved_tgids[SAVED_CMDLINES]; +static unsigned saved_tgids[SAVED_CMDLINES_DEFAULT]; static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; struct saved_cmdlines_buffer { unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; @@ -1641,7 +1641,7 @@ int trace_find_tgid(int pid) preempt_disable(); arch_spin_lock(&trace_cmdline_lock); - map = map_pid_to_cmdline[pid]; + map = savedcmd->map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) tgid = saved_tgids[map]; else @@ -4215,17 +4215,17 @@ tracing_saved_tgids_read(struct file *file, char __user *ubuf, int pid; int i; - file_buf = kmalloc(SAVED_CMDLINES*(16+1+16), GFP_KERNEL); + file_buf = kmalloc(SAVED_CMDLINES_DEFAULT*(16+1+16), GFP_KERNEL); if (!file_buf) return -ENOMEM; buf = file_buf; - for (i = 0; i < SAVED_CMDLINES; i++) { + for (i = 0; i < SAVED_CMDLINES_DEFAULT; i++) { int tgid; int r; - pid = map_cmdline_to_pid[i]; + pid = savedcmd->map_cmdline_to_pid[i]; if (pid == -1 || pid == NO_CMDLINE_MAP) continue; diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index d03ecf65ad53..3bc4b6de0f4d 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -864,13 +864,15 @@ static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int trace_assign_type(field, iter->ent); - if (!trace_seq_puts(s, "graph_ent: func=")) + trace_seq_puts(s, "graph_ent: func="); + if (trace_seq_has_overflowed(s)) return TRACE_TYPE_PARTIAL_LINE; if (!seq_print_ip_sym(s, field->graph_ent.func, flags)) return TRACE_TYPE_PARTIAL_LINE; - if (!trace_seq_puts(s, "\n")) + trace_seq_puts(s, "\n"); + if (trace_seq_has_overflowed(s)) return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_HANDLED; @@ -883,9 +885,10 @@ static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - if (!trace_seq_printf(&iter->seq, "%lx %d\n", + trace_seq_printf(&iter->seq, "%lx %d\n", field->graph_ent.func, - field->graph_ent.depth)) + field->graph_ent.depth); + if (trace_seq_has_overflowed(&iter->seq)) return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_HANDLED; @@ -899,8 +902,8 @@ static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func); - SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth); + SEQ_PUT_HEX_FIELD(s, field->graph_ent.func); + SEQ_PUT_HEX_FIELD(s, field->graph_ent.depth); return TRACE_TYPE_HANDLED; } @@ -913,8 +916,8 @@ static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - SEQ_PUT_FIELD_RET(s, field->graph_ent.func); - SEQ_PUT_FIELD_RET(s, field->graph_ent.depth); + SEQ_PUT_FIELD(s, field->graph_ent.func); + SEQ_PUT_FIELD(s, field->graph_ent.depth); return TRACE_TYPE_HANDLED; } @@ -941,13 +944,15 @@ static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int trace_assign_type(field, entry); - if (!trace_seq_puts(s, "graph_ret: func=")) + trace_seq_puts(s, "graph_ret: func="); + if (trace_seq_has_overflowed(s)) return TRACE_TYPE_PARTIAL_LINE; if (!seq_print_ip_sym(s, field->ret.func, flags)) return TRACE_TYPE_PARTIAL_LINE; - if (!trace_seq_puts(s, "\n")) + trace_seq_puts(s, "\n"); + if (trace_seq_has_overflowed(s)) return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_HANDLED; @@ -960,12 +965,13 @@ static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n", + trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n", field->ret.func, field->ret.calltime, field->ret.rettime, field->ret.overrun, - field->ret.depth)); + field->ret.depth); + if (trace_seq_has_overflowed(&iter->seq)) return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_HANDLED; @@ -979,11 +985,11 @@ static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - SEQ_PUT_HEX_FIELD_RET(s, field->ret.func); - SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime); - SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime); - SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun); - SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth); + SEQ_PUT_HEX_FIELD(s, field->ret.func); + SEQ_PUT_HEX_FIELD(s, field->ret.calltime); + SEQ_PUT_HEX_FIELD(s, field->ret.rettime); + SEQ_PUT_HEX_FIELD(s, field->ret.overrun); + SEQ_PUT_HEX_FIELD(s, field->ret.depth); return TRACE_TYPE_HANDLED; } @@ -996,11 +1002,11 @@ static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int fl trace_assign_type(field, iter->ent); - SEQ_PUT_FIELD_RET(s, field->ret.func); - SEQ_PUT_FIELD_RET(s, field->ret.calltime); - SEQ_PUT_FIELD_RET(s, field->ret.rettime); - SEQ_PUT_FIELD_RET(s, field->ret.overrun); - SEQ_PUT_FIELD_RET(s, field->ret.depth); + SEQ_PUT_FIELD(s, field->ret.func); + SEQ_PUT_FIELD(s, field->ret.calltime); + SEQ_PUT_FIELD(s, field->ret.rettime); + SEQ_PUT_FIELD(s, field->ret.overrun); + SEQ_PUT_FIELD(s, field->ret.depth); return TRACE_TYPE_HANDLED; } -- cgit v1.2.3 From a2b15c0b536307192d86d310b78b4542fa4cc3dc Mon Sep 17 00:00:00 2001 From: Arun Bharadwaj Date: Wed, 3 Jul 2013 10:35:02 -0700 Subject: tracing/sched: Add trace events to track cpu hotplug. Add ftrace event trace_sched_cpu_hotplug to track cpu hot-add and hot-remove events. This is useful in a variety of power, performance and debug analysis scenarios. Change-Id: I5d202c7a229ffacc3aafb7cf9afee0b0ee7b0931 Signed-off-by: Arun Bharadwaj --- kernel/cpu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'kernel') diff --git a/kernel/cpu.c b/kernel/cpu.c index 74e411acb1f2..37731292f8a1 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -24,6 +24,8 @@ #include #include +#include + #include "smpboot.h" #ifdef CONFIG_SMP @@ -425,6 +427,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) out_release: cpu_hotplug_done(); + trace_sched_cpu_hotplug(cpu, err, 0); if (!err) cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu); return err; @@ -530,6 +533,7 @@ out_notify: __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); out: cpu_hotplug_done(); + trace_sched_cpu_hotplug(cpu, ret, 1); return ret; } -- cgit v1.2.3 From 1eff8f99f9f9418d399fb41c234a4e2675bc7e87 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 29 May 2012 17:33:56 -0700 Subject: PM / Suspend: Print wall time at suspend entry and exit Change-Id: I92f252414c013b018b9a392eae1ee039aa0e89dc Signed-off-by: Todd Poynor --- kernel/power/suspend.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'kernel') diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index f9fe133c13e2..a41c3fbac1e9 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -518,6 +519,18 @@ static int enter_state(suspend_state_t state) return error; } +static void pm_suspend_marker(char *annotation) +{ + struct timespec ts; + struct rtc_time tm; + + getnstimeofday(&ts); + rtc_time_to_tm(ts.tv_sec, &tm); + pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", + annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); +} + /** * pm_suspend - Externally visible function for suspending the system. * @state: System sleep state to enter. @@ -532,6 +545,7 @@ int pm_suspend(suspend_state_t state) if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; + pm_suspend_marker("entry"); error = enter_state(state); if (error) { suspend_stats.fail++; @@ -539,6 +553,7 @@ int pm_suspend(suspend_state_t state) } else { suspend_stats.success++; } + pm_suspend_marker("exit"); return error; } EXPORT_SYMBOL(pm_suspend); -- cgit v1.2.3 From abcb8499acaef3fa9d650bea13272b01e90ffa7e Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 19 Feb 2014 15:30:47 -0800 Subject: Power: add an API to log wakeup reasons Add API log_wakeup_reason() and expose it to userspace via sysfs path /sys/kernel/wakeup_reasons/last_resume_reason Change-Id: I81addaf420f1338255c5d0638b0d244a99d777d1 Signed-off-by: Ruchi Kandoi --- kernel/power/Makefile | 2 + kernel/power/wakeup_reason.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 kernel/power/wakeup_reason.c (limited to 'kernel') diff --git a/kernel/power/Makefile b/kernel/power/Makefile index cb880a14cc39..22eb9ed879ad 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o + +obj-$(CONFIG_SUSPEND) += wakeup_reason.o diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c new file mode 100644 index 000000000000..ae9bfece9d9a --- /dev/null +++ b/kernel/power/wakeup_reason.c @@ -0,0 +1,132 @@ +/* + * kernel/power/wakeup_reason.c + * + * Logs the reasons which caused the kernel to resume from + * the suspend mode. + * + * Copyright (C) 2014 Google, Inc. + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_WAKEUP_REASON_IRQS 32 +static int irq_list[MAX_WAKEUP_REASON_IRQS]; +static int irq_count; +static struct kobject *wakeup_reason; +static spinlock_t resume_reason_lock; + +static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int irq_no, buf_offset = 0; + struct irq_desc *desc; + spin_lock(&resume_reason_lock); + for (irq_no = 0; irq_no < irq_count; irq_no++) { + desc = irq_to_desc(irq_list[irq_no]); + if (desc && desc->action && desc->action->name) + buf_offset += sprintf(buf + buf_offset, "%d %s\n", + irq_list[irq_no], desc->action->name); + else + buf_offset += sprintf(buf + buf_offset, "%d\n", + irq_list[irq_no]); + } + spin_unlock(&resume_reason_lock); + return buf_offset; +} + +static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, + reason_show, NULL); + +static struct attribute *attrs[] = { + &resume_reason.attr, + NULL, +}; +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +/* + * logs all the wake up reasons to the kernel + * stores the irqs to expose them to the userspace via sysfs + */ +void log_wakeup_reason(int irq) +{ + struct irq_desc *desc; + desc = irq_to_desc(irq); + if (desc && desc->action && desc->action->name) + printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq, + desc->action->name); + else + printk(KERN_INFO "Resume caused by IRQ %d\n", irq); + + spin_lock(&resume_reason_lock); + irq_list[irq_count++] = irq; + spin_unlock(&resume_reason_lock); +} + +/* Detects a suspend and clears all the previous wake up reasons*/ +static int wakeup_reason_pm_event(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + switch (pm_event) { + case PM_SUSPEND_PREPARE: + spin_lock(&resume_reason_lock); + irq_count = 0; + spin_unlock(&resume_reason_lock); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block wakeup_reason_pm_notifier_block = { + .notifier_call = wakeup_reason_pm_event, +}; + +/* Initializes the sysfs parameter + * registers the pm_event notifier + */ +void __init wakeup_reason_init(void) +{ + int retval; + spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); + if (retval) + printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", + __func__, retval); + + wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj); + if (!wakeup_reason) { + printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n", + __func__); + return; + } + retval = sysfs_create_group(wakeup_reason, &attr_group); + if (retval) { + kobject_put(wakeup_reason); + printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n", + __func__, retval); + } +} + +late_initcall(wakeup_reason_init); -- cgit v1.2.3 From 93fd310cb60f2a0589639aa112e196f4fad47e96 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 20 Feb 2014 19:47:38 -0800 Subject: POWER: fix compile warnings in log_wakeup_reason Change I81addaf420f1338255c5d0638b0d244a99d777d1 introduced compile warnings, fix these. Change-Id: I05482a5335599ab96c0a088a7d175c8d4cf1cf69 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index ae9bfece9d9a..82e69fe52d0b 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -35,7 +35,7 @@ static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) + char *buf) { int irq_no, buf_offset = 0; struct irq_desc *desc; @@ -106,7 +106,7 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { /* Initializes the sysfs parameter * registers the pm_event notifier */ -void __init wakeup_reason_init(void) +int __init wakeup_reason_init(void) { int retval; spin_lock_init(&resume_reason_lock); @@ -119,7 +119,7 @@ void __init wakeup_reason_init(void) if (!wakeup_reason) { printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n", __func__); - return; + return 1; } retval = sysfs_create_group(wakeup_reason, &attr_group); if (retval) { @@ -127,6 +127,7 @@ void __init wakeup_reason_init(void) printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n", __func__, retval); } + return 0; } late_initcall(wakeup_reason_init); -- cgit v1.2.3 From 617d4944c9709bfe186ae7dc170a543bb34b752d Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 7 Mar 2014 12:54:30 -0800 Subject: Power: Add guard condition for maximum wakeup reasons Ensure the array for the wakeup reason IRQs does not overflow. Change-Id: Iddc57a3aeb1888f39d4e7b004164611803a4d37c Signed-off-by: Ruchi Kandoi (cherry picked from commit b5ea40cdfcf38296535f931a7e5e7bf47b6fad7f) --- kernel/power/wakeup_reason.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 82e69fe52d0b..caf44213b14c 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -79,6 +79,13 @@ void log_wakeup_reason(int irq) printk(KERN_INFO "Resume caused by IRQ %d\n", irq); spin_lock(&resume_reason_lock); + if (irq_count == MAX_WAKEUP_REASON_IRQS) { + spin_unlock(&resume_reason_lock); + printk(KERN_WARNING "Resume caused by more than %d IRQs\n", + MAX_WAKEUP_REASON_IRQS); + return; + } + irq_list[irq_count++] = irq; spin_unlock(&resume_reason_lock); } -- cgit v1.2.3 From 5753c931919fcedc765d20a01bf957a1218d0799 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 10 Mar 2014 14:21:30 -0700 Subject: power: wakeup_reason: rename irq_count to irqcount On x86, irq_count conflicts with a declaration in arch/x86/include/asm/processor.h Change-Id: I3e4fde0ff64ef59ff5ed2adc0ea3a644641ee0b7 Signed-off-by: Greg Hackmann --- kernel/power/wakeup_reason.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index caf44213b14c..188a6bfacf5a 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -30,7 +30,7 @@ #define MAX_WAKEUP_REASON_IRQS 32 static int irq_list[MAX_WAKEUP_REASON_IRQS]; -static int irq_count; +static int irqcount; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; @@ -40,7 +40,7 @@ static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, int irq_no, buf_offset = 0; struct irq_desc *desc; spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irq_count; irq_no++) { + for (irq_no = 0; irq_no < irqcount; irq_no++) { desc = irq_to_desc(irq_list[irq_no]); if (desc && desc->action && desc->action->name) buf_offset += sprintf(buf + buf_offset, "%d %s\n", @@ -79,14 +79,14 @@ void log_wakeup_reason(int irq) printk(KERN_INFO "Resume caused by IRQ %d\n", irq); spin_lock(&resume_reason_lock); - if (irq_count == MAX_WAKEUP_REASON_IRQS) { + if (irqcount == MAX_WAKEUP_REASON_IRQS) { spin_unlock(&resume_reason_lock); printk(KERN_WARNING "Resume caused by more than %d IRQs\n", MAX_WAKEUP_REASON_IRQS); return; } - irq_list[irq_count++] = irq; + irq_list[irqcount++] = irq; spin_unlock(&resume_reason_lock); } @@ -97,7 +97,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier, switch (pm_event) { case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); - irq_count = 0; + irqcount = 0; spin_unlock(&resume_reason_lock); break; default: -- cgit v1.2.3 From 4407d13a09440957991b89471e635c3fffc91a21 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 24 Apr 2014 14:31:57 -0700 Subject: Power: Changes the permission to read only for sysfs file /sys/kernel/wakeup_reasons/last_resume_reason Change-Id: I8ac568a7cb58c31decd379195de517ff3c6f9c65 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 188a6bfacf5a..187e4e9105fb 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -34,7 +34,7 @@ static int irqcount; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; -static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, +static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int irq_no, buf_offset = 0; @@ -53,8 +53,7 @@ static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, return buf_offset; } -static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, - reason_show, NULL); +static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); static struct attribute *attrs[] = { &resume_reason.attr, -- cgit v1.2.3 From 1adb5b403433616585cae7fa22a61ede2400319a Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Tue, 14 Oct 2014 17:43:21 -0700 Subject: power: Avoids bogus error messages for the suspend aborts. Avoids printing bogus error message "tasks refusing to freeze", in cases where pending wakeup source caused the suspend abort. Signed-off-by: Ruchi Kandoi Change-Id: I913ad290f501b31cd536d039834c8d24c6f16928 --- kernel/power/process.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/power/process.c b/kernel/power/process.c index 564f786df470..fa50018418dc 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -83,15 +83,17 @@ static int try_to_freeze_tasks(bool user_only) do_div(elapsed_msecs64, NSEC_PER_MSEC); elapsed_msecs = elapsed_msecs64; - if (todo) { + if (wakeup) { pr_cont("\n"); - pr_err("Freezing of tasks %s after %d.%03d seconds " - "(%d tasks refusing to freeze, wq_busy=%d):\n", - wakeup ? "aborted" : "failed", + pr_err("Freezing of tasks aborted after %d.%03d seconds", + elapsed_msecs / 1000, elapsed_msecs % 1000); + } else if (todo) { + pr_cont("\n"); + pr_err("Freezing of tasks failed after %d.%03d seconds" + " (%d tasks refusing to freeze, wq_busy=%d):\n", elapsed_msecs / 1000, elapsed_msecs % 1000, todo - wq_busy, wq_busy); - if (!wakeup) { read_lock(&tasklist_lock); for_each_process_thread(g, p) { if (p != current && !freezer_should_skip(p) @@ -99,7 +101,6 @@ static int try_to_freeze_tasks(bool user_only) sched_show_task(p); } read_unlock(&tasklist_lock); - } } else { pr_cont("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, elapsed_msecs % 1000); -- cgit v1.2.3 From 57caa2ad5ce35bedb7ab374a2e5b4d7adf63da2b Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 29 Oct 2014 10:36:27 -0700 Subject: power: Adds functionality to log the last suspend abort reason. Extends the last_resume_reason to log suspend abort reason. The abort reasons will have "Abort:" appended at the start to distinguish itself from the resume reason. Signed-off-by: Ruchi Kandoi Change-Id: I3207f1844e3d87c706dfc298fb10e1c648814c5f --- kernel/power/process.c | 5 +++++ kernel/power/suspend.c | 20 ++++++++++++++++++-- kernel/power/wakeup_reason.c | 42 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 10 deletions(-) (limited to 'kernel') diff --git a/kernel/power/process.c b/kernel/power/process.c index fa50018418dc..37eac4066e71 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * Timeout for stopping processes @@ -35,6 +36,7 @@ static int try_to_freeze_tasks(bool user_only) unsigned int elapsed_msecs; bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; do_gettimeofday(&start); @@ -64,6 +66,9 @@ static int try_to_freeze_tasks(bool user_only) break; if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); wakeup = true; break; } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index a41c3fbac1e9..024411816ccf 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "power.h" @@ -313,7 +314,8 @@ void __weak arch_suspend_enable_irqs(void) */ static int suspend_enter(suspend_state_t state, bool *wakeup) { - int error; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; + int error, last_dev; error = platform_suspend_prepare(state); if (error) @@ -321,7 +323,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_late(PMSG_SUSPEND); if (error) { + last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; + last_dev %= REC_FAILED_NUM; printk(KERN_ERR "PM: late suspend of devices failed\n"); + log_suspend_abort_reason("%s device failed to power down", + suspend_stats.failed_devs[last_dev]); goto Platform_finish; } error = platform_suspend_prepare_late(state); @@ -330,7 +336,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_noirq(PMSG_SUSPEND); if (error) { + last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; + last_dev %= REC_FAILED_NUM; printk(KERN_ERR "PM: noirq suspend of devices failed\n"); + log_suspend_abort_reason("noirq suspend of %s device failed", + suspend_stats.failed_devs[last_dev]); goto Platform_early_resume; } error = platform_suspend_prepare_noirq(state); @@ -354,8 +364,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) } error = disable_nonboot_cpus(); - if (error || suspend_test(TEST_CPUS)) + if (error || suspend_test(TEST_CPUS)) { + log_suspend_abort_reason("Disabling non-boot cpus failed"); goto Enable_cpus; + } arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); @@ -371,6 +383,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) state, false); events_check_enabled = false; } else if (*wakeup) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); error = -EBUSY; } syscore_resume(); @@ -418,6 +433,7 @@ int suspend_devices_and_enter(suspend_state_t state) error = dpm_suspend_start(PMSG_SUSPEND); if (error) { pr_err("PM: Some devices failed to suspend, or early wake event detected\n"); + log_suspend_abort_reason("Some devices failed to suspend, or early wake event detected"); goto Recover_platform; } suspend_test_finish("suspend devices"); diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 187e4e9105fb..2aacc34ef17c 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -31,6 +31,8 @@ #define MAX_WAKEUP_REASON_IRQS 32 static int irq_list[MAX_WAKEUP_REASON_IRQS]; static int irqcount; +static bool suspend_abort; +static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; @@ -40,14 +42,18 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribu int irq_no, buf_offset = 0; struct irq_desc *desc; spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irqcount; irq_no++) { - desc = irq_to_desc(irq_list[irq_no]); - if (desc && desc->action && desc->action->name) - buf_offset += sprintf(buf + buf_offset, "%d %s\n", - irq_list[irq_no], desc->action->name); - else - buf_offset += sprintf(buf + buf_offset, "%d\n", - irq_list[irq_no]); + if (suspend_abort) { + buf_offset = sprintf(buf, "Abort: %s", abort_reason); + } else { + for (irq_no = 0; irq_no < irqcount; irq_no++) { + desc = irq_to_desc(irq_list[irq_no]); + if (desc && desc->action && desc->action->name) + buf_offset += sprintf(buf + buf_offset, "%d %s\n", + irq_list[irq_no], desc->action->name); + else + buf_offset += sprintf(buf + buf_offset, "%d\n", + irq_list[irq_no]); + } } spin_unlock(&resume_reason_lock); return buf_offset; @@ -89,6 +95,25 @@ void log_wakeup_reason(int irq) spin_unlock(&resume_reason_lock); } +void log_suspend_abort_reason(const char *fmt, ...) +{ + va_list args; + + spin_lock(&resume_reason_lock); + + //Suspend abort reason has already been logged. + if (suspend_abort) { + spin_unlock(&resume_reason_lock); + return; + } + + suspend_abort = true; + va_start(args, fmt); + snprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); + va_end(args); + spin_unlock(&resume_reason_lock); +} + /* Detects a suspend and clears all the previous wake up reasons*/ static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) @@ -97,6 +122,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier, case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; + suspend_abort = false; spin_unlock(&resume_reason_lock); break; default: -- cgit v1.2.3 From dd0c7788b67fed52d2d2b9893f7290e3c63757b8 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 31 Oct 2014 16:05:46 -0700 Subject: power: Add check_wakeup_reason() to verify wakeup source irq Wakeup reason is set before driver resume handlers are called. It is cleared before driver suspend handlers are called, on PM_SUSPEND_PREPARE. Change-Id: I04218c9b0c115a7877e8029c73e6679ff82e0aa4 Signed-off-by: Dmitry Shmidt --- kernel/power/wakeup_reason.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 2aacc34ef17c..085c99edca06 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -34,7 +34,7 @@ static int irqcount; static bool suspend_abort; static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; -static spinlock_t resume_reason_lock; +static DEFINE_SPINLOCK(resume_reason_lock); static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -95,6 +95,21 @@ void log_wakeup_reason(int irq) spin_unlock(&resume_reason_lock); } +int check_wakeup_reason(int irq) +{ + int irq_no; + int ret = false; + + spin_lock(&resume_reason_lock); + for (irq_no = 0; irq_no < irqcount; irq_no++) + if (irq_list[irq_no] == irq) { + ret = true; + break; + } + spin_unlock(&resume_reason_lock); + return ret; +} + void log_suspend_abort_reason(const char *fmt, ...) { va_list args; @@ -141,7 +156,7 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { int __init wakeup_reason_init(void) { int retval; - spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); if (retval) printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", -- cgit v1.2.3 From 49f054b7c5fc79fc33560f623f7a2f2bbd92cf08 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 27 Nov 2014 15:12:10 +0900 Subject: Make suspend abort reason logging depend on CONFIG_PM_SLEEP This unbreaks the build on architectures such as um that do not support CONFIG_PM_SLEEP. Change-Id: Ia846ed0a7fca1d762ececad20748d23610e8544f Signed-off-by: Lorenzo Colitti --- kernel/power/process.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'kernel') diff --git a/kernel/power/process.c b/kernel/power/process.c index 37eac4066e71..e7f1f736a5b6 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -36,7 +36,9 @@ static int try_to_freeze_tasks(bool user_only) unsigned int elapsed_msecs; bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; +#ifdef CONFIG_PM_SLEEP char suspend_abort[MAX_SUSPEND_ABORT_LEN]; +#endif do_gettimeofday(&start); @@ -66,9 +68,11 @@ static int try_to_freeze_tasks(bool user_only) break; if (pm_wakeup_pending()) { +#ifdef CONFIG_PM_SLEEP pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); +#endif wakeup = true; break; } -- cgit v1.2.3 From e710ba39fabd14b7236b42c00a33e105a04e5245 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Tue, 3 Mar 2015 09:38:28 -0800 Subject: power: Remove HAS_WAKELOCK config and document WAKELOCK Remove the HAS_WAKELOCK config as it doesn't seem to have been used in the 3.10 or 3.14 kernels. Add some Documentation to CONFIG_WAKELOCK so that it is selectable and can be disabled is desired. Signed-off-by: Dylan Reid --- kernel/power/Kconfig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index deb2df6a7129..84c480946fb2 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -29,8 +29,13 @@ config SUSPEND_SKIP_SYNC user-space before invoking suspend. Say Y if that's your case. config WAKELOCK - bool + bool "Android's method of preventing suspend" default y + ---help--- + This allows applications to prevent the CPU from suspending while + they need it. + + Say Y if you are running an android userspace. config HIBERNATE_CALLBACKS bool -- cgit v1.2.3 From 1cc3aac268e3ad3511f7e55f993f90cda426e7dd Mon Sep 17 00:00:00 2001 From: jinqian Date: Wed, 25 Mar 2015 16:18:44 -0700 Subject: Power: Report suspend times from last_suspend_time This node epxorts two values separated by space. From left to right: 1. time spent in suspend/resume process 2. time spent sleep in suspend state Change-Id: I2cb9a9408a5fd12166aaec11b935a0fd6a408c63 --- kernel/power/wakeup_reason.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 085c99edca06..76b53400cb16 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -36,6 +36,11 @@ static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; static DEFINE_SPINLOCK(resume_reason_lock); +static struct timespec last_xtime; /* wall time before last suspend */ +static struct timespec curr_xtime; /* wall time after last suspend */ +static struct timespec last_stime; /* total_sleep_time before last suspend */ +static struct timespec curr_stime; /* total_sleep_time after last suspend */ + static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -59,10 +64,32 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribu return buf_offset; } +static ssize_t last_suspend_time_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct timespec sleep_time; + struct timespec total_time; + struct timespec suspend_resume_time; + + sleep_time = timespec_sub(curr_stime, last_stime); + total_time = timespec_sub(curr_xtime, last_xtime); + suspend_resume_time = timespec_sub(total_time, sleep_time); + + /* + * suspend_resume_time is calculated from sleep_time. Userspace would + * always need both. Export them in pair here. + */ + return sprintf(buf, "%lu.%09lu %lu.%09lu\n", + suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec, + sleep_time.tv_sec, sleep_time.tv_nsec); +} + static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); +static struct kobj_attribute suspend_time = __ATTR_RO(last_suspend_time); static struct attribute *attrs[] = { &resume_reason.attr, + &suspend_time.attr, NULL, }; static struct attribute_group attr_group = { @@ -133,12 +160,21 @@ void log_suspend_abort_reason(const char *fmt, ...) static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) { + struct timespec xtom; /* wall_to_monotonic, ignored */ + switch (pm_event) { case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; suspend_abort = false; spin_unlock(&resume_reason_lock); + + get_xtime_and_monotonic_and_sleep_offset(&last_xtime, &xtom, + &last_stime); + break; + case PM_POST_SUSPEND: + get_xtime_and_monotonic_and_sleep_offset(&curr_xtime, &xtom, + &curr_stime); break; default: break; -- cgit v1.2.3 From 45e6e572720eed8a105adf59f5c236fd64301b2b Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Tue, 14 Apr 2015 02:38:20 +0530 Subject: power: wakeup_reason: fix suspend time reporting Suspend time reporting Change-Id: I2cb9a9408a5fd12166aaec11b935a0fd6a408c63 (Power: Report suspend times from last_suspend_time), is broken on 3.16+ kernels because get_xtime_and_monotonic_and_sleep_offset() hrtimer helper routine is removed from kernel timekeeping. The replacement helper routines ktime_get_update_offsets_{tick,now}() are private to core kernel timekeeping so we can't use them, hence using ktime_get() and ktime_get_boottime() instead and sampling the time twice. Idea is to use Monotonic boottime offset to calculate total time spent in last suspend state and CLOCK_MONOTONIC to calculate time spent in last suspend-resume process. Signed-off-by: Amit Pundir --- kernel/power/wakeup_reason.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 76b53400cb16..21787ebb332f 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -36,10 +36,10 @@ static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; static DEFINE_SPINLOCK(resume_reason_lock); -static struct timespec last_xtime; /* wall time before last suspend */ -static struct timespec curr_xtime; /* wall time after last suspend */ -static struct timespec last_stime; /* total_sleep_time before last suspend */ -static struct timespec curr_stime; /* total_sleep_time after last suspend */ +static ktime_t last_monotime; /* monotonic time before last suspend */ +static ktime_t curr_monotime; /* monotonic time after last suspend */ +static ktime_t last_stime; /* monotonic boottime offset before last suspend */ +static ktime_t curr_stime; /* monotonic boottime offset after last suspend */ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -71,14 +71,22 @@ static ssize_t last_suspend_time_show(struct kobject *kobj, struct timespec total_time; struct timespec suspend_resume_time; - sleep_time = timespec_sub(curr_stime, last_stime); - total_time = timespec_sub(curr_xtime, last_xtime); - suspend_resume_time = timespec_sub(total_time, sleep_time); + /* + * total_time is calculated from monotonic bootoffsets because + * unlike CLOCK_MONOTONIC it include the time spent in suspend state. + */ + total_time = ktime_to_timespec(ktime_sub(curr_stime, last_stime)); /* - * suspend_resume_time is calculated from sleep_time. Userspace would - * always need both. Export them in pair here. + * suspend_resume_time is calculated as monotonic (CLOCK_MONOTONIC) + * time interval before entering suspend and post suspend. */ + suspend_resume_time = ktime_to_timespec(ktime_sub(curr_monotime, last_monotime)); + + /* sleep_time = total_time - suspend_resume_time */ + sleep_time = timespec_sub(total_time, suspend_resume_time); + + /* Export suspend_resume_time and sleep_time in pair here. */ return sprintf(buf, "%lu.%09lu %lu.%09lu\n", suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec, sleep_time.tv_sec, sleep_time.tv_nsec); @@ -160,21 +168,22 @@ void log_suspend_abort_reason(const char *fmt, ...) static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) { - struct timespec xtom; /* wall_to_monotonic, ignored */ - switch (pm_event) { case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; suspend_abort = false; spin_unlock(&resume_reason_lock); - - get_xtime_and_monotonic_and_sleep_offset(&last_xtime, &xtom, - &last_stime); + /* monotonic time since boot */ + last_monotime = ktime_get(); + /* monotonic time since boot including the time spent in suspend */ + last_stime = ktime_get_boottime(); break; case PM_POST_SUSPEND: - get_xtime_and_monotonic_and_sleep_offset(&curr_xtime, &xtom, - &curr_stime); + /* monotonic time since boot */ + curr_monotime = ktime_get(); + /* monotonic time since boot including the time spent in suspend */ + curr_stime = ktime_get_boottime(); break; default: break; -- cgit v1.2.3 From 1f027b30b538458d50fa7a40d0ef0ddfed8cd3f2 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 5 Aug 2015 16:54:53 -0700 Subject: wakeup_reason: use vsnprintf instead of snsprintf for vargs. Bug: 22368519 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 21787ebb332f..252611fad2fe 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -159,7 +159,7 @@ void log_suspend_abort_reason(const char *fmt, ...) suspend_abort = true; va_start(args, fmt); - snprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); + vsnprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); va_end(args); spin_unlock(&resume_reason_lock); } -- cgit v1.2.3 From 6809864a2cc59332b246c183a2b78328f6aa551e Mon Sep 17 00:00:00 2001 From: Rom Lemarchand Date: Fri, 7 Nov 2014 12:48:17 -0800 Subject: cgroup: refactor allow_attach function into common code move cpu_cgroup_allow_attach to a common subsys_cgroup_allow_attach. This allows any process with CAP_SYS_NICE to move tasks across cgroups if they use this function as their allow_attach handler. Bug: 18260435 Change-Id: I6bb4933d07e889d0dc39e33b4e71320c34a2c90f Signed-off-by: Rom Lemarchand --- kernel/cgroup.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'kernel') diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 470f6536b9e8..35591b841db2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2663,6 +2663,25 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp, return ret; } +int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) +{ + const struct cred *cred = current_cred(), *tcred; + struct task_struct *task; + + if (capable(CAP_SYS_NICE)) + return 0; + + cgroup_taskset_for_each(task, css, tset) { + tcred = __task_cred(task); + + if (current != task && !uid_eq(cred->euid, tcred->uid) && + !uid_eq(cred->euid, tcred->suid)) + return -EACCES; + } + + return 0; +} + static int cgroup_procs_write_permission(struct task_struct *task, struct cgroup *dst_cgrp, struct kernfs_open_file *of) -- cgit v1.2.3 From 181104628653c6c66c9c3bb5b937153987228e63 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 12 Jul 2011 19:53:24 -0700 Subject: cgroup: Add generic cgroup subsystem permission checks Rather than using explicit euid == 0 checks when trying to move tasks into a cgroup via CFS, move permission checks into each specific cgroup subsystem. If a subsystem does not specify a 'allow_attach' handler, then we fall back to doing our checks the old way. Use the 'allow_attach' handler for the 'cpu' cgroup to allow non-root processes to add arbitrary processes to a 'cpu' cgroup if it has the CAP_SYS_NICE capability set. This version of the patch adds a 'allow_attach' handler instead of reusing the 'can_attach' handler. If the 'can_attach' handler is reused, a new cgroup that implements 'can_attach' but not the permission checks could end up with no permission checks at all. Change-Id: Icfa950aa9321d1ceba362061d32dc7dfa2c64f0c Original-Author: San Mehat Signed-off-by: Colin Cross --- kernel/cgroup.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 35591b841db2..de6515d19279 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2682,6 +2682,25 @@ int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_ta return 0; } +static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) +{ + struct cgroup_subsys_state *css; + int i; + int ret; + + for_each_css(css, i, cgrp) { + if (css->ss->allow_attach) { + ret = css->ss->allow_attach(css, tset); + if (ret) + return ret; + } else { + return -EACCES; + } + } + + return 0; +} + static int cgroup_procs_write_permission(struct task_struct *task, struct cgroup *dst_cgrp, struct kernfs_open_file *of) @@ -2696,8 +2715,23 @@ static int cgroup_procs_write_permission(struct task_struct *task, */ if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) && !uid_eq(cred->euid, tcred->uid) && - !uid_eq(cred->euid, tcred->suid)) - ret = -EACCES; + !uid_eq(cred->euid, tcred->suid)) { + /* + * if the default permission check fails, give each + * cgroup a chance to extend the permission check + */ + struct cgroup_taskset tset = { + .src_csets = LIST_HEAD_INIT(tset.src_csets), + .dst_csets = LIST_HEAD_INIT(tset.dst_csets), + .csets = &tset.src_csets, + }; + struct css_set *cset; + cset = task_css_set(task); + list_add(&cset->mg_node, &tset.src_csets); + ret = cgroup_allow_attach(dst_cgrp, &tset); + if (ret) + ret = -EACCES; + } if (!ret && cgroup_on_dfl(dst_cgrp)) { struct super_block *sb = of->file->f_path.dentry->d_sb; -- cgit v1.2.3 From 0d6687a82af23846e8aa6786bcc672ca16b0a5c6 Mon Sep 17 00:00:00 2001 From: Rom Lemarchand Date: Tue, 26 May 2015 17:00:44 -0700 Subject: cgroup: Fix issues in allow_attach callback - Return -EINVAL when cgroups support isn't enabled - Add allow_attach callback in CPU cgroups Change-Id: Id3360b4a39919524fc4b6fcbd44fa2050009f000 Signed-off-by: Rom Lemarchand --- kernel/sched/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel') diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 67359c7f35db..61b0914cc7aa 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8609,6 +8609,7 @@ struct cgroup_subsys cpu_cgrp_subsys = { .fork = cpu_cgroup_fork, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, + .allow_attach = subsys_cgroup_allow_attach, .legacy_cftypes = cpu_files, .early_init = 1, }; -- cgit v1.2.3 From f4adb71017ba546f8077b681c3953479e580a541 Mon Sep 17 00:00:00 2001 From: Christian Poetzsch Date: Wed, 3 Jun 2015 12:07:33 +0100 Subject: Fix generic cgroup subsystem permission checks In 53b5e2f generic cgroup subsystem permission checks have been added. When this is been done within procs_write an empty taskset is added to the tasks css set. When a task later on migrates to a new group we see a dmesg warning cause the mg_node isn't empty (cgroup.c:2086). Cause this happens all the time this spams dmesg. I am not really familiar with this code, but it looks to me like adding the taskset is just a temporary action in this context. Therefore this taskset should be removed after the actual check. This is what this fix does. This problem was seen and the fix tested on x86 using l-mr1 and master. Change-Id: I9894d39e8b5692ef65149002b07e65a84a33ffea Signed-off-by: Christian Poetzsch --- kernel/cgroup.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel') diff --git a/kernel/cgroup.c b/kernel/cgroup.c index de6515d19279..ad495f0f59bb 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2729,6 +2729,7 @@ static int cgroup_procs_write_permission(struct task_struct *task, cset = task_css_set(task); list_add(&cset->mg_node, &tset.src_csets); ret = cgroup_allow_attach(dst_cgrp, &tset); + list_del(&tset.src_csets); if (ret) ret = -EACCES; } -- cgit v1.2.3 From 69db8fca423ad74f6a16f7d499b5a1006335e4df Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 27 Oct 2015 18:18:04 -0700 Subject: cgroup: fix cgroup_taskset_for_each call in allow_attach() for 4.1 Change-Id: I05013f6e76c30b0ece3671f9f2b4bbdc626cd35c Signed-off-by: Dmitry Shmidt --- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ad495f0f59bb..7fd423e55046 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2671,7 +2671,7 @@ int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_ta if (capable(CAP_SYS_NICE)) return 0; - cgroup_taskset_for_each(task, css, tset) { + cgroup_taskset_for_each(task, tset) { tcred = __task_cred(task); if (current != task && !uid_eq(cred->euid, tcred->uid) && -- cgit v1.2.3 From 703920c14a3caa66862bd12b88a7ed6460ebef6b Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Mon, 21 Dec 2015 16:01:10 +0530 Subject: cgroup: refactor allow_attach handler for 4.4 Refactor *allow_attach() handler to align it with the changes from mainline commit 1f7dd3e5a6e4 "cgroup: fix handling of multi-destination migration from subtree_control enabling". Signed-off-by: Amit Pundir --- kernel/cgroup.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7fd423e55046..a57b7c86871c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2663,15 +2663,16 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp, return ret; } -int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) +int subsys_cgroup_allow_attach(struct cgroup_taskset *tset) { const struct cred *cred = current_cred(), *tcred; struct task_struct *task; + struct cgroup_subsys_state *css; if (capable(CAP_SYS_NICE)) return 0; - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, css, tset) { tcred = __task_cred(task); if (current != task && !uid_eq(cred->euid, tcred->uid) && @@ -2690,7 +2691,7 @@ static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) for_each_css(css, i, cgrp) { if (css->ss->allow_attach) { - ret = css->ss->allow_attach(css, tset); + ret = css->ss->allow_attach(tset); if (ret) return ret; } else { -- cgit v1.2.3 From f2902f9065c5ec4f475367e5d39bdfff0d41fda6 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 18 Apr 2014 14:07:28 -0700 Subject: prctl: adds PR_SET_TIMERSLACK_PID for setting timer slack of an arbitrary thread. Second argument is similar to PR_SET_TIMERSLACK, if non-zero then the slack is set to that value otherwise sets it to the default for the thread. Takes PID of the thread as the third argument. This allows power/performance management software to set timer slack for other threads according to its policy for the thread (such as when the thread is designated foreground vs. background activity) Change-Id: I744d451ff4e60dae69f38f53948ff36c51c14a3f Signed-off-by: Ruchi Kandoi --- kernel/sys.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index 6af9212ab5aa..fd0680992912 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2076,6 +2076,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { struct task_struct *me = current; + struct task_struct *tsk; unsigned char comm[sizeof(me->comm)]; long error; @@ -2199,6 +2200,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else return -EINVAL; break; + case PR_SET_TIMERSLACK_PID: + rcu_read_lock(); + tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); + if (tsk == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + get_task_struct(tsk); + rcu_read_unlock(); + if (arg2 <= 0) + tsk->timer_slack_ns = + tsk->default_timer_slack_ns; + else + tsk->timer_slack_ns = arg2; + put_task_struct(tsk); + error = 0; + break; default: return -EINVAL; } -- cgit v1.2.3 From 2476d3c24159f3b7113d2a36685ba81ae5209648 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 13 Jun 2014 17:03:01 -0700 Subject: prctl: adds the capable(CAP_SYS_NICE) check to PR_SET_TIMERSLACK_PID. Adds a capable() check to make sure that arbitary apps do not change the timer slack for other apps. Bug: 15000427 Change-Id: I558a2551a0e3579c7f7e7aae54b28aa9d982b209 Signed-off-by: Ruchi Kandoi --- kernel/sys.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index fd0680992912..d448bad88823 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2201,6 +2201,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; break; case PR_SET_TIMERSLACK_PID: + if (current->pid != (pid_t)arg3 && + !capable(CAP_SYS_NICE)) + return -EPERM; rcu_read_lock(); tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); if (tsk == NULL) { -- cgit v1.2.3 From 18f42f60bedb93c9e90641bf9a551f9c0caf0a40 Mon Sep 17 00:00:00 2001 From: Micha Kalfon Date: Tue, 13 Jan 2015 11:47:20 +0200 Subject: prctl: fix misplaced PR_SET_TIMERSLACK_PID case The case clause for the PR_SET_TIMERSLACK_PID option was placed inside the an internal switch statement for PR_MCE_KILL (see commits 37a591d4 and 8ae872f1) . This commit moves it to the right place. Change-Id: I63251669d7e2f2aa843d1b0900e7df61518c3dea Signed-off-by: Micha Kalfon Acked-by: Oren Laadan --- kernel/sys.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index d448bad88823..0f45fb855fe3 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2200,26 +2200,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else return -EINVAL; break; - case PR_SET_TIMERSLACK_PID: - if (current->pid != (pid_t)arg3 && - !capable(CAP_SYS_NICE)) - return -EPERM; - rcu_read_lock(); - tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); - if (tsk == NULL) { - rcu_read_unlock(); - return -EINVAL; - } - get_task_struct(tsk); - rcu_read_unlock(); - if (arg2 <= 0) - tsk->timer_slack_ns = - tsk->default_timer_slack_ns; - else - tsk->timer_slack_ns = arg2; - put_task_struct(tsk); - error = 0; - break; default: return -EINVAL; } @@ -2239,6 +2219,26 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_GET_TID_ADDRESS: error = prctl_get_tid_address(me, (int __user **)arg2); break; + case PR_SET_TIMERSLACK_PID: + if (current->pid != (pid_t)arg3 && + !capable(CAP_SYS_NICE)) + return -EPERM; + rcu_read_lock(); + tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); + if (tsk == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + get_task_struct(tsk); + rcu_read_unlock(); + if (arg2 <= 0) + tsk->timer_slack_ns = + tsk->default_timer_slack_ns; + else + tsk->timer_slack_ns = arg2; + put_task_struct(tsk); + error = 0; + break; case PR_SET_CHILD_SUBREAPER: me->signal->is_child_subreaper = !!arg2; break; -- cgit v1.2.3 From d4d049c55d0f0fa7fb5521a83c7e0c029c80e7c0 Mon Sep 17 00:00:00 2001 From: Micha Kalfon Date: Tue, 13 Jan 2015 12:12:57 +0200 Subject: prctl: make PR_SET_TIMERSLACK_PID pid namespace aware Make PR_SET_TIMERSLACK_PID consider pid namespace and resolve the target pid in the caller's namespace. Otherwise, calls from pid namespace other than init would fail or affect the wrong task. Change-Id: I1da15196abc4096536713ce03714e99d2e63820a Signed-off-by: Micha Kalfon Acked-by: Oren Laadan --- kernel/sys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index 0f45fb855fe3..66b933a5c061 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2220,11 +2220,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, error = prctl_get_tid_address(me, (int __user **)arg2); break; case PR_SET_TIMERSLACK_PID: - if (current->pid != (pid_t)arg3 && + if (task_pid_vnr(current) != (pid_t)arg3 && !capable(CAP_SYS_NICE)) return -EPERM; rcu_read_lock(); - tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); + tsk = find_task_by_vpid((pid_t)arg3); if (tsk == NULL) { rcu_read_unlock(); return -EINVAL; -- cgit v1.2.3 From 9d19f72b43f495f6f1ef1268dbed1bbade8dea24 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 16 Sep 2009 12:39:10 -0700 Subject: proc: smaps: Allow smaps access for CAP_SYS_RESOURCE Signed-off-by: San Mehat --- kernel/fork.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/fork.c b/kernel/fork.c index 1155eac61687..7ec6e9939b2c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -800,7 +800,8 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) mm = get_task_mm(task); if (mm && mm != current->mm && - !ptrace_may_access(task, mode)) { + !ptrace_may_access(task, mode) && + !capable(CAP_SYS_RESOURCE)) { mmput(mm); mm = ERR_PTR(-EACCES); } -- cgit v1.2.3 From 3200304ca37de8cdcce2b880c619a08537518592 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 9 May 2005 14:10:26 -0700 Subject: ARM: Make low-level printk work Makes low-level printk work. Signed-off-by: Tony Lindgren --- kernel/printk/printk.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'kernel') diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 2ce8826f1053..eeee1032667f 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -55,6 +55,10 @@ #include "console_cmdline.h" #include "braille.h" +#ifdef CONFIG_DEBUG_LL +extern void printascii(char *); +#endif + int console_printk[4] = { CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */ @@ -1724,6 +1728,10 @@ asmlinkage int vprintk_emit(int facility, int level, */ text_len = vscnprintf(text, sizeof(textbuf), fmt, args); +#ifdef CONFIG_DEBUG_LL + printascii(text); +#endif + /* mark and strip a trailing newline */ if (text_len && text[text_len-1] == '\n') { text_len--; -- cgit v1.2.3 From 4e09c510185cb4db2277ce81cce81b7aa06bea45 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 17 Aug 2011 18:31:58 -0500 Subject: panic: Add board ID to panic output At times, it is necessary for boards to provide some additional information as part of panic logs. Provide information on the board hardware as part of panic logs. It is safer to print this information at the very end in case something bad happens as part of the information retrieval itself. To use this, set global mach_panic_string to an appropriate string in the board file. Change-Id: Id12cdda87b0cd2940dd01d52db97e6162f671b4d Signed-off-by: Nishanth Menon --- kernel/panic.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'kernel') diff --git a/kernel/panic.c b/kernel/panic.c index 4b150bc0c6c1..f07bfc9fe613 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -28,6 +28,9 @@ #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 +/* Machine specific panic information string */ +char *mach_panic_string; + int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE; static unsigned long tainted_mask; static int pause_on_oops; @@ -413,6 +416,11 @@ late_initcall(init_oops_id); void print_oops_end_marker(void) { init_oops_id(); + + if (mach_panic_string) + printk(KERN_WARNING "Board Information: %s\n", + mach_panic_string); + pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id); } -- cgit v1.2.3 From 27742380259ba645e43d6454b10ea77213db7dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 14 Jun 2013 19:54:40 -0700 Subject: ARM: Fix "Make low-level printk work" to use a separate config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5ca8db61b595adc642a07ea187bd41fd7636840e Signed-off-by: Arve Hjønnevåg --- kernel/printk/printk.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index eeee1032667f..28fb44dccbad 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -55,7 +55,7 @@ #include "console_cmdline.h" #include "braille.h" -#ifdef CONFIG_DEBUG_LL +#ifdef CONFIG_EARLY_PRINTK_DIRECT extern void printascii(char *); #endif @@ -1728,10 +1728,6 @@ asmlinkage int vprintk_emit(int facility, int level, */ text_len = vscnprintf(text, sizeof(textbuf), fmt, args); -#ifdef CONFIG_DEBUG_LL - printascii(text); -#endif - /* mark and strip a trailing newline */ if (text_len && text[text_len-1] == '\n') { text_len--; @@ -1762,6 +1758,10 @@ asmlinkage int vprintk_emit(int facility, int level, } } +#ifdef CONFIG_EARLY_PRINTK_DIRECT + printascii(text); +#endif + if (level == LOGLEVEL_DEFAULT) level = default_message_loglevel; -- cgit v1.2.3 From f8ade3666c8612c33929f499b3c8800d83f43d84 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Thu, 1 Sep 2011 15:26:50 -0400 Subject: add extra free kbytes tunable Add a userspace visible knob to tell the VM to keep an extra amount of memory free, by increasing the gap between each zone's min and low watermarks. This is useful for realtime applications that call system calls and have a bound on the number of allocations that happen in any short time period. In this application, extra_free_kbytes would be left at an amount equal to or larger than than the maximum number of allocations that happen in any burst. It may also be useful to reduce the memory use of virtual machines (temporarily?), in a way that does not cause memory fragmentation like ballooning does. [ccross] Revived for use on old kernels where no other solution exists. The tunable will be removed on kernels that do better at avoiding direct reclaim. Change-Id: I765a42be8e964bfd3e2886d1ca85a29d60c3bb3e Signed-off-by: Rik van Riel Signed-off-by: Colin Cross --- kernel/sysctl.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'kernel') diff --git a/kernel/sysctl.c b/kernel/sysctl.c index dc6858d6639e..81fe3bde9fee 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -104,6 +104,7 @@ extern char core_pattern[]; extern unsigned int core_pipe_limit; #endif extern int pid_max; +extern int extra_free_kbytes; extern int pid_max_min, pid_max_max; extern int percpu_pagelist_fraction; extern int compat_log; @@ -1392,6 +1393,14 @@ static struct ctl_table vm_table[] = { .proc_handler = min_free_kbytes_sysctl_handler, .extra1 = &zero, }, + { + .procname = "extra_free_kbytes", + .data = &extra_free_kbytes, + .maxlen = sizeof(extra_free_kbytes), + .mode = 0644, + .proc_handler = min_free_kbytes_sysctl_handler, + .extra1 = &zero, + }, { .procname = "percpu_pagelist_fraction", .data = &percpu_pagelist_fraction, -- cgit v1.2.3 From 586278d78bfa926d7a705da2f192325b3469919d Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 27 Oct 2015 16:42:08 -0700 Subject: mm: add a field to store names for private anonymous memory Userspace processes often have multiple allocators that each do anonymous mmaps to get memory. When examining memory usage of individual processes or systems as a whole, it is useful to be able to break down the various heaps that were allocated by each layer and examine their size, RSS, and physical memory usage. This patch adds a user pointer to the shared union in vm_area_struct that points to a null terminated string inside the user process containing a name for the vma. vmas that point to the same address will be merged, but vmas that point to equivalent strings at different addresses will not be merged. Userspace can set the name for a region of memory by calling prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, start, len, (unsigned long)name); Setting the name to NULL clears it. The names of named anonymous vmas are shown in /proc/pid/maps as [anon:] and in /proc/pid/smaps in a new "Name" field that is only present for named vmas. If the userspace pointer is no longer valid all or part of the name will be replaced with "". The idea to store a userspace pointer to reduce the complexity within mm (at the expense of the complexity of reading /proc/pid/mem) came from Dave Hansen. This results in no runtime overhead in the mm subsystem other than comparing the anon_name pointers when considering vma merging. The pointer is stored in a union with fieds that are only used on file-backed mappings, so it does not increase memory usage. Includes fix from Jed Davis for typo in prctl_set_vma_anon_name, which could attempt to set the name across two vmas at the same time due to a typo, which might corrupt the vma list. Fix it to use tmp instead of end to limit the name setting to a single vma at a time. Change-Id: I9aa7b6b5ef536cd780599ba4e2fba8ceebe8b59f Signed-off-by: Dmitry Shmidt --- kernel/sys.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index 66b933a5c061..d0cb632eef8b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -2072,6 +2074,153 @@ static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) } #endif +#ifdef CONFIG_MMU +static int prctl_update_vma_anon_name(struct vm_area_struct *vma, + struct vm_area_struct **prev, + unsigned long start, unsigned long end, + const char __user *name_addr) +{ + struct mm_struct *mm = vma->vm_mm; + int error = 0; + pgoff_t pgoff; + + if (name_addr == vma_get_anon_name(vma)) { + *prev = vma; + goto out; + } + + pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); + *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma, + vma->vm_file, pgoff, vma_policy(vma), + name_addr); + if (*prev) { + vma = *prev; + goto success; + } + + *prev = vma; + + if (start != vma->vm_start) { + error = split_vma(mm, vma, start, 1); + if (error) + goto out; + } + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + goto out; + } + +success: + if (!vma->vm_file) + vma->anon_name = name_addr; + +out: + if (error == -ENOMEM) + error = -EAGAIN; + return error; +} + +static int prctl_set_vma_anon_name(unsigned long start, unsigned long end, + unsigned long arg) +{ + unsigned long tmp; + struct vm_area_struct *vma, *prev; + int unmapped_error = 0; + int error = -EINVAL; + + /* + * If the interval [start,end) covers some unmapped address + * ranges, just ignore them, but return -ENOMEM at the end. + * - this matches the handling in madvise. + */ + vma = find_vma_prev(current->mm, start, &prev); + if (vma && start > vma->vm_start) + prev = vma; + + for (;;) { + /* Still start < end. */ + error = -ENOMEM; + if (!vma) + return error; + + /* Here start < (end|vma->vm_end). */ + if (start < vma->vm_start) { + unmapped_error = -ENOMEM; + start = vma->vm_start; + if (start >= end) + return error; + } + + /* Here vma->vm_start <= start < (end|vma->vm_end) */ + tmp = vma->vm_end; + if (end < tmp) + tmp = end; + + /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ + error = prctl_update_vma_anon_name(vma, &prev, start, tmp, + (const char __user *)arg); + if (error) + return error; + start = tmp; + if (prev && start < prev->vm_end) + start = prev->vm_end; + error = unmapped_error; + if (start >= end) + return error; + if (prev) + vma = prev->vm_next; + else /* madvise_remove dropped mmap_sem */ + vma = find_vma(current->mm, start); + } +} + +static int prctl_set_vma(unsigned long opt, unsigned long start, + unsigned long len_in, unsigned long arg) +{ + struct mm_struct *mm = current->mm; + int error; + unsigned long len; + unsigned long end; + + if (start & ~PAGE_MASK) + return -EINVAL; + len = (len_in + ~PAGE_MASK) & PAGE_MASK; + + /* Check to see whether len was rounded up from small -ve to zero */ + if (len_in && !len) + return -EINVAL; + + end = start + len; + if (end < start) + return -EINVAL; + + if (end == start) + return 0; + + down_write(&mm->mmap_sem); + + switch (opt) { + case PR_SET_VMA_ANON_NAME: + error = prctl_set_vma_anon_name(start, end, arg); + break; + default: + error = -EINVAL; + } + + up_write(&mm->mmap_sem); + + return error; +} +#else /* CONFIG_MMU */ +static int prctl_set_vma(unsigned long opt, unsigned long start, + unsigned long len_in, unsigned long arg) +{ + return -EINVAL; +} +#endif + SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { @@ -2287,6 +2436,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_GET_FP_MODE: error = GET_FP_MODE(me); break; + case PR_SET_VMA: + error = prctl_set_vma(arg2, arg3, arg4, arg5); + break; default: error = -EINVAL; break; -- cgit v1.2.3 From 29a4f01daa11254debe7aba980681bb838dfff1b Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Thu, 10 Dec 2015 18:24:51 +0530 Subject: mm: private anonymous memory build fixes for 4.4 Update vma_merge() call in private anonymous memory prctl, introduced in AOSP commit ee8c5f78f09a "mm: add a field to store names for private anonymous memory", so as to align with changes from upstream commit 19a809afe2fe "userfaultfd: teach vma_merge to merge across vma->vm_userfaultfd_ctx". Signed-off-by: Amit Pundir --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index d0cb632eef8b..11333311cf1c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2092,7 +2092,7 @@ static int prctl_update_vma_anon_name(struct vm_area_struct *vma, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - name_addr); + vma->vm_userfaultfd_ctx, name_addr); if (*prev) { vma = *prev; goto success; -- cgit v1.2.3 From d49d88766ba924b3df96d9fc1c1a257b90970b74 Mon Sep 17 00:00:00 2001 From: dcashman Date: Tue, 12 Jan 2016 09:18:57 -0800 Subject: FROMLIST: mm: mmap: Add new /proc tunable for mmap_base ASLR. (cherry picked from commit https://lkml.org/lkml/2015/12/21/337) ASLR only uses as few as 8 bits to generate the random offset for the mmap base address on 32 bit architectures. This value was chosen to prevent a poorly chosen value from dividing the address space in such a way as to prevent large allocations. This may not be an issue on all platforms. Allow the specification of a minimum number of bits so that platforms desiring greater ASLR protection may determine where to place the trade-off. Bug: 24047224 Signed-off-by: Daniel Cashman Signed-off-by: Daniel Cashman Change-Id: Ibf9ed3d4390e9686f5cc34f605d509a20d40e6c2 --- kernel/sysctl.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'kernel') diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 81fe3bde9fee..35bfe0c1360b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1577,6 +1577,28 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS + { + .procname = "mmap_rnd_bits", + .data = &mmap_rnd_bits, + .maxlen = sizeof(mmap_rnd_bits), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = (void *)&mmap_rnd_bits_min, + .extra2 = (void *)&mmap_rnd_bits_max, + }, +#endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS + { + .procname = "mmap_rnd_compat_bits", + .data = &mmap_rnd_compat_bits, + .maxlen = sizeof(mmap_rnd_compat_bits), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = (void *)&mmap_rnd_compat_bits_min, + .extra2 = (void *)&mmap_rnd_compat_bits_max, + }, +#endif { } }; -- cgit v1.2.3 From 55d35d82b7181312d75b8fe67a90a605ffde66b9 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 11 Jan 2013 13:51:48 -0800 Subject: hardlockup: detect hard lockups without NMIs using secondary cpus Emulate NMIs on systems where they are not available by using timer interrupts on other cpus. Each cpu will use its softlockup hrtimer to check that the next cpu is processing hrtimer interrupts by verifying that a counter is increasing. This patch is useful on systems where the hardlockup detector is not available due to a lack of NMIs, for example most ARM SoCs. Without this patch any cpu stuck with interrupts disabled can cause a hardware watchdog reset with no debugging information, but with this patch the kernel can detect the lockup and panic, which can result in useful debugging info. Change-Id: Ia5faf50243e19c1755201212e04c8892d929785a Signed-off-by: Colin Cross --- kernel/watchdog.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 18f34cf75f74..25955235ecdd 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved); static DEFINE_PER_CPU(bool, hard_watchdog_warn); static DEFINE_PER_CPU(bool, watchdog_nmi_touch); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); +#endif +#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU +static cpumask_t __read_mostly watchdog_cpus; +#endif +#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); #endif static unsigned long soft_lockup_nmi_warn; @@ -271,7 +276,7 @@ void touch_softlockup_watchdog_sync(void) __this_cpu_write(watchdog_touch_ts, 0); } -#ifdef CONFIG_HARDLOCKUP_DETECTOR +#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI /* watchdog detector functions */ static bool is_hardlockup(void) { @@ -285,6 +290,76 @@ static bool is_hardlockup(void) } #endif +#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU +static unsigned int watchdog_next_cpu(unsigned int cpu) +{ + cpumask_t cpus = watchdog_cpus; + unsigned int next_cpu; + + next_cpu = cpumask_next(cpu, &cpus); + if (next_cpu >= nr_cpu_ids) + next_cpu = cpumask_first(&cpus); + + if (next_cpu == cpu) + return nr_cpu_ids; + + return next_cpu; +} + +static int is_hardlockup_other_cpu(unsigned int cpu) +{ + unsigned long hrint = per_cpu(hrtimer_interrupts, cpu); + + if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint) + return 1; + + per_cpu(hrtimer_interrupts_saved, cpu) = hrint; + return 0; +} + +static void watchdog_check_hardlockup_other_cpu(void) +{ + unsigned int next_cpu; + + /* + * Test for hardlockups every 3 samples. The sample period is + * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over + * watchdog_thresh (over by 20%). + */ + if (__this_cpu_read(hrtimer_interrupts) % 3 != 0) + return; + + /* check for a hardlockup on the next cpu */ + next_cpu = watchdog_next_cpu(smp_processor_id()); + if (next_cpu >= nr_cpu_ids) + return; + + smp_rmb(); + + if (per_cpu(watchdog_nmi_touch, next_cpu) == true) { + per_cpu(watchdog_nmi_touch, next_cpu) = false; + return; + } + + if (is_hardlockup_other_cpu(next_cpu)) { + /* only warn once */ + if (per_cpu(hard_watchdog_warn, next_cpu) == true) + return; + + if (hardlockup_panic) + panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu); + else + WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu); + + per_cpu(hard_watchdog_warn, next_cpu) = true; + } else { + per_cpu(hard_watchdog_warn, next_cpu) = false; + } +} +#else +static inline void watchdog_check_hardlockup_other_cpu(void) { return; } +#endif + static int is_softlockup(unsigned long touch_ts) { unsigned long now = get_timestamp(); @@ -297,7 +372,7 @@ static int is_softlockup(unsigned long touch_ts) return 0; } -#ifdef CONFIG_HARDLOCKUP_DETECTOR +#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, @@ -360,7 +435,7 @@ static void watchdog_overflow_callback(struct perf_event *event, __this_cpu_write(hard_watchdog_warn, false); return; } -#endif /* CONFIG_HARDLOCKUP_DETECTOR */ +#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */ static void watchdog_interrupt_count(void) { @@ -384,6 +459,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) /* kick the hardlockup detector */ watchdog_interrupt_count(); + /* test for hardlockups on the next cpu */ + watchdog_check_hardlockup_other_cpu(); + /* kick the softlockup detector */ wake_up_process(__this_cpu_read(softlockup_watchdog)); @@ -561,7 +639,7 @@ static void watchdog(unsigned int cpu) watchdog_nmi_disable(cpu); } -#ifdef CONFIG_HARDLOCKUP_DETECTOR +#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI /* * People like the simple clean cpu node info on boot. * Reduce the watchdog noise by only printing messages @@ -659,10 +737,45 @@ static void watchdog_nmi_disable(unsigned int cpu) } } +#else +#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU +static int watchdog_nmi_enable(unsigned int cpu) +{ + /* + * The new cpu will be marked online before the first hrtimer interrupt + * runs on it. If another cpu tests for a hardlockup on the new cpu + * before it has run its first hrtimer, it will get a false positive. + * Touch the watchdog on the new cpu to delay the first check for at + * least 3 sampling periods to guarantee one hrtimer has run on the new + * cpu. + */ + per_cpu(watchdog_nmi_touch, cpu) = true; + smp_wmb(); + cpumask_set_cpu(cpu, &watchdog_cpus); + return 0; +} + +static void watchdog_nmi_disable(unsigned int cpu) +{ + unsigned int next_cpu = watchdog_next_cpu(cpu); + + /* + * Offlining this cpu will cause the cpu before this one to start + * checking the one after this one. If this cpu just finished checking + * the next cpu and updating hrtimer_interrupts_saved, and then the + * previous cpu checks it within one sample period, it will trigger a + * false positive. Touch the watchdog on the next cpu to prevent it. + */ + if (next_cpu < nr_cpu_ids) + per_cpu(watchdog_nmi_touch, next_cpu) = true; + smp_wmb(); + cpumask_clear_cpu(cpu, &watchdog_cpus); +} #else static int watchdog_nmi_enable(unsigned int cpu) { return 0; } static void watchdog_nmi_disable(unsigned int cpu) { return; } -#endif /* CONFIG_HARDLOCKUP_DETECTOR */ +#endif /* CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU */ +#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */ static struct smp_hotplug_thread watchdog_threads = { .store = &softlockup_watchdog, -- cgit v1.2.3