Merge remote-tracking branch 'google-common/deprecated/android-3.4' into lineage-16.0

Change-Id: I363f9d4d0623906eaffffb3747a162ccbc92ccb0
Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
This commit is contained in:
Kevin F. Haggerty
2019-08-06 11:41:21 +02:00
committed by Francescodario Cuzzocrea
parent d9d42139ea
commit 0fdd45c3ac
190 changed files with 4707 additions and 1938 deletions
+6 -6
View File
@@ -3963,23 +3963,23 @@ static int cgroup_clear_css_refs(struct cgroup *cgrp)
return !failed;
}
/* checks if all of the css_sets attached to a cgroup have a refcount of 0.
* Must be called with css_set_lock held */
/* Checks if all of the css_sets attached to a cgroup have a refcount of 0. */
static int cgroup_css_sets_empty(struct cgroup *cgrp)
{
struct cg_cgroup_link *link;
int retval = 1;
read_lock(&css_set_lock);
list_for_each_entry(link, &cgrp->css_sets, cgrp_link_list) {
struct css_set *cg = link->cg;
if (cg && (atomic_read(&cg->refcount) > 0)) {
read_unlock(&css_set_lock);
return 0;
retval = 0;
break;
}
}
read_unlock(&css_set_lock);
return 1;
return retval;
}
static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
+8 -1
View File
@@ -68,7 +68,14 @@ lookup_exec_domain(unsigned int personality)
goto out;
}
#ifdef CONFIG_MODULES
/*
* Disable the request_module here to avoid trying to
* load the personality-8 module, which doesn't exist,
* and results in selinux audit noise.
* Disabling this here avoids folks adding module_request
* to their sepolicy, which is maybe too generous
*/
#if 0
read_unlock(&exec_domains_lock);
request_module("personality-%d", pers);
read_lock(&exec_domains_lock);
+1 -1
View File
@@ -1045,7 +1045,7 @@ void do_exit(long code)
/*
* Make sure we are holding no locks:
*/
debug_check_no_locks_held(tsk);
debug_check_no_locks_held();
/*
* We can do this unlocked here. The futex code uses this flag
* just to verify whether the pi state cleanup has been done
+12
View File
@@ -113,6 +113,18 @@ bool freeze_task(struct task_struct *p)
{
unsigned long flags;
/*
* This check can race with freezer_do_not_count, but worst case that
* will result in an extra wakeup being sent to the task. It does not
* race with freezer_count(), the barriers in freezer_count() and
* freezer_should_skip() ensure that either freezer_count() sees
* freezing == true in try_to_freeze() and freezes, or
* freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task
* normally.
*/
if (freezer_should_skip(p))
return false;
spin_lock_irqsave(&freezer_lock, flags);
if (!freezing(p) || frozen(p)) {
spin_unlock_irqrestore(&freezer_lock, flags);
+3 -2
View File
@@ -61,6 +61,7 @@
#include <linux/nsproxy.h>
#include <linux/ptrace.h>
#include <linux/hugetlb.h>
#include <linux/freezer.h>
#include <asm/futex.h>
@@ -1022,7 +1023,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
if (ret) {
raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
return ret;
}
}
raw_spin_lock_irq(&pi_state->owner->pi_lock);
WARN_ON(list_empty(&pi_state->list));
@@ -1936,7 +1937,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
* is no timeout, or if it has yet to expire.
*/
if (!timeout || timeout->task)
schedule();
freezable_schedule();
}
__set_current_state(TASK_RUNNING);
}
+2 -1
View File
@@ -45,6 +45,7 @@
#include <linux/debugobjects.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/freezer.h>
#include <asm/uaccess.h>
@@ -1564,7 +1565,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
t->task = NULL;
if (likely(t->task))
schedule();
freezable_schedule();
hrtimer_cancel(&t->timer);
mode = HRTIMER_MODE_ABS;
+8 -9
View File
@@ -4044,7 +4044,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len)
}
EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
static void print_held_locks_bug(struct task_struct *curr)
static void print_held_locks_bug(void)
{
if (!debug_locks_off())
return;
@@ -4053,22 +4053,21 @@ static void print_held_locks_bug(struct task_struct *curr)
printk("\n");
printk("=====================================\n");
printk("[ BUG: lock held at task exit time! ]\n");
printk("[ BUG: %s/%d still has locks held! ]\n",
current->comm, task_pid_nr(current));
print_kernel_ident();
printk("-------------------------------------\n");
printk("%s/%d is exiting with locks still held!\n",
curr->comm, task_pid_nr(curr));
lockdep_print_held_locks(curr);
lockdep_print_held_locks(current);
printk("\nstack backtrace:\n");
dump_stack();
}
void debug_check_no_locks_held(struct task_struct *task)
void debug_check_no_locks_held(void)
{
if (unlikely(task->lockdep_depth > 0))
print_held_locks_bug(task);
if (unlikely(current->lockdep_depth > 0))
print_held_locks_bug();
}
EXPORT_SYMBOL_GPL(debug_check_no_locks_held);
void debug_show_all_locks(void)
{
+8
View File
@@ -28,6 +28,14 @@ config CPU_FREQ_LIMIT_USERSPACE
/sys/power/cpufreq_max_limit
/sys/power/cpufreq_table
config HAS_WAKELOCK
bool
default y
config WAKELOCK
bool
default y
config HIBERNATE_CALLBACKS
bool
+2
View File
@@ -11,6 +11,8 @@ obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
block_io.o
obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o
obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
obj-$(CONFIG_SUSPEND) += wakeup_reason.o
+13
View File
@@ -25,6 +25,8 @@
#include <linux/freezer.h>
#include <linux/gfp.h>
#include <linux/syscore_ops.h>
#include <linux/ctype.h>
#include <linux/genhd.h>
#include <scsi/scsi_scan.h>
#include "power.h"
@@ -734,6 +736,17 @@ static int software_resume(void)
/* Check if the device is there */
swsusp_resume_device = name_to_dev_t(resume_file);
/*
* name_to_dev_t is ineffective to verify parition if resume_file is in
* integer format. (e.g. major:minor)
*/
if (isdigit(resume_file[0]) && resume_wait) {
int partno;
while (!get_gendisk(swsusp_resume_device, &partno))
msleep(10);
}
if (!swsusp_resume_device) {
/*
* Some device discovery might still be in progress; we need
+1 -69
View File
@@ -96,64 +96,6 @@ static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
power_attr(pm_async);
static ssize_t
touch_event_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
if (tc_ev_processed == 0)
return snprintf(buf, strnlen("touch_event", MAX_BUF) + 1,
"touch_event");
else
return snprintf(buf, strnlen("null", MAX_BUF) + 1,
"null");
}
static ssize_t
touch_event_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
hrtimer_cancel(&tc_ev_timer);
tc_ev_processed = 0;
/* set a timer to notify the userspace to stop processing
* touch event
*/
hrtimer_start(&tc_ev_timer, touch_evt_timer_val, HRTIMER_MODE_REL);
/* wakeup the userspace poll */
sysfs_notify(kobj, NULL, "touch_event");
return n;
}
power_attr(touch_event);
static ssize_t
touch_event_timer_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return snprintf(buf, MAX_BUF, "%lld", touch_evt_timer_val.tv64);
}
static ssize_t
touch_event_timer_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned long val;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
touch_evt_timer_val = ktime_set(0, val*1000);
return n;
}
power_attr(touch_event_timer);
static void touch_event_fn(struct work_struct *work)
{
/* wakeup the userspace poll */
@@ -969,10 +911,6 @@ power_attr(pm_trace_dev_match);
#endif /* CONFIG_PM_TRACE */
#ifdef CONFIG_USER_WAKELOCK
power_attr(wake_lock);
power_attr(wake_unlock);
#endif
#ifdef CONFIG_SEC_DVFS
DEFINE_MUTEX(dvfs_mutex);
static unsigned long dvfs_id;
@@ -1183,7 +1121,7 @@ power_attr(cpufreq_max_limit);
power_attr(cpufreq_min_limit);
power_attr(cpufreq_table);
#endif
static struct attribute *g[] = {
static struct attribute * g[] = {
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
@@ -1199,15 +1137,9 @@ static struct attribute *g[] = {
&wake_lock_attr.attr,
&wake_unlock_attr.attr,
#endif
&touch_event_attr.attr,
&touch_event_timer_attr.attr,
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
#ifdef CONFIG_USER_WAKELOCK
&wake_lock_attr.attr,
&wake_unlock_attr.attr,
#endif
#endif
#ifdef CONFIG_CPU_FREQ_LIMIT_USERSPACE
&cpufreq_table_attr.attr,
+9 -9
View File
@@ -33,8 +33,8 @@ static int try_to_freeze_tasks(bool user_only)
unsigned int todo;
bool wq_busy = false;
struct timeval start, end;
u64 elapsed_csecs64;
unsigned int elapsed_csecs;
u64 elapsed_msecs64;
unsigned int elapsed_msecs;
bool wakeup = false;
int sleep_usecs = USEC_PER_MSEC;
@@ -94,9 +94,9 @@ static int try_to_freeze_tasks(bool user_only)
}
do_gettimeofday(&end);
elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
do_div(elapsed_csecs64, NSEC_PER_SEC / 100);
elapsed_csecs = elapsed_csecs64;
elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
do_div(elapsed_msecs64, NSEC_PER_MSEC);
elapsed_msecs = elapsed_msecs64;
if (todo) {
/* This does not unfreeze processes that are already frozen
@@ -115,7 +115,7 @@ static int try_to_freeze_tasks(bool user_only)
printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
"(%d tasks refusing to freeze, wq_busy=%d):\n",
wakeup ? "aborted" : "failed",
elapsed_csecs / 100, elapsed_csecs % 100,
elapsed_msecs / 1000, elapsed_msecs % 1000,
todo - wq_busy, wq_busy);
}
@@ -124,14 +124,14 @@ static int try_to_freeze_tasks(bool user_only)
do_each_thread(g, p) {
if (p != current && !freezer_should_skip(p)
&& freezing(p) && !frozen(p) &&
elapsed_csecs > 100)
elapsed_msecs > 1000)
sched_show_task(p);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
}
} else {
printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100,
elapsed_csecs % 100);
printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
elapsed_msecs % 1000);
}
return todo ? -EBUSY : 0;
+2
View File
@@ -177,6 +177,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
if (!(suspend_test(TEST_CORE) || *wakeup)) {
error = suspend_ops->enter(state);
events_check_enabled = false;
} else if (*wakeup) {
error = -EBUSY;
}
syscore_resume();
}
-219
View File
@@ -1,219 +0,0 @@
/* kernel/power/userwakelock.c
*
* Copyright (C) 2005-2008 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 <linux/ctype.h>
#include <linux/module.h>
#include <linux/wakelock.h>
#include <linux/slab.h>
#include "power.h"
enum {
DEBUG_FAILURE = BIT(0),
DEBUG_ERROR = BIT(1),
DEBUG_NEW = BIT(2),
DEBUG_ACCESS = BIT(3),
DEBUG_LOOKUP = BIT(4),
};
static int debug_mask = DEBUG_FAILURE;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
static DEFINE_MUTEX(tree_lock);
struct user_wake_lock {
struct rb_node node;
struct wake_lock wake_lock;
char name[0];
};
struct rb_root user_wake_locks;
static struct user_wake_lock *lookup_wake_lock_name(
const char *buf, int allocate, long *timeoutptr)
{
struct rb_node **p = &user_wake_locks.rb_node;
struct rb_node *parent = NULL;
struct user_wake_lock *l;
int diff;
u64 timeout;
int name_len;
const char *arg;
/* Find length of lock name and start of optional timeout string */
arg = buf;
while (*arg && !isspace(*arg))
arg++;
name_len = arg - buf;
if (!name_len)
goto bad_arg;
while (isspace(*arg))
arg++;
/* Process timeout string */
if (timeoutptr && *arg) {
timeout = simple_strtoull(arg, (char **)&arg, 0);
while (isspace(*arg))
arg++;
if (*arg)
goto bad_arg;
/* convert timeout from nanoseconds to jiffies > 0 */
timeout += (NSEC_PER_SEC / HZ) - 1;
do_div(timeout, (NSEC_PER_SEC / HZ));
if (timeout <= 0)
timeout = 1;
*timeoutptr = timeout;
} else if (*arg)
goto bad_arg;
else if (timeoutptr)
*timeoutptr = 0;
/* Lookup wake lock in rbtree */
while (*p) {
parent = *p;
l = rb_entry(parent, struct user_wake_lock, node);
diff = strncmp(buf, l->name, name_len);
if (!diff && l->name[name_len])
diff = -1;
if (debug_mask & DEBUG_ERROR)
pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",
name_len, buf, l->name, diff);
if (diff < 0)
p = &(*p)->rb_left;
else if (diff > 0)
p = &(*p)->rb_right;
else
return l;
}
/* Allocate and add new wakelock to rbtree */
if (!allocate) {
if (debug_mask & DEBUG_ERROR)
pr_info("lookup_wake_lock_name: %.*s not found\n",
name_len, buf);
return ERR_PTR(-EINVAL);
}
l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);
if (l == NULL) {
if (debug_mask & DEBUG_FAILURE)
pr_err("lookup_wake_lock_name: failed to allocate "
"memory for %.*s\n", name_len, buf);
return ERR_PTR(-ENOMEM);
}
memcpy(l->name, buf, name_len);
if (debug_mask & DEBUG_NEW)
pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);
wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);
rb_link_node(&l->node, parent, p);
rb_insert_color(&l->node, &user_wake_locks);
return l;
bad_arg:
if (debug_mask & DEBUG_ERROR)
pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",
name_len, buf, arg);
return ERR_PTR(-EINVAL);
}
ssize_t wake_lock_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
char *s = buf;
char *end = buf + PAGE_SIZE;
struct rb_node *n;
struct user_wake_lock *l;
mutex_lock(&tree_lock);
for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
l = rb_entry(n, struct user_wake_lock, node);
if (wake_lock_active(&l->wake_lock))
s += scnprintf(s, end - s, "%s ", l->name);
}
s += scnprintf(s, end - s, "\n");
mutex_unlock(&tree_lock);
return (s - buf);
}
ssize_t wake_lock_store(
struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
long timeout;
struct user_wake_lock *l;
mutex_lock(&tree_lock);
l = lookup_wake_lock_name(buf, 1, &timeout);
if (IS_ERR(l)) {
n = PTR_ERR(l);
goto bad_name;
}
if (debug_mask & DEBUG_ACCESS)
pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
if (timeout)
wake_lock_timeout(&l->wake_lock, timeout);
else
wake_lock(&l->wake_lock);
bad_name:
mutex_unlock(&tree_lock);
return n;
}
ssize_t wake_unlock_show(
struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
char *s = buf;
char *end = buf + PAGE_SIZE;
struct rb_node *n;
struct user_wake_lock *l;
mutex_lock(&tree_lock);
for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
l = rb_entry(n, struct user_wake_lock, node);
if (!wake_lock_active(&l->wake_lock))
s += scnprintf(s, end - s, "%s ", l->name);
}
s += scnprintf(s, end - s, "\n");
mutex_unlock(&tree_lock);
return (s - buf);
}
ssize_t wake_unlock_store(
struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
struct user_wake_lock *l;
mutex_lock(&tree_lock);
l = lookup_wake_lock_name(buf, 0, NULL);
if (IS_ERR(l)) {
n = PTR_ERR(l);
goto not_found;
}
if (debug_mask & DEBUG_ACCESS)
pr_info("wake_unlock_store: %s\n", l->name);
wake_unlock(&l->wake_lock);
not_found:
mutex_unlock(&tree_lock);
return n;
}
+8 -8
View File
@@ -27,19 +27,20 @@
#include <linux/notifier.h>
#include <linux/suspend.h>
#define MAX_WAKEUP_REASON_IRQS 32
static int irq_list[MAX_WAKEUP_REASON_IRQS];
static int irqcount;
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,
static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int irq_no, buf_offset = 0;
struct irq_desc *desc;
spin_lock(&resume_reason_lock);
for (irq_no = 0; irq_no < irqcount; irq_no++) {
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",
@@ -52,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, 0444,
reason_show, NULL);
static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
static struct attribute *attrs[] = {
&resume_reason.attr,
@@ -78,14 +78,14 @@ void log_wakeup_reason(int irq)
printk(KERN_INFO "Resume caused by IRQ %d\n", irq);
spin_lock(&resume_reason_lock);
if (irqcount == MAX_WAKEUP_REASON_IRQS) {
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[irqcount++] = irq;
irq_list[irq_count++] = irq;
spin_unlock(&resume_reason_lock);
}
@@ -96,7 +96,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier,
switch (pm_event) {
case PM_SUSPEND_PREPARE:
spin_lock(&resume_reason_lock);
irqcount = 0;
irq_count = 0;
spin_unlock(&resume_reason_lock);
break;
default:
+2 -2
View File
@@ -2212,7 +2212,7 @@ relock:
* Now that we woke up, it's crucial if we're supposed to be
* frozen that we freeze now before running anything substantial.
*/
try_to_freeze();
try_to_freeze_nowarn();
spin_lock_irq(&sighand->siglock);
/*
@@ -2772,7 +2772,7 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
recalc_sigpending();
spin_unlock_irq(&tsk->sighand->siglock);
timeout = schedule_timeout_interruptible(timeout);
timeout = freezable_schedule_timeout_interruptible(timeout);
spin_lock_irq(&tsk->sighand->siglock);
__set_task_blocked(tsk, &tsk->real_blocked);
+73 -74
View File
@@ -37,7 +37,6 @@
static struct alarm_base {
spinlock_t lock;
struct timerqueue_head timerqueue;
struct hrtimer timer;
ktime_t (*gettime)(void);
clockid_t base_clockid;
} alarm_bases[ALARM_NUMTYPE];
@@ -46,6 +45,8 @@ static struct alarm_base {
static ktime_t freezer_delta;
static DEFINE_SPINLOCK(freezer_delta_lock);
static struct wakeup_source *ws;
#ifdef CONFIG_RTC_CLASS
/* rtc timer and device for setting alarm wakeups at suspend */
static struct rtc_timer rtctimer;
@@ -133,21 +134,17 @@ void set_power_on_alarm(long secs, bool enable) { }
* @base: pointer to the base where the timer is being run
* @alarm: pointer to alarm being enqueued.
*
* Adds alarm to a alarm_base timerqueue and if necessary sets
* an hrtimer to run.
* Adds alarm to a alarm_base timerqueue
*
* Must hold base->lock when calling.
*/
static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
{
if (alarm->state & ALARMTIMER_STATE_ENQUEUED)
timerqueue_del(&base->timerqueue, &alarm->node);
timerqueue_add(&base->timerqueue, &alarm->node);
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
hrtimer_try_to_cancel(&base->timer);
hrtimer_start(&base->timer, alarm->node.expires,
HRTIMER_MODE_ABS);
}
}
/**
@@ -155,28 +152,17 @@ static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
* @base: pointer to the base where the timer is running
* @alarm: pointer to alarm being removed
*
* Removes alarm to a alarm_base timerqueue and if necessary sets
* a new timer to run.
* Removes alarm to a alarm_base timerqueue
*
* Must hold base->lock when calling.
*/
static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
{
struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
return;
timerqueue_del(&base->timerqueue, &alarm->node);
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
if (next == &alarm->node) {
hrtimer_try_to_cancel(&base->timer);
next = timerqueue_getnext(&base->timerqueue);
if (!next)
return;
hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);
}
}
@@ -191,42 +177,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
*/
static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
{
struct alarm_base *base = container_of(timer, struct alarm_base, timer);
struct timerqueue_node *next;
struct alarm *alarm = container_of(timer, struct alarm, timer);
struct alarm_base *base = &alarm_bases[alarm->type];
unsigned long flags;
ktime_t now;
int ret = HRTIMER_NORESTART;
int restart = ALARMTIMER_NORESTART;
spin_lock_irqsave(&base->lock, flags);
now = base->gettime();
while ((next = timerqueue_getnext(&base->timerqueue))) {
struct alarm *alarm;
ktime_t expired = next->expires;
alarmtimer_remove(base, alarm);
spin_unlock_irqrestore(&base->lock, flags);
if (expired.tv64 > now.tv64)
break;
if (alarm->function)
restart = alarm->function(alarm, base->gettime());
alarm = container_of(next, struct alarm, node);
timerqueue_del(&base->timerqueue, &alarm->node);
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
alarm->state |= ALARMTIMER_STATE_CALLBACK;
spin_unlock_irqrestore(&base->lock, flags);
if (alarm->function)
restart = alarm->function(alarm, now);
spin_lock_irqsave(&base->lock, flags);
alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
if (restart != ALARMTIMER_NORESTART) {
timerqueue_add(&base->timerqueue, &alarm->node);
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
}
}
if (next) {
hrtimer_set_expires(&base->timer, next->expires);
spin_lock_irqsave(&base->lock, flags);
if (restart != ALARMTIMER_NORESTART) {
hrtimer_set_expires(&alarm->timer, alarm->node.expires);
alarmtimer_enqueue(base, alarm);
ret = HRTIMER_RESTART;
}
spin_unlock_irqrestore(&base->lock, flags);
@@ -259,6 +226,7 @@ static int alarmtimer_suspend(struct device *dev)
unsigned long flags;
struct rtc_device *rtc;
int i;
int ret;
spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta;
@@ -288,8 +256,10 @@ static int alarmtimer_suspend(struct device *dev)
if (min.tv64 == 0)
return 0;
/* XXX - Should we enforce a minimum sleep time? */
WARN_ON(min.tv64 < NSEC_PER_SEC);
if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
__pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
return -EBUSY;
}
/* Setup an rtc timer to fire that far in the future */
rtc_timer_cancel(rtc, &rtctimer);
@@ -297,9 +267,11 @@ static int alarmtimer_suspend(struct device *dev)
now = rtc_tm_to_ktime(tm);
now = ktime_add(now, min);
rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
return 0;
/* Set alarm, if in the past reject suspend briefly to handle */
ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
if (ret < 0)
__pm_wakeup_event(ws, 1 * MSEC_PER_SEC);
return ret;
}
#else
static int alarmtimer_suspend(struct device *dev)
@@ -333,25 +305,55 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
{
timerqueue_init(&alarm->node);
hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
HRTIMER_MODE_ABS);
alarm->timer.function = alarmtimer_fired;
alarm->function = function;
alarm->type = type;
alarm->state = ALARMTIMER_STATE_INACTIVE;
}
/**
* alarm_start - Sets an alarm to fire
* alarm_start - Sets an absolute alarm to fire
* @alarm: ptr to alarm to set
* @start: time to run the alarm
*/
void alarm_start(struct alarm *alarm, ktime_t start)
int alarm_start(struct alarm *alarm, ktime_t start)
{
struct alarm_base *base = &alarm_bases[alarm->type];
unsigned long flags;
int ret;
spin_lock_irqsave(&base->lock, flags);
alarm->node.expires = start;
alarmtimer_enqueue(base, alarm);
ret = hrtimer_start(&alarm->timer, alarm->node.expires,
HRTIMER_MODE_ABS);
spin_unlock_irqrestore(&base->lock, flags);
return ret;
}
/**
* alarm_start_relative - Sets a relative alarm to fire
* @alarm: ptr to alarm to set
* @start: time relative to now to run the alarm
*/
int alarm_start_relative(struct alarm *alarm, ktime_t start)
{
struct alarm_base *base = &alarm_bases[alarm->type];
start = ktime_add(start, base->gettime());
return alarm_start(alarm, start);
}
void alarm_restart(struct alarm *alarm)
{
struct alarm_base *base = &alarm_bases[alarm->type];
unsigned long flags;
spin_lock_irqsave(&base->lock, flags);
if (alarmtimer_active(alarm))
alarmtimer_remove(base, alarm);
alarm->node.expires = start;
hrtimer_set_expires(&alarm->timer, alarm->node.expires);
hrtimer_restart(&alarm->timer);
alarmtimer_enqueue(base, alarm);
spin_unlock_irqrestore(&base->lock, flags);
}
@@ -367,18 +369,12 @@ int alarm_try_to_cancel(struct alarm *alarm)
{
struct alarm_base *base = &alarm_bases[alarm->type];
unsigned long flags;
int ret = -1;
int ret;
spin_lock_irqsave(&base->lock, flags);
if (alarmtimer_callback_running(alarm))
goto out;
if (alarmtimer_is_queued(alarm)) {
ret = hrtimer_try_to_cancel(&alarm->timer);
if (ret >= 0)
alarmtimer_remove(base, alarm);
ret = 1;
} else
ret = 0;
out:
spin_unlock_irqrestore(&base->lock, flags);
return ret;
}
@@ -432,6 +428,12 @@ u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval)
return overrun;
}
u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
{
struct alarm_base *base = &alarm_bases[alarm->type];
return alarm_forward(alarm, base->gettime(), interval);
}
@@ -839,10 +841,6 @@ static int __init alarmtimer_init(void)
for (i = 0; i < ALARM_NUMTYPE; i++) {
timerqueue_init_head(&alarm_bases[i].timerqueue);
spin_lock_init(&alarm_bases[i].lock);
hrtimer_init(&alarm_bases[i].timer,
alarm_bases[i].base_clockid,
HRTIMER_MODE_ABS);
alarm_bases[i].timer.function = alarmtimer_fired;
}
error = alarmtimer_rtc_interface_setup();
@@ -858,6 +856,7 @@ static int __init alarmtimer_init(void)
error = PTR_ERR(pdev);
goto out_drv;
}
ws = wakeup_source_register("alarmtimer");
return 0;
out_drv:
+3
View File
@@ -69,6 +69,9 @@ config EVENT_TRACING
select CONTEXT_SWITCH_TRACER
bool
config GPU_TRACEPOINTS
bool
config EVENT_POWER_TRACING_DEPRECATED
depends on EVENT_TRACING
bool "Deprecated power event trace API, to be removed"
+1
View File
@@ -62,5 +62,6 @@ endif
ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif
obj-$(CONFIG_GPU_TRACEPOINTS) += gpu-traces.o
libftrace-y := ftrace.o
+23
View File
@@ -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 <linux/module.h>
#define CREATE_TRACE_POINTS
#include <trace/events/gpu.h>
EXPORT_TRACEPOINT_SYMBOL(gpu_sched_switch);
EXPORT_TRACEPOINT_SYMBOL(gpu_job_enqueue);
+99 -5
View File
@@ -483,6 +483,7 @@ static const char *trace_options[] = {
"overwrite",
"disable_on_free",
"irq-info",
"print-tgid",
NULL
};
@@ -983,6 +984,7 @@ void tracing_reset_current_online_cpus(void)
static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
static unsigned map_cmdline_to_pid[SAVED_CMDLINES];
static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN];
static unsigned saved_tgids[SAVED_CMDLINES];
static int cmdline_idx;
static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
@@ -1128,6 +1130,7 @@ static void trace_save_cmdline(struct task_struct *tsk)
}
memcpy(&saved_cmdlines[idx], tsk->comm, TASK_COMM_LEN);
saved_tgids[idx] = tsk->tgid;
arch_spin_unlock(&trace_cmdline_lock);
}
@@ -1163,6 +1166,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) || !tracer_enabled ||
@@ -1972,6 +1994,13 @@ static void print_func_help_header(struct trace_array *tr, struct seq_file *m)
seq_puts(m, "# | | | | |\n");
}
static void print_func_help_header_tgid(struct trace_array *tr, struct seq_file *m)
{
print_event_info(tr, m);
seq_puts(m, "# TASK-PID TGID CPU# TIMESTAMP FUNCTION\n");
seq_puts(m, "# | | | | | |\n");
}
static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m)
{
print_event_info(tr, m);
@@ -1984,6 +2013,18 @@ static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *
seq_puts(m, "# | | | |||| | |\n");
}
static void print_func_help_header_irq_tgid(struct trace_array *tr, struct seq_file *m)
{
print_event_info(tr, 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)
{
@@ -2276,9 +2317,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->tr, m);
if (trace_flags & TRACE_ITER_TGID)
print_func_help_header_irq_tgid(iter->tr, m);
else
print_func_help_header_irq(iter->tr, m);
else
print_func_help_header(iter->tr, m);
if (trace_flags & TRACE_ITER_TGID)
print_func_help_header_tgid(iter->tr, m);
else
print_func_help_header(iter->tr, m);
}
}
}
@@ -2932,9 +2979,53 @@ tracing_saved_cmdlines_read(struct file *file, char __user *ubuf,
}
static const struct file_operations tracing_saved_cmdlines_fops = {
.open = tracing_open_generic,
.read = tracing_saved_cmdlines_read,
.llseek = generic_file_llseek,
.open = tracing_open_generic,
.read = tracing_saved_cmdlines_read,
.llseek = generic_file_llseek,
};
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
@@ -4785,6 +4876,9 @@ static __init int tracer_init_debugfs(void)
trace_create_file("saved_cmdlines", 0444, d_tracer,
NULL, &tracing_saved_cmdlines_fops);
trace_create_file("saved_tgids", 0444, d_tracer,
NULL, &tracing_saved_tgids_fops);
trace_create_file("trace_clock", 0644, d_tracer, NULL,
&trace_clock_fops);
+2
View File
@@ -460,6 +460,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;
@@ -671,6 +672,7 @@ enum trace_iterator_flags {
TRACE_ITER_OVERWRITE = 0x200000,
TRACE_ITER_STOP_ON_FREE = 0x400000,
TRACE_ITER_IRQ_INFO = 0x800000,
TRACE_ITER_TGID = 0x1000000,
};
/*
+12 -31
View File
@@ -46,6 +46,8 @@ struct fgraph_data {
#define TRACE_GRAPH_PRINT_DURATION 0x10
#define TRACE_GRAPH_PRINT_ABS_TIME 0x20
#define TRACE_GRAPH_PRINT_IRQS 0x40
#define TRACE_GRAPH_PRINT_FLAT 0x80
static struct tracer_opt trace_opts[] = {
/* Display overruns? (for self-debug purpose) */
@@ -62,6 +64,8 @@ static struct tracer_opt trace_opts[] = {
{ TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) },
/* Display interrupts */
{ TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
/* Use standard trace formatting rather than hierarchical */
{ TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) },
{ } /* Empty entry */
};
@@ -1222,6 +1226,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;
@@ -1279,13 +1286,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 */
@@ -1352,6 +1352,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags)
{
struct trace_iterator *iter = s->private;
if (flags & TRACE_GRAPH_PRINT_FLAT) {
trace_default_header(s);
return;
}
if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
return;
@@ -1422,20 +1427,6 @@ static int func_graph_set_flag(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 __read_mostly = {
.name = "function_graph",
.open = graph_trace_open,
@@ -1458,16 +1449,6 @@ static __init int init_graph_trace(void)
{
max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
if (!register_ftrace_event(&graph_trace_entry_event)) {
pr_warning("Warning: could not register graph trace events\n");
return 1;
}
if (!register_ftrace_event(&graph_trace_ret_event)) {
pr_warning("Warning: could not register graph trace events\n");
return 1;
}
return register_tracer(&graph_trace);
}
+180 -2
View File
@@ -630,11 +630,25 @@ int trace_print_context(struct trace_iterator *iter)
unsigned long secs = (unsigned long)t;
char comm[TASK_COMM_LEN];
int ret;
int tgid;
trace_find_cmdline(entry->pid, comm);
ret = trace_seq_printf(s, "%16s-%-5d [%03d] ",
comm, entry->pid, iter->cpu);
ret = trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid);
if (!ret)
return 0;
if (trace_flags & TRACE_ITER_TGID) {
tgid = trace_find_tgid(entry->pid);
if (tgid < 0)
ret = trace_seq_puts(s, "(-----) ");
else
ret = trace_seq_printf(s, "(%5d) ", tgid);
if (!ret)
return 0;
}
ret = trace_seq_printf(s, "[%03d] ", iter->cpu);
if (!ret)
return 0;
@@ -966,6 +980,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)
@@ -1298,6 +1474,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,
+78 -3
View File
@@ -39,6 +39,8 @@ static DEFINE_PER_CPU(bool, hard_watchdog_warn);
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
#endif
#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
#endif
@@ -174,7 +176,7 @@ void touch_softlockup_watchdog_sync(void)
__raw_get_cpu_var(watchdog_touch_ts) = 0;
}
#ifdef CONFIG_HARDLOCKUP_DETECTOR
#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
/* watchdog detector functions */
static int is_hardlockup(void)
{
@@ -188,6 +190,61 @@ static int is_hardlockup(void)
}
#endif
#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
static int is_hardlockup_other_cpu(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)
{
int 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 */
cpu = cpumask_next(smp_processor_id(), cpu_online_mask);
if (cpu >= nr_cpu_ids)
cpu = cpumask_first(cpu_online_mask);
if (cpu == smp_processor_id())
return;
if (per_cpu(watchdog_nmi_touch, cpu) == true) {
per_cpu(watchdog_nmi_touch, cpu) = false;
return;
}
if (is_hardlockup_other_cpu(cpu)) {
/* only warn once */
if (per_cpu(hard_watchdog_warn, cpu) == true)
return;
if (hardlockup_panic)
panic("Watchdog detected hard LOCKUP on cpu %d", cpu);
else
WARN(1, "Watchdog detected hard LOCKUP on cpu %d", cpu);
per_cpu(hard_watchdog_warn, cpu) = true;
} else {
per_cpu(hard_watchdog_warn, 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(smp_processor_id());
@@ -199,7 +256,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,
@@ -247,6 +304,9 @@ static void watchdog_overflow_callback(struct perf_event *event,
__this_cpu_write(hard_watchdog_warn, false);
return;
}
#endif
#ifdef CONFIG_HARDLOCKUP_DETECTOR
static void watchdog_interrupt_count(void)
{
__this_cpu_inc(hrtimer_interrupts);
@@ -265,6 +325,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));
@@ -359,7 +422,7 @@ static int watchdog(void *unused)
}
#ifdef CONFIG_HARDLOCKUP_DETECTOR
#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static int watchdog_nmi_enable(int cpu)
{
struct perf_event_attr *wd_attr;
@@ -430,6 +493,18 @@ static void watchdog_prepare_cpu(int cpu)
WARN_ON(per_cpu(softlockup_watchdog, cpu));
hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer->function = watchdog_timer_fn;
#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_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;
#endif
}
static int watchdog_enable(int cpu)