diff options
-rw-r--r-- | kernel/rcutree.c | 41 | ||||
-rw-r--r-- | kernel/rcutree.h | 3 |
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 | */ |
367 | static void rcu_eqs_enter(bool user) | 367 | static 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 | */ |
397 | void rcu_idle_enter(void) | 394 | void 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 | } |
401 | EXPORT_SYMBOL_GPL(rcu_idle_enter); | 402 | EXPORT_SYMBOL_GPL(rcu_idle_enter); |
402 | 403 | ||
@@ -411,6 +412,9 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter); | |||
411 | */ | 412 | */ |
412 | void rcu_user_enter(void) | 413 | void 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 | */ |
517 | static void rcu_eqs_exit(bool user) | 529 | static 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 | */ |
546 | void rcu_idle_exit(void) | 555 | void 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 | } |
550 | EXPORT_SYMBOL_GPL(rcu_idle_exit); | 563 | EXPORT_SYMBOL_GPL(rcu_idle_exit); |
551 | 564 | ||
@@ -558,6 +571,9 @@ EXPORT_SYMBOL_GPL(rcu_idle_exit); | |||
558 | */ | 571 | */ |
559 | void rcu_user_exit(void) | 572 | void 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. */ |