Merge branches 'core/debugobjects', 'core/iommu', 'core/locking', 'core/printk', 'core/rcu', 'core/resources', 'core/softirq' and 'core/stacktrace' into core/core
This commit is contained in:

@@ -52,28 +52,3 @@ config PREEMPT
|
||||
|
||||
endchoice
|
||||
|
||||
config PREEMPT_RCU
|
||||
bool "Preemptible RCU"
|
||||
depends on PREEMPT
|
||||
default n
|
||||
help
|
||||
This option reduces the latency of the kernel by making certain
|
||||
RCU sections preemptible. Normally RCU code is non-preemptible, if
|
||||
this option is selected then read-only RCU sections become
|
||||
preemptible. This helps latency, but may expose bugs due to
|
||||
now-naive assumptions about each RCU read-side critical section
|
||||
remaining on a given CPU through its execution.
|
||||
|
||||
Say N if you are unsure.
|
||||
|
||||
config RCU_TRACE
|
||||
bool "Enable tracing for RCU - currently stats in debugfs"
|
||||
depends on PREEMPT_RCU
|
||||
select DEBUG_FS
|
||||
default y
|
||||
help
|
||||
This option provides tracing in RCU which presents stats
|
||||
in debugfs for debugging RCU implementation.
|
||||
|
||||
Say Y here if you want to enable RCU tracing
|
||||
Say N if you are unsure.
|
||||
|
@@ -74,10 +74,10 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
|
||||
obj-$(CONFIG_SECCOMP) += seccomp.o
|
||||
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
|
||||
obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o
|
||||
obj-$(CONFIG_TREE_RCU) += rcutree.o
|
||||
obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o
|
||||
ifeq ($(CONFIG_PREEMPT_RCU),y)
|
||||
obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o
|
||||
endif
|
||||
obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o
|
||||
obj-$(CONFIG_PREEMPT_RCU_TRACE) += rcupreempt_trace.o
|
||||
obj-$(CONFIG_RELAY) += relay.o
|
||||
obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
|
||||
obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
|
||||
|
@@ -673,6 +673,18 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
||||
struct irq_desc *desc;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* handle_IRQ_event() always ignores IRQF_DISABLED except for
|
||||
* the _first_ irqaction (sigh). That can cause oopsing, but
|
||||
* the behavior is classified as "will not fix" so we need to
|
||||
* start nudging drivers away from using that idiom.
|
||||
*/
|
||||
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED))
|
||||
== (IRQF_SHARED|IRQF_DISABLED))
|
||||
pr_warning("IRQ %d/%s: IRQF_DISABLED is not "
|
||||
"guaranteed on shared IRQs\n",
|
||||
irq, devname);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
/*
|
||||
* Lockdep wants atomic interrupt handlers:
|
||||
|
@@ -291,14 +291,12 @@ void lockdep_off(void)
|
||||
{
|
||||
current->lockdep_recursion++;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(lockdep_off);
|
||||
|
||||
void lockdep_on(void)
|
||||
{
|
||||
current->lockdep_recursion--;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(lockdep_on);
|
||||
|
||||
/*
|
||||
@@ -580,7 +578,8 @@ static void print_lock_class_header(struct lock_class *class, int depth)
|
||||
/*
|
||||
* printk all lock dependencies starting at <entry>:
|
||||
*/
|
||||
static void print_lock_dependencies(struct lock_class *class, int depth)
|
||||
static void __used
|
||||
print_lock_dependencies(struct lock_class *class, int depth)
|
||||
{
|
||||
struct lock_list *entry;
|
||||
|
||||
@@ -2512,7 +2511,6 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
|
||||
if (subclass)
|
||||
register_lock_class(lock, subclass, 1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(lockdep_init_map);
|
||||
|
||||
/*
|
||||
@@ -2693,8 +2691,9 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock,
|
||||
}
|
||||
|
||||
static int
|
||||
__lock_set_subclass(struct lockdep_map *lock,
|
||||
unsigned int subclass, unsigned long ip)
|
||||
__lock_set_class(struct lockdep_map *lock, const char *name,
|
||||
struct lock_class_key *key, unsigned int subclass,
|
||||
unsigned long ip)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
struct held_lock *hlock, *prev_hlock;
|
||||
@@ -2721,6 +2720,7 @@ __lock_set_subclass(struct lockdep_map *lock,
|
||||
return print_unlock_inbalance_bug(curr, lock, ip);
|
||||
|
||||
found_it:
|
||||
lockdep_init_map(lock, name, key, 0);
|
||||
class = register_lock_class(lock, subclass, 0);
|
||||
hlock->class_idx = class - lock_classes + 1;
|
||||
|
||||
@@ -2905,9 +2905,9 @@ static void check_flags(unsigned long flags)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lock_set_subclass(struct lockdep_map *lock,
|
||||
unsigned int subclass, unsigned long ip)
|
||||
void lock_set_class(struct lockdep_map *lock, const char *name,
|
||||
struct lock_class_key *key, unsigned int subclass,
|
||||
unsigned long ip)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@@ -2917,13 +2917,12 @@ lock_set_subclass(struct lockdep_map *lock,
|
||||
raw_local_irq_save(flags);
|
||||
current->lockdep_recursion = 1;
|
||||
check_flags(flags);
|
||||
if (__lock_set_subclass(lock, subclass, ip))
|
||||
if (__lock_set_class(lock, name, key, subclass, ip))
|
||||
check_chain_key(current);
|
||||
current->lockdep_recursion = 0;
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(lock_set_subclass);
|
||||
EXPORT_SYMBOL_GPL(lock_set_class);
|
||||
|
||||
/*
|
||||
* We are not always called with irqs disabled - do that here,
|
||||
@@ -2947,7 +2946,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
||||
current->lockdep_recursion = 0;
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(lock_acquire);
|
||||
|
||||
void lock_release(struct lockdep_map *lock, int nested,
|
||||
@@ -2965,7 +2963,6 @@ void lock_release(struct lockdep_map *lock, int nested,
|
||||
current->lockdep_recursion = 0;
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(lock_release);
|
||||
|
||||
#ifdef CONFIG_LOCK_STAT
|
||||
@@ -3450,7 +3447,6 @@ retry:
|
||||
if (unlock)
|
||||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(debug_show_all_locks);
|
||||
|
||||
/*
|
||||
@@ -3471,7 +3467,6 @@ void debug_show_held_locks(struct task_struct *task)
|
||||
{
|
||||
__debug_show_held_locks(task);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(debug_show_held_locks);
|
||||
|
||||
void lockdep_sys_exit(void)
|
||||
|
@@ -662,7 +662,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
|
||||
if (recursion_bug) {
|
||||
recursion_bug = 0;
|
||||
strcpy(printk_buf, recursion_bug_msg);
|
||||
printed_len = sizeof(recursion_bug_msg);
|
||||
printed_len = strlen(recursion_bug_msg);
|
||||
}
|
||||
/* Emit the output into the temporary buffer */
|
||||
printed_len += vscnprintf(printk_buf + printed_len,
|
||||
|
@@ -551,6 +551,16 @@ void rcu_irq_exit(void)
|
||||
}
|
||||
}
|
||||
|
||||
void rcu_nmi_enter(void)
|
||||
{
|
||||
rcu_irq_enter();
|
||||
}
|
||||
|
||||
void rcu_nmi_exit(void)
|
||||
{
|
||||
rcu_irq_exit();
|
||||
}
|
||||
|
||||
static void dyntick_save_progress_counter(int cpu)
|
||||
{
|
||||
struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
|
||||
|
@@ -149,12 +149,12 @@ static void rcupreempt_trace_sum(struct rcupreempt_trace *sp)
|
||||
sp->done_length += cp->done_length;
|
||||
sp->done_add += cp->done_add;
|
||||
sp->done_remove += cp->done_remove;
|
||||
atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked));
|
||||
atomic_add(atomic_read(&cp->done_invoked), &sp->done_invoked);
|
||||
sp->rcu_check_callbacks += cp->rcu_check_callbacks;
|
||||
atomic_set(&sp->rcu_try_flip_1,
|
||||
atomic_read(&cp->rcu_try_flip_1));
|
||||
atomic_set(&sp->rcu_try_flip_e1,
|
||||
atomic_read(&cp->rcu_try_flip_e1));
|
||||
atomic_add(atomic_read(&cp->rcu_try_flip_1),
|
||||
&sp->rcu_try_flip_1);
|
||||
atomic_add(atomic_read(&cp->rcu_try_flip_e1),
|
||||
&sp->rcu_try_flip_e1);
|
||||
sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1;
|
||||
sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1;
|
||||
sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1;
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -108,7 +109,6 @@ struct rcu_torture {
|
||||
int rtort_mbtest;
|
||||
};
|
||||
|
||||
static int fullstop = 0; /* stop generating callbacks at test end. */
|
||||
static LIST_HEAD(rcu_torture_freelist);
|
||||
static struct rcu_torture *rcu_torture_current = NULL;
|
||||
static long rcu_torture_current_version = 0;
|
||||
@@ -136,6 +136,30 @@ static int stutter_pause_test = 0;
|
||||
#endif
|
||||
int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
|
||||
|
||||
#define FULLSTOP_SIGNALED 1 /* Bail due to signal. */
|
||||
#define FULLSTOP_CLEANUP 2 /* Orderly shutdown. */
|
||||
static int fullstop; /* stop generating callbacks at test end. */
|
||||
DEFINE_MUTEX(fullstop_mutex); /* protect fullstop transitions and */
|
||||
/* spawning of kthreads. */
|
||||
|
||||
/*
|
||||
* Detect and respond to a signal-based shutdown.
|
||||
*/
|
||||
static int
|
||||
rcutorture_shutdown_notify(struct notifier_block *unused1,
|
||||
unsigned long unused2, void *unused3)
|
||||
{
|
||||
if (fullstop)
|
||||
return NOTIFY_DONE;
|
||||
if (signal_pending(current)) {
|
||||
mutex_lock(&fullstop_mutex);
|
||||
if (!ACCESS_ONCE(fullstop))
|
||||
fullstop = FULLSTOP_SIGNALED;
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an element from the rcu_tortures pool.
|
||||
*/
|
||||
@@ -199,11 +223,12 @@ rcu_random(struct rcu_random_state *rrsp)
|
||||
static void
|
||||
rcu_stutter_wait(void)
|
||||
{
|
||||
while (stutter_pause_test || !rcutorture_runnable)
|
||||
while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) {
|
||||
if (rcutorture_runnable)
|
||||
schedule_timeout_interruptible(1);
|
||||
else
|
||||
schedule_timeout_interruptible(round_jiffies_relative(HZ));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -599,7 +624,7 @@ rcu_torture_writer(void *arg)
|
||||
rcu_stutter_wait();
|
||||
} while (!kthread_should_stop() && !fullstop);
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
|
||||
while (!kthread_should_stop())
|
||||
while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
|
||||
schedule_timeout_uninterruptible(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -624,7 +649,7 @@ rcu_torture_fakewriter(void *arg)
|
||||
} while (!kthread_should_stop() && !fullstop);
|
||||
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
|
||||
while (!kthread_should_stop())
|
||||
while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
|
||||
schedule_timeout_uninterruptible(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -734,7 +759,7 @@ rcu_torture_reader(void *arg)
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
|
||||
if (irqreader && cur_ops->irqcapable)
|
||||
del_timer_sync(&t);
|
||||
while (!kthread_should_stop())
|
||||
while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
|
||||
schedule_timeout_uninterruptible(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -831,7 +856,7 @@ rcu_torture_stats(void *arg)
|
||||
do {
|
||||
schedule_timeout_interruptible(stat_interval * HZ);
|
||||
rcu_torture_stats_print();
|
||||
} while (!kthread_should_stop());
|
||||
} while (!kthread_should_stop() && !fullstop);
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
|
||||
return 0;
|
||||
}
|
||||
@@ -899,7 +924,7 @@ rcu_torture_shuffle(void *arg)
|
||||
do {
|
||||
schedule_timeout_interruptible(shuffle_interval * HZ);
|
||||
rcu_torture_shuffle_tasks();
|
||||
} while (!kthread_should_stop());
|
||||
} while (!kthread_should_stop() && !fullstop);
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
|
||||
return 0;
|
||||
}
|
||||
@@ -914,10 +939,10 @@ rcu_torture_stutter(void *arg)
|
||||
do {
|
||||
schedule_timeout_interruptible(stutter * HZ);
|
||||
stutter_pause_test = 1;
|
||||
if (!kthread_should_stop())
|
||||
if (!kthread_should_stop() && !fullstop)
|
||||
schedule_timeout_interruptible(stutter * HZ);
|
||||
stutter_pause_test = 0;
|
||||
} while (!kthread_should_stop());
|
||||
} while (!kthread_should_stop() && !fullstop);
|
||||
VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
|
||||
return 0;
|
||||
}
|
||||
@@ -934,12 +959,27 @@ rcu_torture_print_module_parms(char *tag)
|
||||
stutter, irqreader);
|
||||
}
|
||||
|
||||
static struct notifier_block rcutorture_nb = {
|
||||
.notifier_call = rcutorture_shutdown_notify,
|
||||
};
|
||||
|
||||
static void
|
||||
rcu_torture_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
fullstop = 1;
|
||||
mutex_lock(&fullstop_mutex);
|
||||
if (!fullstop) {
|
||||
/* If being signaled, let it happen, then exit. */
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
schedule_timeout_interruptible(10 * HZ);
|
||||
if (cur_ops->cb_barrier != NULL)
|
||||
cur_ops->cb_barrier();
|
||||
return;
|
||||
}
|
||||
fullstop = FULLSTOP_CLEANUP;
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
unregister_reboot_notifier(&rcutorture_nb);
|
||||
if (stutter_task) {
|
||||
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
|
||||
kthread_stop(stutter_task);
|
||||
@@ -1015,6 +1055,8 @@ rcu_torture_init(void)
|
||||
{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
|
||||
&srcu_ops, &sched_ops, &sched_ops_sync, };
|
||||
|
||||
mutex_lock(&fullstop_mutex);
|
||||
|
||||
/* Process args and tell the world that the torturer is on the job. */
|
||||
for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
|
||||
cur_ops = torture_ops[i];
|
||||
@@ -1024,6 +1066,7 @@ rcu_torture_init(void)
|
||||
if (i == ARRAY_SIZE(torture_ops)) {
|
||||
printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
|
||||
torture_type);
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
return (-EINVAL);
|
||||
}
|
||||
if (cur_ops->init)
|
||||
@@ -1146,9 +1189,12 @@ rcu_torture_init(void)
|
||||
goto unwind;
|
||||
}
|
||||
}
|
||||
register_reboot_notifier(&rcutorture_nb);
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
return 0;
|
||||
|
||||
unwind:
|
||||
mutex_unlock(&fullstop_mutex);
|
||||
rcu_torture_cleanup();
|
||||
return firsterr;
|
||||
}
|
||||
|
1535
kernel/rcutree.c
Normal file
1535
kernel/rcutree.c
Normal file
File diff suppressed because it is too large
Load Diff
271
kernel/rcutree_trace.c
Normal file
271
kernel/rcutree_trace.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Read-Copy Update tracing for classic implementation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright IBM Corporation, 2008
|
||||
*
|
||||
* Papers: http://www.rdrop.com/users/paulmck/RCU
|
||||
*
|
||||
* For detailed explanation of Read-Copy Update mechanism see -
|
||||
* Documentation/RCU
|
||||
*
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
|
||||
{
|
||||
if (!rdp->beenonline)
|
||||
return;
|
||||
seq_printf(m, "%3d%cc=%ld g=%ld pq=%d pqc=%ld qp=%d rpfq=%ld rp=%x",
|
||||
rdp->cpu,
|
||||
cpu_is_offline(rdp->cpu) ? '!' : ' ',
|
||||
rdp->completed, rdp->gpnum,
|
||||
rdp->passed_quiesc, rdp->passed_quiesc_completed,
|
||||
rdp->qs_pending,
|
||||
rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending,
|
||||
(int)(rdp->n_rcu_pending & 0xffff));
|
||||
#ifdef CONFIG_NO_HZ
|
||||
seq_printf(m, " dt=%d/%d dn=%d df=%lu",
|
||||
rdp->dynticks->dynticks,
|
||||
rdp->dynticks->dynticks_nesting,
|
||||
rdp->dynticks->dynticks_nmi,
|
||||
rdp->dynticks_fqs);
|
||||
#endif /* #ifdef CONFIG_NO_HZ */
|
||||
seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
|
||||
seq_printf(m, " ql=%ld b=%ld\n", rdp->qlen, rdp->blimit);
|
||||
}
|
||||
|
||||
#define PRINT_RCU_DATA(name, func, m) \
|
||||
do { \
|
||||
int _p_r_d_i; \
|
||||
\
|
||||
for_each_possible_cpu(_p_r_d_i) \
|
||||
func(m, &per_cpu(name, _p_r_d_i)); \
|
||||
} while (0)
|
||||
|
||||
static int show_rcudata(struct seq_file *m, void *unused)
|
||||
{
|
||||
seq_puts(m, "rcu:\n");
|
||||
PRINT_RCU_DATA(rcu_data, print_one_rcu_data, m);
|
||||
seq_puts(m, "rcu_bh:\n");
|
||||
PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcudata_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, show_rcudata, NULL);
|
||||
}
|
||||
|
||||
static struct file_operations rcudata_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rcudata_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
|
||||
{
|
||||
if (!rdp->beenonline)
|
||||
return;
|
||||
seq_printf(m, "%d,%s,%ld,%ld,%d,%ld,%d,%ld,%ld",
|
||||
rdp->cpu,
|
||||
cpu_is_offline(rdp->cpu) ? "\"Y\"" : "\"N\"",
|
||||
rdp->completed, rdp->gpnum,
|
||||
rdp->passed_quiesc, rdp->passed_quiesc_completed,
|
||||
rdp->qs_pending,
|
||||
rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending,
|
||||
rdp->n_rcu_pending);
|
||||
#ifdef CONFIG_NO_HZ
|
||||
seq_printf(m, ",%d,%d,%d,%lu",
|
||||
rdp->dynticks->dynticks,
|
||||
rdp->dynticks->dynticks_nesting,
|
||||
rdp->dynticks->dynticks_nmi,
|
||||
rdp->dynticks_fqs);
|
||||
#endif /* #ifdef CONFIG_NO_HZ */
|
||||
seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
|
||||
seq_printf(m, ",%ld,%ld\n", rdp->qlen, rdp->blimit);
|
||||
}
|
||||
|
||||
static int show_rcudata_csv(struct seq_file *m, void *unused)
|
||||
{
|
||||
seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\",\"rpfq\",\"rp\",");
|
||||
#ifdef CONFIG_NO_HZ
|
||||
seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
|
||||
#endif /* #ifdef CONFIG_NO_HZ */
|
||||
seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\"\n");
|
||||
seq_puts(m, "\"rcu:\"\n");
|
||||
PRINT_RCU_DATA(rcu_data, print_one_rcu_data_csv, m);
|
||||
seq_puts(m, "\"rcu_bh:\"\n");
|
||||
PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcudata_csv_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, show_rcudata_csv, NULL);
|
||||
}
|
||||
|
||||
static struct file_operations rcudata_csv_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rcudata_csv_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
|
||||
{
|
||||
int level = 0;
|
||||
struct rcu_node *rnp;
|
||||
|
||||
seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x "
|
||||
"nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu\n",
|
||||
rsp->completed, rsp->gpnum, rsp->signaled,
|
||||
(long)(rsp->jiffies_force_qs - jiffies),
|
||||
(int)(jiffies & 0xffff),
|
||||
rsp->n_force_qs, rsp->n_force_qs_ngp,
|
||||
rsp->n_force_qs - rsp->n_force_qs_ngp,
|
||||
rsp->n_force_qs_lh);
|
||||
for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
|
||||
if (rnp->level != level) {
|
||||
seq_puts(m, "\n");
|
||||
level = rnp->level;
|
||||
}
|
||||
seq_printf(m, "%lx/%lx %d:%d ^%d ",
|
||||
rnp->qsmask, rnp->qsmaskinit,
|
||||
rnp->grplo, rnp->grphi, rnp->grpnum);
|
||||
}
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
||||
static int show_rcuhier(struct seq_file *m, void *unused)
|
||||
{
|
||||
seq_puts(m, "rcu:\n");
|
||||
print_one_rcu_state(m, &rcu_state);
|
||||
seq_puts(m, "rcu_bh:\n");
|
||||
print_one_rcu_state(m, &rcu_bh_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcuhier_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, show_rcuhier, NULL);
|
||||
}
|
||||
|
||||
static struct file_operations rcuhier_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rcuhier_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int show_rcugp(struct seq_file *m, void *unused)
|
||||
{
|
||||
seq_printf(m, "rcu: completed=%ld gpnum=%ld\n",
|
||||
rcu_state.completed, rcu_state.gpnum);
|
||||
seq_printf(m, "rcu_bh: completed=%ld gpnum=%ld\n",
|
||||
rcu_bh_state.completed, rcu_bh_state.gpnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcugp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, show_rcugp, NULL);
|
||||
}
|
||||
|
||||
static struct file_operations rcugp_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rcugp_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir;
|
||||
static int __init rcuclassic_trace_init(void)
|
||||
{
|
||||
rcudir = debugfs_create_dir("rcu", NULL);
|
||||
if (!rcudir)
|
||||
goto out;
|
||||
|
||||
datadir = debugfs_create_file("rcudata", 0444, rcudir,
|
||||
NULL, &rcudata_fops);
|
||||
if (!datadir)
|
||||
goto free_out;
|
||||
|
||||
datadir_csv = debugfs_create_file("rcudata.csv", 0444, rcudir,
|
||||
NULL, &rcudata_csv_fops);
|
||||
if (!datadir_csv)
|
||||
goto free_out;
|
||||
|
||||
gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
|
||||
if (!gpdir)
|
||||
goto free_out;
|
||||
|
||||
hierdir = debugfs_create_file("rcuhier", 0444, rcudir,
|
||||
NULL, &rcuhier_fops);
|
||||
if (!hierdir)
|
||||
goto free_out;
|
||||
return 0;
|
||||
free_out:
|
||||
if (datadir)
|
||||
debugfs_remove(datadir);
|
||||
if (datadir_csv)
|
||||
debugfs_remove(datadir_csv);
|
||||
if (gpdir)
|
||||
debugfs_remove(gpdir);
|
||||
debugfs_remove(rcudir);
|
||||
out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __exit rcuclassic_trace_cleanup(void)
|
||||
{
|
||||
debugfs_remove(datadir);
|
||||
debugfs_remove(datadir_csv);
|
||||
debugfs_remove(gpdir);
|
||||
debugfs_remove(hierdir);
|
||||
debugfs_remove(rcudir);
|
||||
}
|
||||
|
||||
|
||||
module_init(rcuclassic_trace_init);
|
||||
module_exit(rcuclassic_trace_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Paul E. McKenney");
|
||||
MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
|
||||
MODULE_LICENSE("GPL");
|
@@ -853,6 +853,15 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
|
||||
if (PFN_DOWN(p->start) <= PFN_DOWN(addr) &&
|
||||
PFN_DOWN(p->end) >= PFN_DOWN(addr + size - 1))
|
||||
continue;
|
||||
/*
|
||||
* if a resource is "BUSY", it's not a hardware resource
|
||||
* but a driver mapping of such a resource; we don't want
|
||||
* to warn for those; some drivers legitimately map only
|
||||
* partial hardware resources. (example: vesafb)
|
||||
*/
|
||||
if (p->flags & IORESOURCE_BUSY)
|
||||
continue;
|
||||
|
||||
printk(KERN_WARNING "resource map sanity check conflict: "
|
||||
"0x%llx 0x%llx 0x%llx 0x%llx %s\n",
|
||||
(unsigned long long)addr,
|
||||
|
@@ -102,20 +102,6 @@ void local_bh_disable(void)
|
||||
|
||||
EXPORT_SYMBOL(local_bh_disable);
|
||||
|
||||
void __local_bh_enable(void)
|
||||
{
|
||||
WARN_ON_ONCE(in_irq());
|
||||
|
||||
/*
|
||||
* softirqs should never be enabled by __local_bh_enable(),
|
||||
* it always nests inside local_bh_enable() sections:
|
||||
*/
|
||||
WARN_ON_ONCE(softirq_count() == SOFTIRQ_OFFSET);
|
||||
|
||||
sub_preempt_count(SOFTIRQ_OFFSET);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__local_bh_enable);
|
||||
|
||||
/*
|
||||
* Special-case - softirqs can safely be enabled in
|
||||
* cond_resched_softirq(), or by __do_softirq(),
|
||||
@@ -269,6 +255,7 @@ void irq_enter(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
rcu_irq_enter();
|
||||
if (idle_cpu(cpu) && !in_interrupt()) {
|
||||
__irq_enter();
|
||||
tick_check_idle(cpu);
|
||||
@@ -295,9 +282,9 @@ void irq_exit(void)
|
||||
|
||||
#ifdef CONFIG_NO_HZ
|
||||
/* Make sure that timer wheel updates are propagated */
|
||||
if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
|
||||
tick_nohz_stop_sched_tick(0);
|
||||
rcu_irq_exit();
|
||||
if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
|
||||
tick_nohz_stop_sched_tick(0);
|
||||
#endif
|
||||
preempt_enable_no_resched();
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
* Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/stacktrace.h>
|
||||
@@ -24,3 +25,13 @@ void print_stack_trace(struct stack_trace *trace, int spaces)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(print_stack_trace);
|
||||
|
||||
/*
|
||||
* Architectures that do not implement save_stack_trace_tsk get this
|
||||
* weak alias and a once-per-bootup warning (whenever this facility
|
||||
* is utilized - for example by procfs):
|
||||
*/
|
||||
__weak void
|
||||
save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
{
|
||||
WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n");
|
||||
}
|
||||
|
Reference in New Issue
Block a user