Merge branch 'linus' into irq/genirq
This commit is contained in:
@@ -51,6 +51,7 @@ obj-$(CONFIG_UID16) += uid16.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_KALLSYMS) += kallsyms.o
|
||||
obj-$(CONFIG_PM) += power/
|
||||
obj-$(CONFIG_FREEZER) += power/
|
||||
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
|
||||
obj-$(CONFIG_KEXEC) += kexec.o
|
||||
obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
|
||||
|
||||
+77
-17
@@ -54,6 +54,7 @@ asynchronous and synchronous parts of the kernel.
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
static async_cookie_t next_cookie = 1;
|
||||
@@ -132,21 +133,23 @@ static void run_one_entry(void)
|
||||
entry = list_first_entry(&async_pending, struct async_entry, list);
|
||||
|
||||
/* 2) move it to the running queue */
|
||||
list_del(&entry->list);
|
||||
list_add_tail(&entry->list, &async_running);
|
||||
list_move_tail(&entry->list, entry->running);
|
||||
spin_unlock_irqrestore(&async_lock, flags);
|
||||
|
||||
/* 3) run it (and print duration)*/
|
||||
if (initcall_debug && system_state == SYSTEM_BOOTING) {
|
||||
printk("calling %lli_%pF @ %i\n", entry->cookie, entry->func, task_pid_nr(current));
|
||||
printk("calling %lli_%pF @ %i\n", (long long)entry->cookie,
|
||||
entry->func, task_pid_nr(current));
|
||||
calltime = ktime_get();
|
||||
}
|
||||
entry->func(entry->data, entry->cookie);
|
||||
if (initcall_debug && system_state == SYSTEM_BOOTING) {
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
printk("initcall %lli_%pF returned 0 after %lld usecs\n", entry->cookie,
|
||||
entry->func, ktime_to_ns(delta) >> 10);
|
||||
printk("initcall %lli_%pF returned 0 after %lld usecs\n",
|
||||
(long long)entry->cookie,
|
||||
entry->func,
|
||||
(long long)ktime_to_ns(delta) >> 10);
|
||||
}
|
||||
|
||||
/* 4) remove it from the running queue */
|
||||
@@ -205,18 +208,44 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l
|
||||
return newcookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* async_schedule - schedule a function for asynchronous execution
|
||||
* @ptr: function to execute asynchronously
|
||||
* @data: data pointer to pass to the function
|
||||
*
|
||||
* Returns an async_cookie_t that may be used for checkpointing later.
|
||||
* Note: This function may be called from atomic or non-atomic contexts.
|
||||
*/
|
||||
async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
|
||||
{
|
||||
return __async_schedule(ptr, data, &async_pending);
|
||||
return __async_schedule(ptr, data, &async_running);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_schedule);
|
||||
|
||||
async_cookie_t async_schedule_special(async_func_ptr *ptr, void *data, struct list_head *running)
|
||||
/**
|
||||
* async_schedule_domain - schedule a function for asynchronous execution within a certain domain
|
||||
* @ptr: function to execute asynchronously
|
||||
* @data: data pointer to pass to the function
|
||||
* @running: running list for the domain
|
||||
*
|
||||
* Returns an async_cookie_t that may be used for checkpointing later.
|
||||
* @running may be used in the async_synchronize_*_domain() functions
|
||||
* to wait within a certain synchronization domain rather than globally.
|
||||
* A synchronization domain is specified via the running queue @running to use.
|
||||
* Note: This function may be called from atomic or non-atomic contexts.
|
||||
*/
|
||||
async_cookie_t async_schedule_domain(async_func_ptr *ptr, void *data,
|
||||
struct list_head *running)
|
||||
{
|
||||
return __async_schedule(ptr, data, running);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_schedule_special);
|
||||
EXPORT_SYMBOL_GPL(async_schedule_domain);
|
||||
|
||||
/**
|
||||
* async_synchronize_full - synchronize all asynchronous function calls
|
||||
*
|
||||
* This function waits until all asynchronous function calls have been done.
|
||||
*/
|
||||
void async_synchronize_full(void)
|
||||
{
|
||||
do {
|
||||
@@ -225,13 +254,30 @@ void async_synchronize_full(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_full);
|
||||
|
||||
void async_synchronize_full_special(struct list_head *list)
|
||||
/**
|
||||
* async_synchronize_full_domain - synchronize all asynchronous function within a certain domain
|
||||
* @list: running list to synchronize on
|
||||
*
|
||||
* This function waits until all asynchronous function calls for the
|
||||
* synchronization domain specified by the running list @list have been done.
|
||||
*/
|
||||
void async_synchronize_full_domain(struct list_head *list)
|
||||
{
|
||||
async_synchronize_cookie_special(next_cookie, list);
|
||||
async_synchronize_cookie_domain(next_cookie, list);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_full_special);
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
|
||||
|
||||
void async_synchronize_cookie_special(async_cookie_t cookie, struct list_head *running)
|
||||
/**
|
||||
* async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing
|
||||
* @cookie: async_cookie_t to use as checkpoint
|
||||
* @running: running list to synchronize on
|
||||
*
|
||||
* This function waits until all asynchronous function calls for the
|
||||
* synchronization domain specified by the running list @list submitted
|
||||
* prior to @cookie have been done.
|
||||
*/
|
||||
void async_synchronize_cookie_domain(async_cookie_t cookie,
|
||||
struct list_head *running)
|
||||
{
|
||||
ktime_t starttime, delta, endtime;
|
||||
|
||||
@@ -247,14 +293,22 @@ void async_synchronize_cookie_special(async_cookie_t cookie, struct list_head *r
|
||||
delta = ktime_sub(endtime, starttime);
|
||||
|
||||
printk("async_continuing @ %i after %lli usec\n",
|
||||
task_pid_nr(current), ktime_to_ns(delta) >> 10);
|
||||
task_pid_nr(current),
|
||||
(long long)ktime_to_ns(delta) >> 10);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_cookie_special);
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_cookie_domain);
|
||||
|
||||
/**
|
||||
* async_synchronize_cookie - synchronize asynchronous function calls with cookie checkpointing
|
||||
* @cookie: async_cookie_t to use as checkpoint
|
||||
*
|
||||
* This function waits until all asynchronous function calls prior to @cookie
|
||||
* have been done.
|
||||
*/
|
||||
void async_synchronize_cookie(async_cookie_t cookie)
|
||||
{
|
||||
async_synchronize_cookie_special(cookie, &async_running);
|
||||
async_synchronize_cookie_domain(cookie, &async_running);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(async_synchronize_cookie);
|
||||
|
||||
@@ -315,7 +369,11 @@ static int async_manager_thread(void *unused)
|
||||
ec = atomic_read(&entry_count);
|
||||
|
||||
while (tc < ec && tc < MAX_THREADS) {
|
||||
kthread_run(async_thread, NULL, "async/%i", tc);
|
||||
if (IS_ERR(kthread_run(async_thread, NULL, "async/%i",
|
||||
tc))) {
|
||||
msleep(100);
|
||||
continue;
|
||||
}
|
||||
atomic_inc(&thread_count);
|
||||
tc++;
|
||||
}
|
||||
@@ -330,7 +388,9 @@ static int async_manager_thread(void *unused)
|
||||
static int __init async_init(void)
|
||||
{
|
||||
if (async_enabled)
|
||||
kthread_run(async_manager_thread, NULL, "async/mgr");
|
||||
if (IS_ERR(kthread_run(async_manager_thread, NULL,
|
||||
"async/mgr")))
|
||||
async_enabled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+21
-12
@@ -1115,13 +1115,15 @@ static void cgroup_kill_sb(struct super_block *sb) {
|
||||
}
|
||||
write_unlock(&css_set_lock);
|
||||
|
||||
list_del(&root->root_list);
|
||||
root_count--;
|
||||
if (!list_empty(&root->root_list)) {
|
||||
list_del(&root->root_list);
|
||||
root_count--;
|
||||
}
|
||||
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
|
||||
kfree(root);
|
||||
kill_litter_super(sb);
|
||||
kfree(root);
|
||||
}
|
||||
|
||||
static struct file_system_type cgroup_fs_type = {
|
||||
@@ -2349,7 +2351,7 @@ static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
|
||||
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
|
||||
struct cgroup_subsys *ss = subsys[i];
|
||||
if (ss->root == root)
|
||||
mutex_lock_nested(&ss->hierarchy_mutex, i);
|
||||
mutex_lock(&ss->hierarchy_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2434,7 +2436,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
||||
|
||||
err_remove:
|
||||
|
||||
cgroup_lock_hierarchy(root);
|
||||
list_del(&cgrp->sibling);
|
||||
cgroup_unlock_hierarchy(root);
|
||||
root->number_of_cgroups--;
|
||||
|
||||
err_destroy:
|
||||
@@ -2507,7 +2511,7 @@ static int cgroup_clear_css_refs(struct cgroup *cgrp)
|
||||
for_each_subsys(cgrp->root, ss) {
|
||||
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
||||
int refcnt;
|
||||
do {
|
||||
while (1) {
|
||||
/* We can only remove a CSS with a refcnt==1 */
|
||||
refcnt = atomic_read(&css->refcnt);
|
||||
if (refcnt > 1) {
|
||||
@@ -2521,7 +2525,10 @@ static int cgroup_clear_css_refs(struct cgroup *cgrp)
|
||||
* css_tryget() to spin until we set the
|
||||
* CSS_REMOVED bits or abort
|
||||
*/
|
||||
} while (atomic_cmpxchg(&css->refcnt, refcnt, 0) != refcnt);
|
||||
if (atomic_cmpxchg(&css->refcnt, refcnt, 0) == refcnt)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
done:
|
||||
for_each_subsys(cgrp->root, ss) {
|
||||
@@ -2630,6 +2637,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
||||
BUG_ON(!list_empty(&init_task.tasks));
|
||||
|
||||
mutex_init(&ss->hierarchy_mutex);
|
||||
lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key);
|
||||
ss->active = 1;
|
||||
}
|
||||
|
||||
@@ -2991,20 +2999,21 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
return 0;
|
||||
}
|
||||
task_lock(tsk);
|
||||
cg = tsk->cgroups;
|
||||
parent = task_cgroup(tsk, subsys->subsys_id);
|
||||
|
||||
/* Pin the hierarchy */
|
||||
if (!atomic_inc_not_zero(&parent->root->sb->s_active)) {
|
||||
if (!atomic_inc_not_zero(&root->sb->s_active)) {
|
||||
/* We race with the final deactivate_super() */
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Keep the cgroup alive */
|
||||
task_lock(tsk);
|
||||
parent = task_cgroup(tsk, subsys->subsys_id);
|
||||
cg = tsk->cgroups;
|
||||
get_css_set(cg);
|
||||
task_unlock(tsk);
|
||||
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
|
||||
/* Now do the VFS work to create a cgroup */
|
||||
@@ -3043,7 +3052,7 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
put_css_set(cg);
|
||||
|
||||
deactivate_super(parent->root->sb);
|
||||
deactivate_super(root->sb);
|
||||
/* The cgroup is still accessible in the VFS, but
|
||||
* we're not going to try to rmdir() it at this
|
||||
* point. */
|
||||
@@ -3069,7 +3078,7 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
|
||||
mutex_lock(&cgroup_mutex);
|
||||
put_css_set(cg);
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
deactivate_super(parent->root->sb);
|
||||
deactivate_super(root->sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -60,6 +60,14 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/cgroup.h>
|
||||
|
||||
/*
|
||||
* Workqueue for cpuset related tasks.
|
||||
*
|
||||
* Using kevent workqueue may cause deadlock when memory_migrate
|
||||
* is set. So we create a separate workqueue thread for cpuset.
|
||||
*/
|
||||
static struct workqueue_struct *cpuset_wq;
|
||||
|
||||
/*
|
||||
* Tracks how many cpusets are currently defined in system.
|
||||
* When there is only one cpuset (the root cpuset) we can
|
||||
@@ -831,7 +839,7 @@ static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
|
||||
*/
|
||||
static void async_rebuild_sched_domains(void)
|
||||
{
|
||||
schedule_work(&rebuild_sched_domains_work);
|
||||
queue_work(cpuset_wq, &rebuild_sched_domains_work);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2111,6 +2119,9 @@ void __init cpuset_init_smp(void)
|
||||
|
||||
hotcpu_notifier(cpuset_track_online_cpus, 0);
|
||||
hotplug_memory_notifier(cpuset_track_online_nodes, 10);
|
||||
|
||||
cpuset_wq = create_singlethread_workqueue("cpuset");
|
||||
BUG_ON(!cpuset_wq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+24
-23
@@ -98,7 +98,7 @@ EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
* @size: size of requested memory area
|
||||
* @dma_handle: This will be filled with the correct dma handle
|
||||
* @ret: This pointer will be filled with the virtual address
|
||||
* to allocated area.
|
||||
* to allocated area.
|
||||
*
|
||||
* This function should be only called from per-arch dma_alloc_coherent()
|
||||
* to support allocation from per-device coherent memory pools.
|
||||
@@ -118,31 +118,32 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
mem = dev->dma_mem;
|
||||
if (!mem)
|
||||
return 0;
|
||||
if (unlikely(size > mem->size))
|
||||
return 0;
|
||||
|
||||
*ret = NULL;
|
||||
|
||||
if (unlikely(size > (mem->size << PAGE_SHIFT)))
|
||||
goto err;
|
||||
|
||||
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
|
||||
if (pageno >= 0) {
|
||||
/*
|
||||
* Memory was found in the per-device arena.
|
||||
*/
|
||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||
memset(*ret, 0, size);
|
||||
} else if (mem->flags & DMA_MEMORY_EXCLUSIVE) {
|
||||
/*
|
||||
* The per-device arena is exhausted and we are not
|
||||
* permitted to fall back to generic memory.
|
||||
*/
|
||||
*ret = NULL;
|
||||
} else {
|
||||
/*
|
||||
* The per-device arena is exhausted and we are
|
||||
* permitted to fall back to generic memory.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (unlikely(pageno < 0))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Memory was found in the per-device area.
|
||||
*/
|
||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||
memset(*ret, 0, size);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
/*
|
||||
* In the case where the allocation can not be satisfied from the
|
||||
* per-device area, try to fall back to generic memory if the
|
||||
* constraints allow it.
|
||||
*/
|
||||
return mem->flags & DMA_MEMORY_EXCLUSIVE;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_alloc_from_coherent);
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@ static void __exit_signal(struct task_struct *tsk)
|
||||
* We won't ever get here for the group leader, since it
|
||||
* will have been the last reference on the signal_struct.
|
||||
*/
|
||||
sig->utime = cputime_add(sig->utime, task_utime(tsk));
|
||||
sig->stime = cputime_add(sig->stime, task_stime(tsk));
|
||||
sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));
|
||||
sig->min_flt += tsk->min_flt;
|
||||
sig->maj_flt += tsk->maj_flt;
|
||||
@@ -126,6 +128,7 @@ static void __exit_signal(struct task_struct *tsk)
|
||||
sig->inblock += task_io_get_inblock(tsk);
|
||||
sig->oublock += task_io_get_oublock(tsk);
|
||||
task_io_accounting_add(&sig->ioac, &tsk->ioac);
|
||||
sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
|
||||
sig = NULL; /* Marker for below. */
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -817,17 +817,17 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig)
|
||||
static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
{
|
||||
struct signal_struct *sig;
|
||||
int ret;
|
||||
|
||||
if (clone_flags & CLONE_THREAD) {
|
||||
ret = thread_group_cputime_clone_thread(current);
|
||||
if (likely(!ret)) {
|
||||
atomic_inc(¤t->signal->count);
|
||||
atomic_inc(¤t->signal->live);
|
||||
}
|
||||
return ret;
|
||||
atomic_inc(¤t->signal->count);
|
||||
atomic_inc(¤t->signal->live);
|
||||
return 0;
|
||||
}
|
||||
sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
|
||||
|
||||
if (sig)
|
||||
posix_cpu_timers_init_group(sig);
|
||||
|
||||
tsk->signal = sig;
|
||||
if (!sig)
|
||||
return -ENOMEM;
|
||||
@@ -851,21 +851,20 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
sig->tty_old_pgrp = NULL;
|
||||
sig->tty = NULL;
|
||||
|
||||
sig->cutime = sig->cstime = cputime_zero;
|
||||
sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
|
||||
sig->gtime = cputime_zero;
|
||||
sig->cgtime = cputime_zero;
|
||||
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
|
||||
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
|
||||
sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
|
||||
task_io_accounting_init(&sig->ioac);
|
||||
sig->sum_sched_runtime = 0;
|
||||
taskstats_tgid_init(sig);
|
||||
|
||||
task_lock(current->group_leader);
|
||||
memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
|
||||
task_unlock(current->group_leader);
|
||||
|
||||
posix_cpu_timers_init_group(sig);
|
||||
|
||||
acct_init_pacct(&sig->pacct);
|
||||
|
||||
tty_audit_fork(sig);
|
||||
@@ -1007,6 +1006,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
* triggers too late. This doesn't hurt, the check is only there
|
||||
* to stop root fork bombs.
|
||||
*/
|
||||
retval = -EAGAIN;
|
||||
if (nr_threads >= max_threads)
|
||||
goto bad_fork_cleanup_count;
|
||||
|
||||
@@ -1095,7 +1095,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
#ifdef CONFIG_DEBUG_MUTEXES
|
||||
p->blocked_on = NULL; /* not blocked yet */
|
||||
#endif
|
||||
if (unlikely(ptrace_reparented(current)))
|
||||
if (unlikely(current->ptrace))
|
||||
ptrace_fork(p, clone_flags);
|
||||
|
||||
/* Perform scheduler related setup. Assign this task to a CPU. */
|
||||
|
||||
+27
-24
@@ -1165,6 +1165,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
|
||||
u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
struct restart_block *restart;
|
||||
DECLARE_WAITQUEUE(wait, curr);
|
||||
struct futex_hash_bucket *hb;
|
||||
struct futex_q q;
|
||||
@@ -1216,11 +1217,13 @@ retry:
|
||||
|
||||
if (!ret)
|
||||
goto retry;
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = -EWOULDBLOCK;
|
||||
if (uval != val)
|
||||
goto out_unlock_put_key;
|
||||
if (unlikely(uval != val)) {
|
||||
queue_unlock(&q, hb);
|
||||
goto out_put_key;
|
||||
}
|
||||
|
||||
/* Only actually queue if *uaddr contained val. */
|
||||
queue_me(&q, hb);
|
||||
@@ -1284,38 +1287,38 @@ retry:
|
||||
*/
|
||||
|
||||
/* If we were woken (and unqueued), we succeeded, whatever. */
|
||||
ret = 0;
|
||||
if (!unqueue_me(&q))
|
||||
return 0;
|
||||
goto out_put_key;
|
||||
ret = -ETIMEDOUT;
|
||||
if (rem)
|
||||
return -ETIMEDOUT;
|
||||
goto out_put_key;
|
||||
|
||||
/*
|
||||
* We expect signal_pending(current), but another thread may
|
||||
* have handled it for us already.
|
||||
*/
|
||||
ret = -ERESTARTSYS;
|
||||
if (!abs_time)
|
||||
return -ERESTARTSYS;
|
||||
else {
|
||||
struct restart_block *restart;
|
||||
restart = ¤t_thread_info()->restart_block;
|
||||
restart->fn = futex_wait_restart;
|
||||
restart->futex.uaddr = (u32 *)uaddr;
|
||||
restart->futex.val = val;
|
||||
restart->futex.time = abs_time->tv64;
|
||||
restart->futex.bitset = bitset;
|
||||
restart->futex.flags = 0;
|
||||
goto out_put_key;
|
||||
|
||||
if (fshared)
|
||||
restart->futex.flags |= FLAGS_SHARED;
|
||||
if (clockrt)
|
||||
restart->futex.flags |= FLAGS_CLOCKRT;
|
||||
return -ERESTART_RESTARTBLOCK;
|
||||
}
|
||||
restart = ¤t_thread_info()->restart_block;
|
||||
restart->fn = futex_wait_restart;
|
||||
restart->futex.uaddr = (u32 *)uaddr;
|
||||
restart->futex.val = val;
|
||||
restart->futex.time = abs_time->tv64;
|
||||
restart->futex.bitset = bitset;
|
||||
restart->futex.flags = 0;
|
||||
|
||||
out_unlock_put_key:
|
||||
queue_unlock(&q, hb);
|
||||
if (fshared)
|
||||
restart->futex.flags |= FLAGS_SHARED;
|
||||
if (clockrt)
|
||||
restart->futex.flags |= FLAGS_CLOCKRT;
|
||||
|
||||
ret = -ERESTART_RESTARTBLOCK;
|
||||
|
||||
out_put_key:
|
||||
put_futex_key(fshared, &q.key);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+43
-2
@@ -501,6 +501,13 @@ static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base)
|
||||
continue;
|
||||
timer = rb_entry(base->first, struct hrtimer, node);
|
||||
expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
|
||||
/*
|
||||
* clock_was_set() has changed base->offset so the
|
||||
* result might be negative. Fix it up to prevent a
|
||||
* false positive in clockevents_program_event()
|
||||
*/
|
||||
if (expires.tv64 < 0)
|
||||
expires.tv64 = 0;
|
||||
if (expires.tv64 < cpu_base->expires_next.tv64)
|
||||
cpu_base->expires_next = expires;
|
||||
}
|
||||
@@ -614,7 +621,9 @@ void clock_was_set(void)
|
||||
*/
|
||||
void hres_timers_resume(void)
|
||||
{
|
||||
/* Retrigger the CPU local events: */
|
||||
WARN_ONCE(!irqs_disabled(),
|
||||
KERN_INFO "hres_timers_resume() called with IRQs enabled!");
|
||||
|
||||
retrigger_next_event(NULL);
|
||||
}
|
||||
|
||||
@@ -1156,6 +1165,29 @@ static void __run_hrtimer(struct hrtimer *timer)
|
||||
|
||||
#ifdef CONFIG_HIGH_RES_TIMERS
|
||||
|
||||
static int force_clock_reprogram;
|
||||
|
||||
/*
|
||||
* After 5 iteration's attempts, we consider that hrtimer_interrupt()
|
||||
* is hanging, which could happen with something that slows the interrupt
|
||||
* such as the tracing. Then we force the clock reprogramming for each future
|
||||
* hrtimer interrupts to avoid infinite loops and use the min_delta_ns
|
||||
* threshold that we will overwrite.
|
||||
* The next tick event will be scheduled to 3 times we currently spend on
|
||||
* hrtimer_interrupt(). This gives a good compromise, the cpus will spend
|
||||
* 1/4 of their time to process the hrtimer interrupts. This is enough to
|
||||
* let it running without serious starvation.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
hrtimer_interrupt_hanging(struct clock_event_device *dev,
|
||||
ktime_t try_time)
|
||||
{
|
||||
force_clock_reprogram = 1;
|
||||
dev->min_delta_ns = (unsigned long)try_time.tv64 * 3;
|
||||
printk(KERN_WARNING "hrtimer: interrupt too slow, "
|
||||
"forcing clock min delta to %lu ns\n", dev->min_delta_ns);
|
||||
}
|
||||
/*
|
||||
* High resolution timer interrupt
|
||||
* Called with interrupts disabled
|
||||
@@ -1165,6 +1197,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
||||
struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
|
||||
struct hrtimer_clock_base *base;
|
||||
ktime_t expires_next, now;
|
||||
int nr_retries = 0;
|
||||
int i;
|
||||
|
||||
BUG_ON(!cpu_base->hres_active);
|
||||
@@ -1172,6 +1205,10 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
||||
dev->next_event.tv64 = KTIME_MAX;
|
||||
|
||||
retry:
|
||||
/* 5 retries is enough to notice a hang */
|
||||
if (!(++nr_retries % 5))
|
||||
hrtimer_interrupt_hanging(dev, ktime_sub(ktime_get(), now));
|
||||
|
||||
now = ktime_get();
|
||||
|
||||
expires_next.tv64 = KTIME_MAX;
|
||||
@@ -1224,7 +1261,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
||||
|
||||
/* Reprogramming necessary ? */
|
||||
if (expires_next.tv64 != KTIME_MAX) {
|
||||
if (tick_program_event(expires_next, 0))
|
||||
if (tick_program_event(expires_next, force_clock_reprogram))
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@@ -1578,6 +1615,10 @@ static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
case CPU_DYING:
|
||||
case CPU_DYING_FROZEN:
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DYING, &scpu);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
case CPU_DEAD_FROZEN:
|
||||
{
|
||||
|
||||
@@ -384,6 +384,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
|
||||
out_unlock:
|
||||
spin_unlock(&desc->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(handle_level_irq);
|
||||
|
||||
/**
|
||||
* handle_fasteoi_irq - irq handler for transparent controllers
|
||||
@@ -595,6 +596,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
}
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__set_irq_handler);
|
||||
|
||||
void
|
||||
set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
|
||||
|
||||
@@ -39,6 +39,18 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
|
||||
ack_bad_irq(irq);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
|
||||
static void __init init_irq_default_affinity(void)
|
||||
{
|
||||
alloc_bootmem_cpumask_var(&irq_default_affinity);
|
||||
cpumask_setall(irq_default_affinity);
|
||||
}
|
||||
#else
|
||||
static void __init init_irq_default_affinity(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Linux has a controller-independent interrupt architecture.
|
||||
* Every controller has a 'controller-template', that is used
|
||||
@@ -134,6 +146,8 @@ int __init early_irq_init(void)
|
||||
int legacy_count;
|
||||
int i;
|
||||
|
||||
init_irq_default_affinity();
|
||||
|
||||
desc = irq_desc_legacy;
|
||||
legacy_count = ARRAY_SIZE(irq_desc_legacy);
|
||||
|
||||
@@ -219,6 +233,8 @@ int __init early_irq_init(void)
|
||||
int count;
|
||||
int i;
|
||||
|
||||
init_irq_default_affinity();
|
||||
|
||||
desc = irq_desc;
|
||||
count = ARRAY_SIZE(irq_desc);
|
||||
|
||||
|
||||
+1
-9
@@ -15,17 +15,9 @@
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
|
||||
cpumask_var_t irq_default_affinity;
|
||||
|
||||
static int init_irq_default_affinity(void)
|
||||
{
|
||||
alloc_cpumask_var(&irq_default_affinity, GFP_KERNEL);
|
||||
cpumask_setall(irq_default_affinity);
|
||||
return 0;
|
||||
}
|
||||
core_initcall(init_irq_default_affinity);
|
||||
|
||||
/**
|
||||
* synchronize_irq - wait for pending IRQ handlers (on other CPUs)
|
||||
* @irq: interrupt number to wait for
|
||||
|
||||
@@ -71,7 +71,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
|
||||
desc = irq_desc_ptrs[irq];
|
||||
|
||||
if (desc && old_desc != desc)
|
||||
goto out_unlock;
|
||||
goto out_unlock;
|
||||
|
||||
node = cpu_to_node(cpu);
|
||||
desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
|
||||
@@ -84,10 +84,15 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
|
||||
init_copy_one_irq_desc(irq, old_desc, desc, cpu);
|
||||
|
||||
irq_desc_ptrs[irq] = desc;
|
||||
spin_unlock_irqrestore(&sparse_irq_lock, flags);
|
||||
|
||||
/* free the old one */
|
||||
free_one_irq_desc(old_desc, desc);
|
||||
spin_unlock(&old_desc->lock);
|
||||
kfree(old_desc);
|
||||
spin_lock(&desc->lock);
|
||||
|
||||
return desc;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&sparse_irq_lock, flags);
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ int do_getitimer(int which, struct itimerval *value)
|
||||
struct task_cputime cputime;
|
||||
cputime_t utime;
|
||||
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
thread_group_cputimer(tsk, &cputime);
|
||||
utime = cputime.utime;
|
||||
if (cputime_le(cval, utime)) { /* about to fire */
|
||||
cval = jiffies_to_cputime(1);
|
||||
@@ -82,7 +82,7 @@ int do_getitimer(int which, struct itimerval *value)
|
||||
struct task_cputime times;
|
||||
cputime_t ptime;
|
||||
|
||||
thread_group_cputime(tsk, ×);
|
||||
thread_group_cputimer(tsk, ×);
|
||||
ptime = cputime_add(times.utime, times.stime);
|
||||
if (cputime_le(cval, ptime)) { /* about to fire */
|
||||
cval = jiffies_to_cputime(1);
|
||||
|
||||
+10
-6
@@ -30,19 +30,20 @@
|
||||
#define all_var 0
|
||||
#endif
|
||||
|
||||
extern const unsigned long kallsyms_addresses[];
|
||||
extern const u8 kallsyms_names[];
|
||||
/* These will be re-linked against their real values during the second link stage */
|
||||
extern const unsigned long kallsyms_addresses[] __attribute__((weak));
|
||||
extern const u8 kallsyms_names[] __attribute__((weak));
|
||||
|
||||
/* tell the compiler that the count isn't in the small data section if the arch
|
||||
* has one (eg: FRV)
|
||||
*/
|
||||
extern const unsigned long kallsyms_num_syms
|
||||
__attribute__((__section__(".rodata")));
|
||||
__attribute__((weak, section(".rodata")));
|
||||
|
||||
extern const u8 kallsyms_token_table[];
|
||||
extern const u16 kallsyms_token_index[];
|
||||
extern const u8 kallsyms_token_table[] __attribute__((weak));
|
||||
extern const u16 kallsyms_token_index[] __attribute__((weak));
|
||||
|
||||
extern const unsigned long kallsyms_markers[];
|
||||
extern const unsigned long kallsyms_markers[] __attribute__((weak));
|
||||
|
||||
static inline int is_kernel_inittext(unsigned long addr)
|
||||
{
|
||||
@@ -167,6 +168,9 @@ static unsigned long get_symbol_pos(unsigned long addr,
|
||||
unsigned long symbol_start = 0, symbol_end = 0;
|
||||
unsigned long i, low, high, mid;
|
||||
|
||||
/* This kernel should never had been booted. */
|
||||
BUG_ON(!kallsyms_addresses);
|
||||
|
||||
/* do a binary search on the sorted kallsyms_addresses array */
|
||||
low = 0;
|
||||
high = kallsyms_num_syms;
|
||||
|
||||
@@ -1465,6 +1465,11 @@ int kernel_kexec(void)
|
||||
error = device_power_down(PMSG_FREEZE);
|
||||
if (error)
|
||||
goto Enable_irqs;
|
||||
|
||||
/* Suspend system devices */
|
||||
error = sysdev_suspend(PMSG_FREEZE);
|
||||
if (error)
|
||||
goto Power_up_devices;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -1477,6 +1482,8 @@ int kernel_kexec(void)
|
||||
|
||||
#ifdef CONFIG_KEXEC_JUMP
|
||||
if (kexec_image->preserve_context) {
|
||||
sysdev_resume();
|
||||
Power_up_devices:
|
||||
device_power_up(PMSG_RESTORE);
|
||||
Enable_irqs:
|
||||
local_irq_enable();
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ static int collect_garbage_slots(void);
|
||||
static int __kprobes check_safety(void)
|
||||
{
|
||||
int ret = 0;
|
||||
#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
|
||||
#if defined(CONFIG_PREEMPT) && defined(CONFIG_FREEZER)
|
||||
ret = freeze_processes();
|
||||
if (ret == 0) {
|
||||
struct task_struct *p, *q;
|
||||
|
||||
+25
-10
@@ -573,13 +573,13 @@ static char last_unloaded_module[MODULE_NAME_LEN+1];
|
||||
/* Init the unload section of the module. */
|
||||
static void module_unload_init(struct module *mod)
|
||||
{
|
||||
unsigned int i;
|
||||
int cpu;
|
||||
|
||||
INIT_LIST_HEAD(&mod->modules_which_use_me);
|
||||
for (i = 0; i < NR_CPUS; i++)
|
||||
local_set(&mod->ref[i].count, 0);
|
||||
for_each_possible_cpu(cpu)
|
||||
local_set(__module_ref_addr(mod, cpu), 0);
|
||||
/* Hold reference count during initialization. */
|
||||
local_set(&mod->ref[raw_smp_processor_id()].count, 1);
|
||||
local_set(__module_ref_addr(mod, raw_smp_processor_id()), 1);
|
||||
/* Backwards compatibility macros put refcount during init. */
|
||||
mod->waiter = current;
|
||||
}
|
||||
@@ -717,10 +717,11 @@ static int try_stop_module(struct module *mod, int flags, int *forced)
|
||||
|
||||
unsigned int module_refcount(struct module *mod)
|
||||
{
|
||||
unsigned int i, total = 0;
|
||||
unsigned int total = 0;
|
||||
int cpu;
|
||||
|
||||
for (i = 0; i < NR_CPUS; i++)
|
||||
total += local_read(&mod->ref[i].count);
|
||||
for_each_possible_cpu(cpu)
|
||||
total += local_read(__module_ref_addr(mod, cpu));
|
||||
return total;
|
||||
}
|
||||
EXPORT_SYMBOL(module_refcount);
|
||||
@@ -894,7 +895,7 @@ void module_put(struct module *module)
|
||||
{
|
||||
if (module) {
|
||||
unsigned int cpu = get_cpu();
|
||||
local_dec(&module->ref[cpu].count);
|
||||
local_dec(__module_ref_addr(module, cpu));
|
||||
/* Maybe they're waiting for us to drop reference? */
|
||||
if (unlikely(!module_is_live(module)))
|
||||
wake_up_process(module->waiter);
|
||||
@@ -1464,7 +1465,10 @@ static void free_module(struct module *mod)
|
||||
kfree(mod->args);
|
||||
if (mod->percpu)
|
||||
percpu_modfree(mod->percpu);
|
||||
|
||||
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
||||
if (mod->refptr)
|
||||
percpu_modfree(mod->refptr);
|
||||
#endif
|
||||
/* Free lock-classes: */
|
||||
lockdep_free_key_range(mod->module_core, mod->core_size);
|
||||
|
||||
@@ -2011,6 +2015,14 @@ static noinline struct module *load_module(void __user *umod,
|
||||
if (err < 0)
|
||||
goto free_mod;
|
||||
|
||||
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
||||
mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t),
|
||||
mod->name);
|
||||
if (!mod->refptr) {
|
||||
err = -ENOMEM;
|
||||
goto free_mod;
|
||||
}
|
||||
#endif
|
||||
if (pcpuindex) {
|
||||
/* We have a special allocation for this section. */
|
||||
percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
|
||||
@@ -2018,7 +2030,7 @@ static noinline struct module *load_module(void __user *umod,
|
||||
mod->name);
|
||||
if (!percpu) {
|
||||
err = -ENOMEM;
|
||||
goto free_mod;
|
||||
goto free_percpu;
|
||||
}
|
||||
sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||
mod->percpu = percpu;
|
||||
@@ -2282,6 +2294,9 @@ static noinline struct module *load_module(void __user *umod,
|
||||
free_percpu:
|
||||
if (percpu)
|
||||
percpu_modfree(percpu);
|
||||
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
|
||||
percpu_modfree(mod->refptr);
|
||||
#endif
|
||||
free_mod:
|
||||
kfree(args);
|
||||
free_hdr:
|
||||
|
||||
+115
-78
@@ -9,76 +9,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
||||
/*
|
||||
* Allocate the thread_group_cputime structure appropriately and fill in the
|
||||
* current values of the fields. Called from copy_signal() via
|
||||
* thread_group_cputime_clone_thread() when adding a second or subsequent
|
||||
* thread to a thread group. Assumes interrupts are enabled when called.
|
||||
*/
|
||||
int thread_group_cputime_alloc(struct task_struct *tsk)
|
||||
{
|
||||
struct signal_struct *sig = tsk->signal;
|
||||
struct task_cputime *cputime;
|
||||
|
||||
/*
|
||||
* If we have multiple threads and we don't already have a
|
||||
* per-CPU task_cputime struct (checked in the caller), allocate
|
||||
* one and fill it in with the times accumulated so far. We may
|
||||
* race with another thread so recheck after we pick up the sighand
|
||||
* lock.
|
||||
*/
|
||||
cputime = alloc_percpu(struct task_cputime);
|
||||
if (cputime == NULL)
|
||||
return -ENOMEM;
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
if (sig->cputime.totals) {
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
free_percpu(cputime);
|
||||
return 0;
|
||||
}
|
||||
sig->cputime.totals = cputime;
|
||||
cputime = per_cpu_ptr(sig->cputime.totals, smp_processor_id());
|
||||
cputime->utime = tsk->utime;
|
||||
cputime->stime = tsk->stime;
|
||||
cputime->sum_exec_runtime = tsk->se.sum_exec_runtime;
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* thread_group_cputime - Sum the thread group time fields across all CPUs.
|
||||
*
|
||||
* @tsk: The task we use to identify the thread group.
|
||||
* @times: task_cputime structure in which we return the summed fields.
|
||||
*
|
||||
* Walk the list of CPUs to sum the per-CPU time fields in the thread group
|
||||
* time structure.
|
||||
*/
|
||||
void thread_group_cputime(
|
||||
struct task_struct *tsk,
|
||||
struct task_cputime *times)
|
||||
{
|
||||
struct task_cputime *totals, *tot;
|
||||
int i;
|
||||
|
||||
totals = tsk->signal->cputime.totals;
|
||||
if (!totals) {
|
||||
times->utime = tsk->utime;
|
||||
times->stime = tsk->stime;
|
||||
times->sum_exec_runtime = tsk->se.sum_exec_runtime;
|
||||
return;
|
||||
}
|
||||
|
||||
times->stime = times->utime = cputime_zero;
|
||||
times->sum_exec_runtime = 0;
|
||||
for_each_possible_cpu(i) {
|
||||
tot = per_cpu_ptr(totals, i);
|
||||
times->utime = cputime_add(times->utime, tot->utime);
|
||||
times->stime = cputime_add(times->stime, tot->stime);
|
||||
times->sum_exec_runtime += tot->sum_exec_runtime;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after updating RLIMIT_CPU to set timer expiration if necessary.
|
||||
*/
|
||||
@@ -300,6 +230,71 @@ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
|
||||
{
|
||||
struct sighand_struct *sighand;
|
||||
struct signal_struct *sig;
|
||||
struct task_struct *t;
|
||||
|
||||
*times = INIT_CPUTIME;
|
||||
|
||||
rcu_read_lock();
|
||||
sighand = rcu_dereference(tsk->sighand);
|
||||
if (!sighand)
|
||||
goto out;
|
||||
|
||||
sig = tsk->signal;
|
||||
|
||||
t = tsk;
|
||||
do {
|
||||
times->utime = cputime_add(times->utime, t->utime);
|
||||
times->stime = cputime_add(times->stime, t->stime);
|
||||
times->sum_exec_runtime += t->se.sum_exec_runtime;
|
||||
|
||||
t = next_thread(t);
|
||||
} while (t != tsk);
|
||||
|
||||
times->utime = cputime_add(times->utime, sig->utime);
|
||||
times->stime = cputime_add(times->stime, sig->stime);
|
||||
times->sum_exec_runtime += sig->sum_sched_runtime;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void update_gt_cputime(struct task_cputime *a, struct task_cputime *b)
|
||||
{
|
||||
if (cputime_gt(b->utime, a->utime))
|
||||
a->utime = b->utime;
|
||||
|
||||
if (cputime_gt(b->stime, a->stime))
|
||||
a->stime = b->stime;
|
||||
|
||||
if (b->sum_exec_runtime > a->sum_exec_runtime)
|
||||
a->sum_exec_runtime = b->sum_exec_runtime;
|
||||
}
|
||||
|
||||
void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
|
||||
{
|
||||
struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
|
||||
struct task_cputime sum;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cputimer->lock, flags);
|
||||
if (!cputimer->running) {
|
||||
cputimer->running = 1;
|
||||
/*
|
||||
* The POSIX timer interface allows for absolute time expiry
|
||||
* values through the TIMER_ABSTIME flag, therefore we have
|
||||
* to synchronize the timer to the clock every time we start
|
||||
* it.
|
||||
*/
|
||||
thread_group_cputime(tsk, &sum);
|
||||
update_gt_cputime(&cputimer->cputime, &sum);
|
||||
}
|
||||
*times = cputimer->cputime;
|
||||
spin_unlock_irqrestore(&cputimer->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample a process (thread group) clock for the given group_leader task.
|
||||
* Must be called with tasklist_lock held for reading.
|
||||
@@ -527,7 +522,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)
|
||||
{
|
||||
struct task_cputime cputime;
|
||||
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
thread_group_cputimer(tsk, &cputime);
|
||||
cleanup_timers(tsk->signal->cpu_timers,
|
||||
cputime.utime, cputime.stime, cputime.sum_exec_runtime);
|
||||
}
|
||||
@@ -685,6 +680,33 @@ static void cpu_timer_fire(struct k_itimer *timer)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample a process (thread group) timer for the given group_leader task.
|
||||
* Must be called with tasklist_lock held for reading.
|
||||
*/
|
||||
static int cpu_timer_sample_group(const clockid_t which_clock,
|
||||
struct task_struct *p,
|
||||
union cpu_time_count *cpu)
|
||||
{
|
||||
struct task_cputime cputime;
|
||||
|
||||
thread_group_cputimer(p, &cputime);
|
||||
switch (CPUCLOCK_WHICH(which_clock)) {
|
||||
default:
|
||||
return -EINVAL;
|
||||
case CPUCLOCK_PROF:
|
||||
cpu->cpu = cputime_add(cputime.utime, cputime.stime);
|
||||
break;
|
||||
case CPUCLOCK_VIRT:
|
||||
cpu->cpu = cputime.utime;
|
||||
break;
|
||||
case CPUCLOCK_SCHED:
|
||||
cpu->sched = cputime.sum_exec_runtime + task_delta_exec(p);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guts of sys_timer_settime for CPU timers.
|
||||
* This is called with the timer locked and interrupts disabled.
|
||||
@@ -746,7 +768,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
|
||||
if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
|
||||
cpu_clock_sample(timer->it_clock, p, &val);
|
||||
} else {
|
||||
cpu_clock_sample_group(timer->it_clock, p, &val);
|
||||
cpu_timer_sample_group(timer->it_clock, p, &val);
|
||||
}
|
||||
|
||||
if (old) {
|
||||
@@ -894,7 +916,7 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
|
||||
read_unlock(&tasklist_lock);
|
||||
goto dead;
|
||||
} else {
|
||||
cpu_clock_sample_group(timer->it_clock, p, &now);
|
||||
cpu_timer_sample_group(timer->it_clock, p, &now);
|
||||
clear_dead = (unlikely(p->exit_state) &&
|
||||
thread_group_empty(p));
|
||||
}
|
||||
@@ -1034,6 +1056,19 @@ static void check_thread_timers(struct task_struct *tsk,
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_process_timers(struct task_struct *tsk)
|
||||
{
|
||||
struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
|
||||
unsigned long flags;
|
||||
|
||||
if (!cputimer->running)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&cputimer->lock, flags);
|
||||
cputimer->running = 0;
|
||||
spin_unlock_irqrestore(&cputimer->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for any per-thread CPU timers that have fired and move them
|
||||
* off the tsk->*_timers list onto the firing list. Per-thread timers
|
||||
@@ -1057,13 +1092,15 @@ static void check_process_timers(struct task_struct *tsk,
|
||||
sig->rlim[RLIMIT_CPU].rlim_cur == RLIM_INFINITY &&
|
||||
list_empty(&timers[CPUCLOCK_VIRT]) &&
|
||||
cputime_eq(sig->it_virt_expires, cputime_zero) &&
|
||||
list_empty(&timers[CPUCLOCK_SCHED]))
|
||||
list_empty(&timers[CPUCLOCK_SCHED])) {
|
||||
stop_process_timers(tsk);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect the current process totals.
|
||||
*/
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
thread_group_cputimer(tsk, &cputime);
|
||||
utime = cputime.utime;
|
||||
ptime = cputime_add(utime, cputime.stime);
|
||||
sum_sched_runtime = cputime.sum_exec_runtime;
|
||||
@@ -1234,7 +1271,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||
clear_dead_task(timer, now);
|
||||
goto out_unlock;
|
||||
}
|
||||
cpu_clock_sample_group(timer->it_clock, p, &now);
|
||||
cpu_timer_sample_group(timer->it_clock, p, &now);
|
||||
bump_cpu_timer(timer, now);
|
||||
/* Leave the tasklist_lock locked for the call below. */
|
||||
}
|
||||
@@ -1329,7 +1366,7 @@ static inline int fastpath_timer_check(struct task_struct *tsk)
|
||||
if (!task_cputime_zero(&sig->cputime_expires)) {
|
||||
struct task_cputime group_sample;
|
||||
|
||||
thread_group_cputime(tsk, &group_sample);
|
||||
thread_group_cputimer(tsk, &group_sample);
|
||||
if (task_cputime_expired(&group_sample, &sig->cputime_expires))
|
||||
return 1;
|
||||
}
|
||||
@@ -1411,7 +1448,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
||||
struct list_head *head;
|
||||
|
||||
BUG_ON(clock_idx == CPUCLOCK_SCHED);
|
||||
cpu_clock_sample_group(clock_idx, tsk, &now);
|
||||
cpu_timer_sample_group(clock_idx, tsk, &now);
|
||||
|
||||
if (oldval) {
|
||||
if (!cputime_eq(*oldval, cputime_zero)) {
|
||||
|
||||
@@ -3,8 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
||||
obj-y := main.o
|
||||
obj-$(CONFIG_PM_SLEEP) += process.o console.o
|
||||
obj-$(CONFIG_PM) += main.o
|
||||
obj-$(CONFIG_PM_SLEEP) += console.o
|
||||
obj-$(CONFIG_FREEZER) += process.o
|
||||
obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
|
||||
|
||||
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
|
||||
|
||||
@@ -78,6 +78,12 @@ void pm_restore_console(void)
|
||||
}
|
||||
set_console(orig_fgconsole);
|
||||
release_console_sem();
|
||||
|
||||
if (vt_waitactive(orig_fgconsole)) {
|
||||
pr_debug("Resume: Can't switch VCs.");
|
||||
return;
|
||||
}
|
||||
|
||||
kmsg_redirect = orig_kmsg;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -71,6 +71,14 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
|
||||
mutex_unlock(&pm_mutex);
|
||||
}
|
||||
|
||||
static bool entering_platform_hibernation;
|
||||
|
||||
bool system_entering_hibernation(void)
|
||||
{
|
||||
return entering_platform_hibernation;
|
||||
}
|
||||
EXPORT_SYMBOL(system_entering_hibernation);
|
||||
|
||||
#ifdef CONFIG_PM_DEBUG
|
||||
static void hibernation_debug_sleep(void)
|
||||
{
|
||||
@@ -219,6 +227,12 @@ static int create_image(int platform_mode)
|
||||
"aborting hibernation\n");
|
||||
goto Enable_irqs;
|
||||
}
|
||||
sysdev_suspend(PMSG_FREEZE);
|
||||
if (error) {
|
||||
printk(KERN_ERR "PM: Some devices failed to power down, "
|
||||
"aborting hibernation\n");
|
||||
goto Power_up_devices;
|
||||
}
|
||||
|
||||
if (hibernation_test(TEST_CORE))
|
||||
goto Power_up;
|
||||
@@ -234,9 +248,11 @@ static int create_image(int platform_mode)
|
||||
if (!in_suspend)
|
||||
platform_leave(platform_mode);
|
||||
Power_up:
|
||||
sysdev_resume();
|
||||
/* NOTE: device_power_up() is just a resume() for devices
|
||||
* that suspended with irqs off ... no overall powerup.
|
||||
*/
|
||||
Power_up_devices:
|
||||
device_power_up(in_suspend ?
|
||||
(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
|
||||
Enable_irqs:
|
||||
@@ -327,6 +343,7 @@ static int resume_target_kernel(void)
|
||||
"aborting resume\n");
|
||||
goto Enable_irqs;
|
||||
}
|
||||
sysdev_suspend(PMSG_QUIESCE);
|
||||
/* We'll ignore saved state, but this gets preempt count (etc) right */
|
||||
save_processor_state();
|
||||
error = restore_highmem();
|
||||
@@ -349,6 +366,7 @@ static int resume_target_kernel(void)
|
||||
swsusp_free();
|
||||
restore_processor_state();
|
||||
touch_softlockup_watchdog();
|
||||
sysdev_resume();
|
||||
device_power_up(PMSG_RECOVER);
|
||||
Enable_irqs:
|
||||
local_irq_enable();
|
||||
@@ -411,6 +429,7 @@ int hibernation_platform_enter(void)
|
||||
if (error)
|
||||
goto Close;
|
||||
|
||||
entering_platform_hibernation = true;
|
||||
suspend_console();
|
||||
error = device_suspend(PMSG_HIBERNATE);
|
||||
if (error) {
|
||||
@@ -431,6 +450,7 @@ int hibernation_platform_enter(void)
|
||||
local_irq_disable();
|
||||
error = device_power_down(PMSG_HIBERNATE);
|
||||
if (!error) {
|
||||
sysdev_suspend(PMSG_HIBERNATE);
|
||||
hibernation_ops->enter();
|
||||
/* We should never get here */
|
||||
while (1);
|
||||
@@ -445,6 +465,7 @@ int hibernation_platform_enter(void)
|
||||
Finish:
|
||||
hibernation_ops->finish();
|
||||
Resume_devices:
|
||||
entering_platform_hibernation = false;
|
||||
device_resume(PMSG_RESTORE);
|
||||
resume_console();
|
||||
Close:
|
||||
@@ -584,6 +605,12 @@ static int software_resume(void)
|
||||
int error;
|
||||
unsigned int flags;
|
||||
|
||||
/*
|
||||
* If the user said "noresume".. bail out early.
|
||||
*/
|
||||
if (noresume)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* name_to_dev_t() below takes a sysfs buffer mutex when sysfs
|
||||
* is configured into the kernel. Since the regular hibernate
|
||||
@@ -600,6 +627,11 @@ static int software_resume(void)
|
||||
mutex_unlock(&pm_mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
/*
|
||||
* Some device discovery might still be in progress; we need
|
||||
* to wait for this to finish.
|
||||
*/
|
||||
wait_for_device_probe();
|
||||
swsusp_resume_device = name_to_dev_t(resume_file);
|
||||
pr_debug("PM: Resume from partition %s\n", resume_file);
|
||||
} else {
|
||||
|
||||
+19
-15
@@ -57,16 +57,6 @@ int pm_notifier_call_chain(unsigned long val)
|
||||
#ifdef CONFIG_PM_DEBUG
|
||||
int pm_test_level = TEST_NONE;
|
||||
|
||||
static int suspend_test(int level)
|
||||
{
|
||||
if (pm_test_level == level) {
|
||||
printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
|
||||
mdelay(5000);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const pm_tests[__TEST_AFTER_LAST] = {
|
||||
[TEST_NONE] = "none",
|
||||
[TEST_CORE] = "core",
|
||||
@@ -125,14 +115,24 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
}
|
||||
|
||||
power_attr(pm_test);
|
||||
#else /* !CONFIG_PM_DEBUG */
|
||||
static inline int suspend_test(int level) { return 0; }
|
||||
#endif /* !CONFIG_PM_DEBUG */
|
||||
#endif /* CONFIG_PM_DEBUG */
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
|
||||
static int suspend_test(int level)
|
||||
{
|
||||
#ifdef CONFIG_PM_DEBUG
|
||||
if (pm_test_level == level) {
|
||||
printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
|
||||
mdelay(5000);
|
||||
return 1;
|
||||
}
|
||||
#endif /* !CONFIG_PM_DEBUG */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_TEST_SUSPEND
|
||||
|
||||
/*
|
||||
@@ -298,8 +298,12 @@ static int suspend_enter(suspend_state_t state)
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (!suspend_test(TEST_CORE))
|
||||
error = suspend_ops->enter(state);
|
||||
error = sysdev_suspend(PMSG_SUSPEND);
|
||||
if (!error) {
|
||||
if (!suspend_test(TEST_CORE))
|
||||
error = suspend_ops->enter(state);
|
||||
sysdev_resume();
|
||||
}
|
||||
|
||||
device_power_up(PMSG_RESUME);
|
||||
Done:
|
||||
|
||||
+3
-2
@@ -60,6 +60,7 @@ static struct block_device *resume_bdev;
|
||||
static int submit(int rw, pgoff_t page_off, struct page *page,
|
||||
struct bio **bio_chain)
|
||||
{
|
||||
const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
|
||||
struct bio *bio;
|
||||
|
||||
bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
|
||||
@@ -80,7 +81,7 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
|
||||
bio_get(bio);
|
||||
|
||||
if (bio_chain == NULL) {
|
||||
submit_bio(rw | (1 << BIO_RW_SYNC), bio);
|
||||
submit_bio(bio_rw, bio);
|
||||
wait_on_page_locked(page);
|
||||
if (rw == READ)
|
||||
bio_set_pages_dirty(bio);
|
||||
@@ -90,7 +91,7 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
|
||||
get_page(page); /* These pages are freed later */
|
||||
bio->bi_private = *bio_chain;
|
||||
*bio_chain = bio;
|
||||
submit_bio(rw | (1 << BIO_RW_SYNC), bio);
|
||||
submit_bio(bio_rw, bio);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-6
@@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp)
|
||||
data->swap = swsusp_resume_device ?
|
||||
swap_type_of(swsusp_resume_device, 0, NULL) : -1;
|
||||
data->mode = O_RDONLY;
|
||||
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
|
||||
if (error)
|
||||
pm_notifier_call_chain(PM_POST_RESTORE);
|
||||
} else {
|
||||
data->swap = -1;
|
||||
data->mode = O_WRONLY;
|
||||
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
|
||||
if (error)
|
||||
pm_notifier_call_chain(PM_POST_HIBERNATION);
|
||||
} else {
|
||||
data->swap = -1;
|
||||
data->mode = O_WRONLY;
|
||||
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
|
||||
if (error)
|
||||
pm_notifier_call_chain(PM_POST_RESTORE);
|
||||
}
|
||||
if (error)
|
||||
atomic_inc(&snapshot_device_available);
|
||||
|
||||
+9
-6
@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress);
|
||||
* driver system.
|
||||
*/
|
||||
static DECLARE_MUTEX(console_sem);
|
||||
static DECLARE_MUTEX(secondary_console_sem);
|
||||
struct console *console_drivers;
|
||||
EXPORT_SYMBOL_GPL(console_drivers);
|
||||
|
||||
@@ -891,12 +890,14 @@ void suspend_console(void)
|
||||
printk("Suspending console(s) (use no_console_suspend to debug)\n");
|
||||
acquire_console_sem();
|
||||
console_suspended = 1;
|
||||
up(&console_sem);
|
||||
}
|
||||
|
||||
void resume_console(void)
|
||||
{
|
||||
if (!console_suspend_enabled)
|
||||
return;
|
||||
down(&console_sem);
|
||||
console_suspended = 0;
|
||||
release_console_sem();
|
||||
}
|
||||
@@ -912,11 +913,9 @@ void resume_console(void)
|
||||
void acquire_console_sem(void)
|
||||
{
|
||||
BUG_ON(in_interrupt());
|
||||
if (console_suspended) {
|
||||
down(&secondary_console_sem);
|
||||
return;
|
||||
}
|
||||
down(&console_sem);
|
||||
if (console_suspended)
|
||||
return;
|
||||
console_locked = 1;
|
||||
console_may_schedule = 1;
|
||||
}
|
||||
@@ -926,6 +925,10 @@ int try_acquire_console_sem(void)
|
||||
{
|
||||
if (down_trylock(&console_sem))
|
||||
return -1;
|
||||
if (console_suspended) {
|
||||
up(&console_sem);
|
||||
return -1;
|
||||
}
|
||||
console_locked = 1;
|
||||
console_may_schedule = 0;
|
||||
return 0;
|
||||
@@ -979,7 +982,7 @@ void release_console_sem(void)
|
||||
unsigned wake_klogd = 0;
|
||||
|
||||
if (console_suspended) {
|
||||
up(&secondary_console_sem);
|
||||
up(&console_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,12 +114,15 @@ int __ref profile_init(void)
|
||||
if (!slab_is_available()) {
|
||||
prof_buffer = alloc_bootmem(buffer_bytes);
|
||||
alloc_bootmem_cpumask_var(&prof_cpu_mask);
|
||||
cpumask_copy(prof_cpu_mask, cpu_possible_mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!alloc_cpumask_var(&prof_cpu_mask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
cpumask_copy(prof_cpu_mask, cpu_possible_mask);
|
||||
|
||||
prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL);
|
||||
if (prof_buffer)
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -716,7 +716,7 @@ void rcu_check_callbacks(int cpu, int user)
|
||||
raise_rcu_softirq();
|
||||
}
|
||||
|
||||
static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
|
||||
static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
|
||||
struct rcu_data *rdp)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
+1
-1
@@ -1314,7 +1314,7 @@ int rcu_needs_cpu(int cpu)
|
||||
* access due to the fact that this CPU cannot possibly have any RCU
|
||||
* callbacks in flight yet.
|
||||
*/
|
||||
static void
|
||||
static void __cpuinit
|
||||
rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
+3
-1
@@ -663,8 +663,10 @@ int relay_late_setup_files(struct rchan *chan,
|
||||
|
||||
mutex_lock(&relay_channels_mutex);
|
||||
/* Is chan already set up? */
|
||||
if (unlikely(chan->has_base_filename))
|
||||
if (unlikely(chan->has_base_filename)) {
|
||||
mutex_unlock(&relay_channels_mutex);
|
||||
return -EEXIST;
|
||||
}
|
||||
chan->has_base_filename = 1;
|
||||
chan->parent = parent;
|
||||
curr_cpu = get_cpu();
|
||||
|
||||
+25
-11
@@ -3880,19 +3880,24 @@ int select_nohz_load_balancer(int stop_tick)
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (stop_tick) {
|
||||
cpumask_set_cpu(cpu, nohz.cpu_mask);
|
||||
cpu_rq(cpu)->in_nohz_recently = 1;
|
||||
|
||||
/*
|
||||
* If we are going offline and still the leader, give up!
|
||||
*/
|
||||
if (!cpu_active(cpu) &&
|
||||
atomic_read(&nohz.load_balancer) == cpu) {
|
||||
if (!cpu_active(cpu)) {
|
||||
if (atomic_read(&nohz.load_balancer) != cpu)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are going offline and still the leader,
|
||||
* give up!
|
||||
*/
|
||||
if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpumask_set_cpu(cpu, nohz.cpu_mask);
|
||||
|
||||
/* time for ilb owner also to sleep */
|
||||
if (cpumask_weight(nohz.cpu_mask) == num_online_cpus()) {
|
||||
if (atomic_read(&nohz.load_balancer) == cpu)
|
||||
@@ -4687,8 +4692,8 @@ EXPORT_SYMBOL(default_wake_function);
|
||||
* started to run but is not in state TASK_RUNNING. try_to_wake_up() returns
|
||||
* zero in this (rare) case, and we handle it by continuing to scan the queue.
|
||||
*/
|
||||
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
|
||||
int nr_exclusive, int sync, void *key)
|
||||
void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
|
||||
int nr_exclusive, int sync, void *key)
|
||||
{
|
||||
wait_queue_t *curr, *next;
|
||||
|
||||
@@ -6939,20 +6944,26 @@ static void free_rootdomain(struct root_domain *rd)
|
||||
|
||||
static void rq_attach_root(struct rq *rq, struct root_domain *rd)
|
||||
{
|
||||
struct root_domain *old_rd = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rq->lock, flags);
|
||||
|
||||
if (rq->rd) {
|
||||
struct root_domain *old_rd = rq->rd;
|
||||
old_rd = rq->rd;
|
||||
|
||||
if (cpumask_test_cpu(rq->cpu, old_rd->online))
|
||||
set_rq_offline(rq);
|
||||
|
||||
cpumask_clear_cpu(rq->cpu, old_rd->span);
|
||||
|
||||
if (atomic_dec_and_test(&old_rd->refcount))
|
||||
free_rootdomain(old_rd);
|
||||
/*
|
||||
* If we dont want to free the old_rt yet then
|
||||
* set old_rd to NULL to skip the freeing later
|
||||
* in this function:
|
||||
*/
|
||||
if (!atomic_dec_and_test(&old_rd->refcount))
|
||||
old_rd = NULL;
|
||||
}
|
||||
|
||||
atomic_inc(&rd->refcount);
|
||||
@@ -6963,6 +6974,9 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
|
||||
set_rq_online(rq);
|
||||
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
|
||||
if (old_rd)
|
||||
free_rootdomain(old_rd);
|
||||
}
|
||||
|
||||
static int __init_refok init_rootdomain(struct root_domain *rd, bool bootmem)
|
||||
|
||||
+19
-2
@@ -719,7 +719,7 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup)
|
||||
__enqueue_entity(cfs_rq, se);
|
||||
}
|
||||
|
||||
static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||
static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||
{
|
||||
if (cfs_rq->last == se)
|
||||
cfs_rq->last = NULL;
|
||||
@@ -728,6 +728,12 @@ static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||
cfs_rq->next = NULL;
|
||||
}
|
||||
|
||||
static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||
{
|
||||
for_each_sched_entity(se)
|
||||
__clear_buddies(cfs_rq_of(se), se);
|
||||
}
|
||||
|
||||
static void
|
||||
dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
|
||||
{
|
||||
@@ -768,8 +774,14 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
|
||||
|
||||
ideal_runtime = sched_slice(cfs_rq, curr);
|
||||
delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
|
||||
if (delta_exec > ideal_runtime)
|
||||
if (delta_exec > ideal_runtime) {
|
||||
resched_task(rq_of(cfs_rq)->curr);
|
||||
/*
|
||||
* The current task ran long enough, ensure it doesn't get
|
||||
* re-elected due to buddy favours.
|
||||
*/
|
||||
clear_buddies(cfs_rq, curr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1452,6 +1464,11 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
|
||||
|
||||
do {
|
||||
se = pick_next_entity(cfs_rq);
|
||||
/*
|
||||
* If se was a buddy, clear it so that it will have to earn
|
||||
* the favour again.
|
||||
*/
|
||||
__clear_buddies(cfs_rq, se);
|
||||
set_next_entity(cfs_rq, se);
|
||||
cfs_rq = group_cfs_rq(se);
|
||||
} while (cfs_rq);
|
||||
|
||||
+2
-2
@@ -968,8 +968,8 @@ static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask)
|
||||
if ((this_cpu != -1) && cpu_isset(this_cpu, *mask))
|
||||
return this_cpu;
|
||||
|
||||
first = first_cpu(*mask);
|
||||
if (first != NR_CPUS)
|
||||
first = cpumask_first(mask);
|
||||
if (first < nr_cpu_ids)
|
||||
return first;
|
||||
|
||||
return -1;
|
||||
|
||||
+26
-22
@@ -296,20 +296,21 @@ sched_info_switch(struct task_struct *prev, struct task_struct *next)
|
||||
static inline void account_group_user_time(struct task_struct *tsk,
|
||||
cputime_t cputime)
|
||||
{
|
||||
struct signal_struct *sig;
|
||||
struct thread_group_cputimer *cputimer;
|
||||
|
||||
/* tsk == current, ensure it is safe to use ->signal */
|
||||
if (unlikely(tsk->exit_state))
|
||||
return;
|
||||
|
||||
sig = tsk->signal;
|
||||
if (sig->cputime.totals) {
|
||||
struct task_cputime *times;
|
||||
cputimer = &tsk->signal->cputimer;
|
||||
|
||||
times = per_cpu_ptr(sig->cputime.totals, get_cpu());
|
||||
times->utime = cputime_add(times->utime, cputime);
|
||||
put_cpu_no_resched();
|
||||
}
|
||||
if (!cputimer->running)
|
||||
return;
|
||||
|
||||
spin_lock(&cputimer->lock);
|
||||
cputimer->cputime.utime =
|
||||
cputime_add(cputimer->cputime.utime, cputime);
|
||||
spin_unlock(&cputimer->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,20 +326,21 @@ static inline void account_group_user_time(struct task_struct *tsk,
|
||||
static inline void account_group_system_time(struct task_struct *tsk,
|
||||
cputime_t cputime)
|
||||
{
|
||||
struct signal_struct *sig;
|
||||
struct thread_group_cputimer *cputimer;
|
||||
|
||||
/* tsk == current, ensure it is safe to use ->signal */
|
||||
if (unlikely(tsk->exit_state))
|
||||
return;
|
||||
|
||||
sig = tsk->signal;
|
||||
if (sig->cputime.totals) {
|
||||
struct task_cputime *times;
|
||||
cputimer = &tsk->signal->cputimer;
|
||||
|
||||
times = per_cpu_ptr(sig->cputime.totals, get_cpu());
|
||||
times->stime = cputime_add(times->stime, cputime);
|
||||
put_cpu_no_resched();
|
||||
}
|
||||
if (!cputimer->running)
|
||||
return;
|
||||
|
||||
spin_lock(&cputimer->lock);
|
||||
cputimer->cputime.stime =
|
||||
cputime_add(cputimer->cputime.stime, cputime);
|
||||
spin_unlock(&cputimer->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,6 +356,7 @@ static inline void account_group_system_time(struct task_struct *tsk,
|
||||
static inline void account_group_exec_runtime(struct task_struct *tsk,
|
||||
unsigned long long ns)
|
||||
{
|
||||
struct thread_group_cputimer *cputimer;
|
||||
struct signal_struct *sig;
|
||||
|
||||
sig = tsk->signal;
|
||||
@@ -362,11 +365,12 @@ static inline void account_group_exec_runtime(struct task_struct *tsk,
|
||||
if (unlikely(!sig))
|
||||
return;
|
||||
|
||||
if (sig->cputime.totals) {
|
||||
struct task_cputime *times;
|
||||
cputimer = &sig->cputimer;
|
||||
|
||||
times = per_cpu_ptr(sig->cputime.totals, get_cpu());
|
||||
times->sum_exec_runtime += ns;
|
||||
put_cpu_no_resched();
|
||||
}
|
||||
if (!cputimer->running)
|
||||
return;
|
||||
|
||||
spin_lock(&cputimer->lock);
|
||||
cputimer->cputime.sum_exec_runtime += ns;
|
||||
spin_unlock(&cputimer->lock);
|
||||
}
|
||||
|
||||
+6
-4
@@ -909,7 +909,9 @@ static void print_fatal_signal(struct pt_regs *regs, int signr)
|
||||
}
|
||||
#endif
|
||||
printk("\n");
|
||||
preempt_disable();
|
||||
show_regs(regs);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static int __init setup_print_fatal_signals(char *str)
|
||||
@@ -1365,7 +1367,6 @@ int do_notify_parent(struct task_struct *tsk, int sig)
|
||||
struct siginfo info;
|
||||
unsigned long flags;
|
||||
struct sighand_struct *psig;
|
||||
struct task_cputime cputime;
|
||||
int ret = sig;
|
||||
|
||||
BUG_ON(sig == -1);
|
||||
@@ -1395,9 +1396,10 @@ int do_notify_parent(struct task_struct *tsk, int sig)
|
||||
info.si_uid = __task_cred(tsk)->uid;
|
||||
rcu_read_unlock();
|
||||
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
info.si_utime = cputime_to_jiffies(cputime.utime);
|
||||
info.si_stime = cputime_to_jiffies(cputime.stime);
|
||||
info.si_utime = cputime_to_clock_t(cputime_add(tsk->utime,
|
||||
tsk->signal->utime));
|
||||
info.si_stime = cputime_to_clock_t(cputime_add(tsk->stime,
|
||||
tsk->signal->stime));
|
||||
|
||||
info.si_status = tsk->exit_code & 0x7f;
|
||||
if (tsk->exit_code & 0x80)
|
||||
|
||||
+33
-3
@@ -18,6 +18,7 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_function_lock);
|
||||
enum {
|
||||
CSD_FLAG_WAIT = 0x01,
|
||||
CSD_FLAG_ALLOC = 0x02,
|
||||
CSD_FLAG_LOCK = 0x04,
|
||||
};
|
||||
|
||||
struct call_function_data {
|
||||
@@ -186,6 +187,9 @@ void generic_smp_call_function_single_interrupt(void)
|
||||
if (data_flags & CSD_FLAG_WAIT) {
|
||||
smp_wmb();
|
||||
data->flags &= ~CSD_FLAG_WAIT;
|
||||
} else if (data_flags & CSD_FLAG_LOCK) {
|
||||
smp_wmb();
|
||||
data->flags &= ~CSD_FLAG_LOCK;
|
||||
} else if (data_flags & CSD_FLAG_ALLOC)
|
||||
kfree(data);
|
||||
}
|
||||
@@ -196,6 +200,8 @@ void generic_smp_call_function_single_interrupt(void)
|
||||
}
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct call_single_data, csd_data);
|
||||
|
||||
/*
|
||||
* smp_call_function_single - Run a function on a specific CPU
|
||||
* @func: The function to run. This must be fast and non-blocking.
|
||||
@@ -224,14 +230,38 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
|
||||
func(info);
|
||||
local_irq_restore(flags);
|
||||
} else if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
|
||||
struct call_single_data *data = NULL;
|
||||
struct call_single_data *data;
|
||||
|
||||
if (!wait) {
|
||||
/*
|
||||
* We are calling a function on a single CPU
|
||||
* and we are not going to wait for it to finish.
|
||||
* We first try to allocate the data, but if we
|
||||
* fail, we fall back to use a per cpu data to pass
|
||||
* the information to that CPU. Since all callers
|
||||
* of this code will use the same data, we must
|
||||
* synchronize the callers to prevent a new caller
|
||||
* from corrupting the data before the callee
|
||||
* can access it.
|
||||
*
|
||||
* The CSD_FLAG_LOCK is used to let us know when
|
||||
* the IPI handler is done with the data.
|
||||
* The first caller will set it, and the callee
|
||||
* will clear it. The next caller must wait for
|
||||
* it to clear before we set it again. This
|
||||
* will make sure the callee is done with the
|
||||
* data before a new caller will use it.
|
||||
*/
|
||||
data = kmalloc(sizeof(*data), GFP_ATOMIC);
|
||||
if (data)
|
||||
data->flags = CSD_FLAG_ALLOC;
|
||||
}
|
||||
if (!data) {
|
||||
else {
|
||||
data = &per_cpu(csd_data, me);
|
||||
while (data->flags & CSD_FLAG_LOCK)
|
||||
cpu_relax();
|
||||
data->flags = CSD_FLAG_LOCK;
|
||||
}
|
||||
} else {
|
||||
data = &d;
|
||||
data->flags = CSD_FLAG_WAIT;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
@@ -88,6 +89,14 @@ void touch_all_softlockup_watchdogs(void)
|
||||
}
|
||||
EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
|
||||
|
||||
int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
|
||||
struct file *filp, void __user *buffer,
|
||||
size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
touch_all_softlockup_watchdogs();
|
||||
return proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback runs from the timer interrupt, and checks
|
||||
* whether the watchdog thread has hung or not:
|
||||
|
||||
+4
-12
@@ -1525,22 +1525,14 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
|
||||
return -EFAULT;
|
||||
if (new_rlim.rlim_cur > new_rlim.rlim_max)
|
||||
return -EINVAL;
|
||||
old_rlim = current->signal->rlim + resource;
|
||||
if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
|
||||
!capable(CAP_SYS_RESOURCE))
|
||||
return -EPERM;
|
||||
|
||||
if (resource == RLIMIT_NOFILE) {
|
||||
if (new_rlim.rlim_max == RLIM_INFINITY)
|
||||
new_rlim.rlim_max = sysctl_nr_open;
|
||||
if (new_rlim.rlim_cur == RLIM_INFINITY)
|
||||
new_rlim.rlim_cur = sysctl_nr_open;
|
||||
if (new_rlim.rlim_max > sysctl_nr_open)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (new_rlim.rlim_cur > new_rlim.rlim_max)
|
||||
return -EINVAL;
|
||||
if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
|
||||
return -EPERM;
|
||||
|
||||
retval = security_task_setrlimit(resource, &new_rlim);
|
||||
if (retval)
|
||||
|
||||
+4
-3
@@ -101,6 +101,7 @@ static int two = 2;
|
||||
|
||||
static int zero;
|
||||
static int one = 1;
|
||||
static unsigned long one_ul = 1;
|
||||
static int one_hundred = 100;
|
||||
|
||||
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
|
||||
@@ -809,7 +810,7 @@ static struct ctl_table kern_table[] = {
|
||||
.data = &softlockup_thresh,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_minmax,
|
||||
.proc_handler = &proc_dosoftlockup_thresh,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &neg_one,
|
||||
.extra2 = &sixty,
|
||||
@@ -974,7 +975,7 @@ static struct ctl_table vm_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = &dirty_background_bytes_handler,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &one,
|
||||
.extra1 = &one_ul,
|
||||
},
|
||||
{
|
||||
.ctl_name = VM_DIRTY_RATIO,
|
||||
@@ -995,7 +996,7 @@ static struct ctl_table vm_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = &dirty_bytes_handler,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &one,
|
||||
.extra1 = &one_ul,
|
||||
},
|
||||
{
|
||||
.procname = "dirty_writeback_centisecs",
|
||||
|
||||
@@ -273,6 +273,21 @@ out_bc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transfer the do_timer job away from a dying cpu.
|
||||
*
|
||||
* Called with interrupts disabled.
|
||||
*/
|
||||
static void tick_handover_do_timer(int *cpup)
|
||||
{
|
||||
if (*cpup == tick_do_timer_cpu) {
|
||||
int cpu = cpumask_first(cpu_online_mask);
|
||||
|
||||
tick_do_timer_cpu = (cpu < nr_cpu_ids) ? cpu :
|
||||
TICK_DO_TIMER_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown an event device on a given cpu:
|
||||
*
|
||||
@@ -297,13 +312,6 @@ static void tick_shutdown(unsigned int *cpup)
|
||||
clockevents_exchange_device(dev, NULL);
|
||||
td->evtdev = NULL;
|
||||
}
|
||||
/* Transfer the do_timer job away from this cpu */
|
||||
if (*cpup == tick_do_timer_cpu) {
|
||||
int cpu = cpumask_first(cpu_online_mask);
|
||||
|
||||
tick_do_timer_cpu = (cpu < nr_cpu_ids) ? cpu :
|
||||
TICK_DO_TIMER_NONE;
|
||||
}
|
||||
spin_unlock_irqrestore(&tick_device_lock, flags);
|
||||
}
|
||||
|
||||
@@ -357,6 +365,10 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
|
||||
tick_broadcast_oneshot_control(reason);
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_CPU_DYING:
|
||||
tick_handover_do_timer(dev);
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_CPU_DEAD:
|
||||
tick_shutdown_broadcast_oneshot(dev);
|
||||
tick_shutdown_broadcast(dev);
|
||||
|
||||
@@ -134,7 +134,7 @@ __setup("nohz=", setup_tick_nohz);
|
||||
* value. We do this unconditionally on any cpu, as we don't know whether the
|
||||
* cpu, which has the update task assigned is in a long sleep.
|
||||
*/
|
||||
void tick_nohz_update_jiffies(void)
|
||||
static void tick_nohz_update_jiffies(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
||||
|
||||
@@ -52,6 +52,7 @@ config FUNCTION_TRACER
|
||||
depends on HAVE_FUNCTION_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FRAME_POINTER
|
||||
select KALLSYMS
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
help
|
||||
@@ -238,6 +239,7 @@ config STACK_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FUNCTION_TRACER
|
||||
select STACKTRACE
|
||||
select KALLSYMS
|
||||
help
|
||||
This special tracer records the maximum stack footprint of the
|
||||
kernel and displays it in debugfs/tracing/stack_trace.
|
||||
@@ -302,4 +304,27 @@ config FTRACE_STARTUP_TEST
|
||||
functioning properly. It will do tests on all the configured
|
||||
tracers of ftrace.
|
||||
|
||||
config MMIOTRACE
|
||||
bool "Memory mapped IO tracing"
|
||||
depends on HAVE_MMIOTRACE_SUPPORT && DEBUG_KERNEL && PCI
|
||||
select TRACING
|
||||
help
|
||||
Mmiotrace traces Memory Mapped I/O access and is meant for
|
||||
debugging and reverse engineering. It is called from the ioremap
|
||||
implementation and works via page faults. Tracing is disabled by
|
||||
default and can be enabled at run-time.
|
||||
|
||||
See Documentation/tracers/mmiotrace.txt.
|
||||
If you are not helping to develop drivers, say N.
|
||||
|
||||
config MMIOTRACE_TEST
|
||||
tristate "Test module for mmiotrace"
|
||||
depends on MMIOTRACE && m
|
||||
help
|
||||
This is a dumb module for testing mmiotrace. It is very dangerous
|
||||
as it will write garbage to IO memory starting at a given address.
|
||||
However, it should be safe to use on e.g. unused portion of VRAM.
|
||||
|
||||
Say N, unless you absolutely know what you are doing.
|
||||
|
||||
endmenu
|
||||
|
||||
+37
-1
@@ -17,6 +17,7 @@
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/kthread.h>
|
||||
@@ -1736,9 +1737,12 @@ static void clear_ftrace_pid(struct pid *pid)
|
||||
{
|
||||
struct task_struct *p;
|
||||
|
||||
rcu_read_lock();
|
||||
do_each_pid_task(pid, PIDTYPE_PID, p) {
|
||||
clear_tsk_trace_trace(p);
|
||||
} while_each_pid_task(pid, PIDTYPE_PID, p);
|
||||
rcu_read_unlock();
|
||||
|
||||
put_pid(pid);
|
||||
}
|
||||
|
||||
@@ -1746,9 +1750,11 @@ static void set_ftrace_pid(struct pid *pid)
|
||||
{
|
||||
struct task_struct *p;
|
||||
|
||||
rcu_read_lock();
|
||||
do_each_pid_task(pid, PIDTYPE_PID, p) {
|
||||
set_tsk_trace_trace(p);
|
||||
} while_each_pid_task(pid, PIDTYPE_PID, p);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void clear_ftrace_pid_task(struct pid **pid)
|
||||
@@ -1965,6 +1971,7 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
|
||||
static atomic_t ftrace_graph_active;
|
||||
static struct notifier_block ftrace_suspend_notifier;
|
||||
|
||||
int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
|
||||
{
|
||||
@@ -2026,7 +2033,7 @@ free:
|
||||
static int start_graph_tracing(void)
|
||||
{
|
||||
struct ftrace_ret_stack **ret_stack_list;
|
||||
int ret;
|
||||
int ret, cpu;
|
||||
|
||||
ret_stack_list = kmalloc(FTRACE_RETSTACK_ALLOC_SIZE *
|
||||
sizeof(struct ftrace_ret_stack *),
|
||||
@@ -2035,6 +2042,10 @@ static int start_graph_tracing(void)
|
||||
if (!ret_stack_list)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The cpu_boot init_task->ret_stack will never be freed */
|
||||
for_each_online_cpu(cpu)
|
||||
ftrace_graph_init_task(idle_task(cpu));
|
||||
|
||||
do {
|
||||
ret = alloc_retstack_tasklist(ret_stack_list);
|
||||
} while (ret == -EAGAIN);
|
||||
@@ -2043,6 +2054,27 @@ static int start_graph_tracing(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hibernation protection.
|
||||
* The state of the current task is too much unstable during
|
||||
* suspend/restore to disk. We want to protect against that.
|
||||
*/
|
||||
static int
|
||||
ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,
|
||||
void *unused)
|
||||
{
|
||||
switch (state) {
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
pause_graph_tracing();
|
||||
break;
|
||||
|
||||
case PM_POST_HIBERNATION:
|
||||
unpause_graph_tracing();
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
||||
trace_func_graph_ent_t entryfunc)
|
||||
{
|
||||
@@ -2050,6 +2082,9 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
||||
|
||||
mutex_lock(&ftrace_sysctl_lock);
|
||||
|
||||
ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call;
|
||||
register_pm_notifier(&ftrace_suspend_notifier);
|
||||
|
||||
atomic_inc(&ftrace_graph_active);
|
||||
ret = start_graph_tracing();
|
||||
if (ret) {
|
||||
@@ -2075,6 +2110,7 @@ void unregister_ftrace_graph(void)
|
||||
ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
|
||||
ftrace_graph_entry = ftrace_graph_entry_stub;
|
||||
ftrace_shutdown(FTRACE_STOP_FUNC_RET);
|
||||
unregister_pm_notifier(&ftrace_suspend_notifier);
|
||||
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ static inline int test_time_stamp(u64 delta)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BUF_PAGE_SIZE (PAGE_SIZE - sizeof(struct buffer_data_page))
|
||||
#define BUF_PAGE_SIZE (PAGE_SIZE - offsetof(struct buffer_data_page, data))
|
||||
|
||||
/*
|
||||
* head_page == tail_page && head == tail then buffer is empty.
|
||||
@@ -1025,12 +1025,8 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
}
|
||||
|
||||
if (next_page == head_page) {
|
||||
if (!(buffer->flags & RB_FL_OVERWRITE)) {
|
||||
/* reset write */
|
||||
if (tail <= BUF_PAGE_SIZE)
|
||||
local_set(&tail_page->write, tail);
|
||||
if (!(buffer->flags & RB_FL_OVERWRITE))
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* tail_page has not moved yet? */
|
||||
if (tail_page == cpu_buffer->tail_page) {
|
||||
@@ -1105,6 +1101,10 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
return event;
|
||||
|
||||
out_unlock:
|
||||
/* reset write */
|
||||
if (tail <= BUF_PAGE_SIZE)
|
||||
local_set(&tail_page->write, tail);
|
||||
|
||||
__raw_spin_unlock(&cpu_buffer->lock);
|
||||
local_irq_restore(flags);
|
||||
return NULL;
|
||||
@@ -2174,6 +2174,9 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
|
||||
|
||||
cpu_buffer->overrun = 0;
|
||||
cpu_buffer->entries = 0;
|
||||
|
||||
cpu_buffer->write_stamp = 0;
|
||||
cpu_buffer->read_stamp = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE)
|
||||
|
||||
unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX;
|
||||
unsigned long __read_mostly tracing_max_latency;
|
||||
unsigned long __read_mostly tracing_thresh;
|
||||
|
||||
/*
|
||||
@@ -3736,7 +3736,7 @@ static struct notifier_block trace_die_notifier = {
|
||||
* it if we decide to change what log level the ftrace dump
|
||||
* should be at.
|
||||
*/
|
||||
#define KERN_TRACE KERN_INFO
|
||||
#define KERN_TRACE KERN_EMERG
|
||||
|
||||
static void
|
||||
trace_printk_seq(struct trace_seq *s)
|
||||
@@ -3770,6 +3770,7 @@ void ftrace_dump(void)
|
||||
dump_ran = 1;
|
||||
|
||||
/* No turning back! */
|
||||
tracing_off();
|
||||
ftrace_kill();
|
||||
|
||||
for_each_tracing_cpu(cpu) {
|
||||
|
||||
@@ -380,6 +380,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr)
|
||||
|
||||
static void __irqsoff_tracer_init(struct trace_array *tr)
|
||||
{
|
||||
tracing_max_latency = 0;
|
||||
irqsoff_trace = tr;
|
||||
/* make sure that the tracer is visible */
|
||||
smp_wmb();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mmiotrace.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
@@ -19,6 +20,7 @@ struct header_iter {
|
||||
static struct trace_array *mmio_trace_array;
|
||||
static bool overrun_detected;
|
||||
static unsigned long prev_overruns;
|
||||
static atomic_t dropped_count;
|
||||
|
||||
static void mmio_reset_data(struct trace_array *tr)
|
||||
{
|
||||
@@ -121,11 +123,11 @@ static void mmio_close(struct trace_iterator *iter)
|
||||
|
||||
static unsigned long count_overruns(struct trace_iterator *iter)
|
||||
{
|
||||
unsigned long cnt = 0;
|
||||
unsigned long cnt = atomic_xchg(&dropped_count, 0);
|
||||
unsigned long over = ring_buffer_overruns(iter->tr->buffer);
|
||||
|
||||
if (over > prev_overruns)
|
||||
cnt = over - prev_overruns;
|
||||
cnt += over - prev_overruns;
|
||||
prev_overruns = over;
|
||||
return cnt;
|
||||
}
|
||||
@@ -310,8 +312,10 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
|
||||
|
||||
event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
|
||||
&irq_flags);
|
||||
if (!event)
|
||||
if (!event) {
|
||||
atomic_inc(&dropped_count);
|
||||
return;
|
||||
}
|
||||
entry = ring_buffer_event_data(event);
|
||||
tracing_generic_entry_update(&entry->ent, 0, preempt_count());
|
||||
entry->ent.type = TRACE_MMIO_RW;
|
||||
@@ -338,8 +342,10 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
|
||||
|
||||
event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
|
||||
&irq_flags);
|
||||
if (!event)
|
||||
if (!event) {
|
||||
atomic_inc(&dropped_count);
|
||||
return;
|
||||
}
|
||||
entry = ring_buffer_event_data(event);
|
||||
tracing_generic_entry_update(&entry->ent, 0, preempt_count());
|
||||
entry->ent.type = TRACE_MMIO_MAP;
|
||||
|
||||
@@ -333,6 +333,7 @@ static void stop_wakeup_tracer(struct trace_array *tr)
|
||||
|
||||
static int wakeup_tracer_init(struct trace_array *tr)
|
||||
{
|
||||
tracing_max_latency = 0;
|
||||
wakeup_trace = tr;
|
||||
start_wakeup_tracer(tr);
|
||||
return 0;
|
||||
|
||||
@@ -23,10 +23,20 @@ static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
|
||||
{
|
||||
struct ring_buffer_event *event;
|
||||
struct trace_entry *entry;
|
||||
unsigned int loops = 0;
|
||||
|
||||
while ((event = ring_buffer_consume(tr->buffer, cpu, NULL))) {
|
||||
entry = ring_buffer_event_data(event);
|
||||
|
||||
/*
|
||||
* The ring buffer is a size of trace_buf_size, if
|
||||
* we loop more than the size, there's something wrong
|
||||
* with the ring buffer.
|
||||
*/
|
||||
if (loops++ > trace_buf_size) {
|
||||
printk(KERN_CONT ".. bad ring buffer ");
|
||||
goto failed;
|
||||
}
|
||||
if (!trace_valid_entry(entry)) {
|
||||
printk(KERN_CONT ".. invalid entry %d ",
|
||||
entry->type);
|
||||
@@ -57,11 +67,20 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
|
||||
|
||||
cnt = ring_buffer_entries(tr->buffer);
|
||||
|
||||
/*
|
||||
* The trace_test_buffer_cpu runs a while loop to consume all data.
|
||||
* If the calling tracer is broken, and is constantly filling
|
||||
* the buffer, this will run forever, and hard lock the box.
|
||||
* We disable the ring buffer while we do this test to prevent
|
||||
* a hard lock up.
|
||||
*/
|
||||
tracing_off();
|
||||
for_each_possible_cpu(cpu) {
|
||||
ret = trace_test_buffer_cpu(tr, cpu);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
tracing_on();
|
||||
__raw_spin_unlock(&ftrace_max_lock);
|
||||
local_irq_restore(flags);
|
||||
|
||||
|
||||
+1
-2
@@ -72,6 +72,7 @@ static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
|
||||
static void uid_hash_remove(struct user_struct *up)
|
||||
{
|
||||
hlist_del_init(&up->uidhash_node);
|
||||
put_user_ns(up->user_ns);
|
||||
}
|
||||
|
||||
static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
|
||||
@@ -334,7 +335,6 @@ static void free_user(struct user_struct *up, unsigned long flags)
|
||||
atomic_inc(&up->__count);
|
||||
spin_unlock_irqrestore(&uidhash_lock, flags);
|
||||
|
||||
put_user_ns(up->user_ns);
|
||||
INIT_WORK(&up->work, remove_user_sysfs_dir);
|
||||
schedule_work(&up->work);
|
||||
}
|
||||
@@ -357,7 +357,6 @@ static void free_user(struct user_struct *up, unsigned long flags)
|
||||
sched_destroy_user(up);
|
||||
key_put(up->uid_keyring);
|
||||
key_put(up->session_keyring);
|
||||
put_user_ns(up->user_ns);
|
||||
kmem_cache_free(uid_cachep, up);
|
||||
}
|
||||
|
||||
|
||||
+17
-4
@@ -60,12 +60,25 @@ int create_user_ns(struct cred *new)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_user_ns(struct kref *kref)
|
||||
/*
|
||||
* Deferred destructor for a user namespace. This is required because
|
||||
* free_user_ns() may be called with uidhash_lock held, but we need to call
|
||||
* back to free_uid() which will want to take the lock again.
|
||||
*/
|
||||
static void free_user_ns_work(struct work_struct *work)
|
||||
{
|
||||
struct user_namespace *ns;
|
||||
|
||||
ns = container_of(kref, struct user_namespace, kref);
|
||||
struct user_namespace *ns =
|
||||
container_of(work, struct user_namespace, destroyer);
|
||||
free_uid(ns->creator);
|
||||
kfree(ns);
|
||||
}
|
||||
|
||||
void free_user_ns(struct kref *kref)
|
||||
{
|
||||
struct user_namespace *ns =
|
||||
container_of(kref, struct user_namespace, kref);
|
||||
|
||||
INIT_WORK(&ns->destroyer, free_user_ns_work);
|
||||
schedule_work(&ns->destroyer);
|
||||
}
|
||||
EXPORT_SYMBOL(free_user_ns);
|
||||
|
||||
+52
-7
@@ -91,6 +91,15 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
|
||||
}
|
||||
EXPORT_SYMBOL(prepare_to_wait_exclusive);
|
||||
|
||||
/*
|
||||
* finish_wait - clean up after waiting in a queue
|
||||
* @q: waitqueue waited on
|
||||
* @wait: wait descriptor
|
||||
*
|
||||
* Sets current thread back to running state and removes
|
||||
* the wait descriptor from the given waitqueue if still
|
||||
* queued.
|
||||
*/
|
||||
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -117,6 +126,39 @@ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
|
||||
}
|
||||
EXPORT_SYMBOL(finish_wait);
|
||||
|
||||
/*
|
||||
* abort_exclusive_wait - abort exclusive waiting in a queue
|
||||
* @q: waitqueue waited on
|
||||
* @wait: wait descriptor
|
||||
* @state: runstate of the waiter to be woken
|
||||
* @key: key to identify a wait bit queue or %NULL
|
||||
*
|
||||
* Sets current thread back to running state and removes
|
||||
* the wait descriptor from the given waitqueue if still
|
||||
* queued.
|
||||
*
|
||||
* Wakes up the next waiter if the caller is concurrently
|
||||
* woken up through the queue.
|
||||
*
|
||||
* This prevents waiter starvation where an exclusive waiter
|
||||
* aborts and is woken up concurrently and noone wakes up
|
||||
* the next waiter.
|
||||
*/
|
||||
void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
|
||||
unsigned int mode, void *key)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
if (!list_empty(&wait->task_list))
|
||||
list_del_init(&wait->task_list);
|
||||
else if (waitqueue_active(q))
|
||||
__wake_up_common(q, mode, 1, 0, key);
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(abort_exclusive_wait);
|
||||
|
||||
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
|
||||
{
|
||||
int ret = default_wake_function(wait, mode, sync, key);
|
||||
@@ -177,17 +219,20 @@ int __sched
|
||||
__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
|
||||
int (*action)(void *), unsigned mode)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
do {
|
||||
int ret;
|
||||
|
||||
prepare_to_wait_exclusive(wq, &q->wait, mode);
|
||||
if (test_bit(q->key.bit_nr, q->key.flags)) {
|
||||
if ((ret = (*action)(q->key.flags)))
|
||||
break;
|
||||
}
|
||||
if (!test_bit(q->key.bit_nr, q->key.flags))
|
||||
continue;
|
||||
ret = action(q->key.flags);
|
||||
if (!ret)
|
||||
continue;
|
||||
abort_exclusive_wait(wq, &q->wait, mode, &q->key);
|
||||
return ret;
|
||||
} while (test_and_set_bit(q->key.bit_nr, q->key.flags));
|
||||
finish_wait(wq, &q->wait);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(__wait_on_bit_lock);
|
||||
|
||||
|
||||
+10
-10
@@ -971,6 +971,8 @@ undo:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static struct workqueue_struct *work_on_cpu_wq __read_mostly;
|
||||
|
||||
struct work_for_cpu {
|
||||
struct work_struct work;
|
||||
long (*fn)(void *);
|
||||
@@ -991,8 +993,8 @@ static void do_work_for_cpu(struct work_struct *w)
|
||||
* @fn: the function to run
|
||||
* @arg: the function arg
|
||||
*
|
||||
* This will return -EINVAL in the cpu is not online, or the return value
|
||||
* of @fn otherwise.
|
||||
* This will return the value @fn returns.
|
||||
* It is up to the caller to ensure that the cpu doesn't go offline.
|
||||
*/
|
||||
long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
|
||||
{
|
||||
@@ -1001,14 +1003,8 @@ long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
|
||||
INIT_WORK(&wfc.work, do_work_for_cpu);
|
||||
wfc.fn = fn;
|
||||
wfc.arg = arg;
|
||||
get_online_cpus();
|
||||
if (unlikely(!cpu_online(cpu)))
|
||||
wfc.ret = -EINVAL;
|
||||
else {
|
||||
schedule_work_on(cpu, &wfc.work);
|
||||
flush_work(&wfc.work);
|
||||
}
|
||||
put_online_cpus();
|
||||
queue_work_on(cpu, work_on_cpu_wq, &wfc.work);
|
||||
flush_work(&wfc.work);
|
||||
|
||||
return wfc.ret;
|
||||
}
|
||||
@@ -1025,4 +1021,8 @@ void __init init_workqueues(void)
|
||||
hotcpu_notifier(workqueue_cpu_callback, 0);
|
||||
keventd_wq = create_workqueue("events");
|
||||
BUG_ON(!keventd_wq);
|
||||
#ifdef CONFIG_SMP
|
||||
work_on_cpu_wq = create_workqueue("work_on_cpu");
|
||||
BUG_ON(!work_on_cpu_wq);
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user