aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/rcutree.c41
-rw-r--r--kernel/rcutree.h3
2 files changed, 36 insertions, 8 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 79fa2db1595b..d62c04482228 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -366,11 +366,9 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
366 */ 366 */
367static void rcu_eqs_enter(bool user) 367static void rcu_eqs_enter(bool user)
368{ 368{
369 unsigned long flags;
370 long long oldval; 369 long long oldval;
371 struct rcu_dynticks *rdtp; 370 struct rcu_dynticks *rdtp;
372 371
373 local_irq_save(flags);
374 rdtp = &__get_cpu_var(rcu_dynticks); 372 rdtp = &__get_cpu_var(rcu_dynticks);
375 oldval = rdtp->dynticks_nesting; 373 oldval = rdtp->dynticks_nesting;
376 WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0); 374 WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
@@ -379,7 +377,6 @@ static void rcu_eqs_enter(bool user)
379 else 377 else
380 rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE; 378 rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
381 rcu_eqs_enter_common(rdtp, oldval, user); 379 rcu_eqs_enter_common(rdtp, oldval, user);
382 local_irq_restore(flags);
383} 380}
384 381
385/** 382/**
@@ -396,7 +393,11 @@ static void rcu_eqs_enter(bool user)
396 */ 393 */
397void rcu_idle_enter(void) 394void rcu_idle_enter(void)
398{ 395{
396 unsigned long flags;
397
398 local_irq_save(flags);
399 rcu_eqs_enter(0); 399 rcu_eqs_enter(0);
400 local_irq_restore(flags);
400} 401}
401EXPORT_SYMBOL_GPL(rcu_idle_enter); 402EXPORT_SYMBOL_GPL(rcu_idle_enter);
402 403
@@ -411,6 +412,9 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter);
411 */ 412 */
412void rcu_user_enter(void) 413void rcu_user_enter(void)
413{ 414{
415 unsigned long flags;
416 struct rcu_dynticks *rdtp;
417
414 /* 418 /*
415 * Some contexts may involve an exception occuring in an irq, 419 * Some contexts may involve an exception occuring in an irq,
416 * leading to that nesting: 420 * leading to that nesting:
@@ -422,7 +426,15 @@ void rcu_user_enter(void)
422 if (in_interrupt()) 426 if (in_interrupt())
423 return; 427 return;
424 428
425 rcu_eqs_enter(1); 429 WARN_ON_ONCE(!current->mm);
430
431 local_irq_save(flags);
432 rdtp = &__get_cpu_var(rcu_dynticks);
433 if (!rdtp->in_user) {
434 rdtp->in_user = true;
435 rcu_eqs_enter(1);
436 }
437 local_irq_restore(flags);
426} 438}
427 439
428/** 440/**
@@ -516,11 +528,9 @@ static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
516 */ 528 */
517static void rcu_eqs_exit(bool user) 529static void rcu_eqs_exit(bool user)
518{ 530{
519 unsigned long flags;
520 struct rcu_dynticks *rdtp; 531 struct rcu_dynticks *rdtp;
521 long long oldval; 532 long long oldval;
522 533
523 local_irq_save(flags);
524 rdtp = &__get_cpu_var(rcu_dynticks); 534 rdtp = &__get_cpu_var(rcu_dynticks);
525 oldval = rdtp->dynticks_nesting; 535 oldval = rdtp->dynticks_nesting;
526 WARN_ON_ONCE(oldval < 0); 536 WARN_ON_ONCE(oldval < 0);
@@ -529,7 +539,6 @@ static void rcu_eqs_exit(bool user)
529 else 539 else
530 rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; 540 rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
531 rcu_eqs_exit_common(rdtp, oldval, user); 541 rcu_eqs_exit_common(rdtp, oldval, user);
532 local_irq_restore(flags);
533} 542}
534 543
535/** 544/**
@@ -545,7 +554,11 @@ static void rcu_eqs_exit(bool user)
545 */ 554 */
546void rcu_idle_exit(void) 555void rcu_idle_exit(void)
547{ 556{
557 unsigned long flags;
558
559 local_irq_save(flags);
548 rcu_eqs_exit(0); 560 rcu_eqs_exit(0);
561 local_irq_restore(flags);
549} 562}
550EXPORT_SYMBOL_GPL(rcu_idle_exit); 563EXPORT_SYMBOL_GPL(rcu_idle_exit);
551 564
@@ -558,6 +571,9 @@ EXPORT_SYMBOL_GPL(rcu_idle_exit);
558 */ 571 */
559void rcu_user_exit(void) 572void rcu_user_exit(void)
560{ 573{
574 unsigned long flags;
575 struct rcu_dynticks *rdtp;
576
561 /* 577 /*
562 * Some contexts may involve an exception occuring in an irq, 578 * Some contexts may involve an exception occuring in an irq,
563 * leading to that nesting: 579 * leading to that nesting:
@@ -569,7 +585,13 @@ void rcu_user_exit(void)
569 if (in_interrupt()) 585 if (in_interrupt())
570 return; 586 return;
571 587
572 rcu_eqs_exit(1); 588 local_irq_save(flags);
589 rdtp = &__get_cpu_var(rcu_dynticks);
590 if (rdtp->in_user) {
591 rdtp->in_user = false;
592 rcu_eqs_exit(1);
593 }
594 local_irq_restore(flags);
573} 595}
574 596
575/** 597/**
@@ -2586,6 +2608,9 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
2586 rdp->dynticks = &per_cpu(rcu_dynticks, cpu); 2608 rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
2587 WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE); 2609 WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
2588 WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1); 2610 WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
2611#ifdef CONFIG_RCU_USER_QS
2612 WARN_ON_ONCE(rdp->dynticks->in_user);
2613#endif
2589 rdp->cpu = cpu; 2614 rdp->cpu = cpu;
2590 rdp->rsp = rsp; 2615 rdp->rsp = rsp;
2591 raw_spin_unlock_irqrestore(&rnp->lock, flags); 2616 raw_spin_unlock_irqrestore(&rnp->lock, flags);
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 7576fd4d8ce6..10cc2f9f8433 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -102,6 +102,9 @@ struct rcu_dynticks {
102 /* idle-period nonlazy_posted snapshot. */ 102 /* idle-period nonlazy_posted snapshot. */
103 int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */ 103 int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
104#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */ 104#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
105#ifdef CONFIG_RCU_USER_QS
106 bool in_user; /* Is the CPU in userland from RCU POV? */
107#endif
105}; 108};
106 109
107/* RCU's kthread states for tracing. */ 110/* RCU's kthread states for tracing. */