History

kcsan: Remove reporting indirection

Now that we have separate kcsan_report_*() functions, we can factor the distinct logic for each of the report cases out of kcsan_report(). While this means each case has to handle mutual exclusion independently, this minimizes the conditionality of code and makes it easier to read, and will permit passing distinct bits of information to print_report() in future. There should be no functional change as a result of this patch.

Mark Rutland committed 5 years ago

Commit 19dfdc01 parent 39b2e761 file · +49 −66Browse files

Unified · Split

kernel/kcsan/report.c+49−66
@@ -434,13 +434,11 @@ static void print_report(enum kcsan_value_change value_change, · 433 unmodified lines
434 434
435static void release_report(unsigned long *flags, struct other_info *other_info)435static void release_report(unsigned long *flags, struct other_info *other_info)
436{436{
437 if (other_info)437 /*
438 /*438 * Use size to denote valid/invalid, since KCSAN entirely ignores
439 * Use size to denote valid/invalid, since KCSAN entirely439 * 0-sized accesses.
440 * ignores 0-sized accesses.440 */
441 */441 other_info->ai.size = 0;
442 other_info->ai.size = 0;
443
444 raw_spin_unlock_irqrestore(&report_lock, *flags);442 raw_spin_unlock_irqrestore(&report_lock, *flags);
445}443}
446 444
@@ -573,61 +571,6 @@ discard: · 126 unmodified lines
573 return false;571 return false;
574}572}
575 573
576/*
577 * Depending on the report type either sets @other_info and returns false, or
578 * awaits @other_info and returns true. If @other_info is not required for the
579 * report type, simply acquires @report_lock and returns true.
580 */
581static noinline bool prepare_report(unsigned long *flags,
582 enum kcsan_report_type type,
583 const struct access_info *ai,
584 struct other_info *other_info)
585{
586 switch (type) {
587 case KCSAN_REPORT_CONSUMED_WATCHPOINT:
588 prepare_report_producer(flags, ai, other_info);
589 return false;
590 case KCSAN_REPORT_RACE_SIGNAL:
591 return prepare_report_consumer(flags, ai, other_info);
592 default:
593 /* @other_info not required; just acquire @report_lock. */
594 raw_spin_lock_irqsave(&report_lock, *flags);
595 return true;
596 }
597}
598
599static void kcsan_report(const struct access_info *ai, enum kcsan_value_change value_change,
600 enum kcsan_report_type type, struct other_info *other_info)
601{
602 unsigned long flags = 0;
603
604 kcsan_disable_current();
605
606 /*
607 * Because we may generate reports when we're in scheduler code, the use
608 * of printk() could deadlock. Until such time that all printing code
609 * called in print_report() is scheduler-safe, accept the risk, and just
610 * get our message out. As such, also disable lockdep to hide the
611 * warning, and avoid disabling lockdep for the rest of the kernel.
612 */
613 lockdep_off();
614
615 if (prepare_report(&flags, type, ai, other_info)) {
616 /*
617 * Never report if value_change is FALSE, only if we it is
618 * either TRUE or MAYBE. In case of MAYBE, further filtering may
619 * be done once we know the full stack trace in print_report().
620 */
621 if (value_change != KCSAN_VALUE_CHANGE_FALSE)
622 print_report(value_change, type, ai, other_info);
623
624 release_report(&flags, other_info);
625 }
626
627 lockdep_on();
628 kcsan_enable_current();
629}
630
631static struct access_info prepare_access_info(const volatile void *ptr, size_t size,574static struct access_info prepare_access_info(const volatile void *ptr, size_t size,
632 int access_type)575 int access_type)
633{576{
@@ -644,22 +587,62 @@ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_typ · 10 unmodified lines
644 int watchpoint_idx)587 int watchpoint_idx)
645{588{
646 const struct access_info ai = prepare_access_info(ptr, size, access_type);589 const struct access_info ai = prepare_access_info(ptr, size, access_type);
590 unsigned long flags;
591
592 kcsan_disable_current();
593 lockdep_off(); /* See kcsan_report_known_origin(). */
647 594
648 kcsan_report(&ai, KCSAN_VALUE_CHANGE_MAYBE, KCSAN_REPORT_CONSUMED_WATCHPOINT,595 prepare_report_producer(&flags, &ai, &other_infos[watchpoint_idx]);
649 &other_infos[watchpoint_idx]);596
597 lockdep_on();
598 kcsan_enable_current();
650}599}
651 600
652void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type,601void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type,
653 enum kcsan_value_change value_change, int watchpoint_idx)602 enum kcsan_value_change value_change, int watchpoint_idx)
654{603{
655 const struct access_info ai = prepare_access_info(ptr, size, access_type);604 const struct access_info ai = prepare_access_info(ptr, size, access_type);
605 struct other_info *other_info = &other_infos[watchpoint_idx];
606 unsigned long flags = 0;
656 607
657 kcsan_report(&ai, value_change, KCSAN_REPORT_RACE_SIGNAL, &other_infos[watchpoint_idx]);608 kcsan_disable_current();
609 /*
610 * Because we may generate reports when we're in scheduler code, the use
611 * of printk() could deadlock. Until such time that all printing code
612 * called in print_report() is scheduler-safe, accept the risk, and just
613 * get our message out. As such, also disable lockdep to hide the
614 * warning, and avoid disabling lockdep for the rest of the kernel.
615 */
616 lockdep_off();
617
618 if (!prepare_report_consumer(&flags, &ai, other_info))
619 goto out;
620 /*
621 * Never report if value_change is FALSE, only when it is
622 * either TRUE or MAYBE. In case of MAYBE, further filtering may
623 * be done once we know the full stack trace in print_report().
624 */
625 if (value_change != KCSAN_VALUE_CHANGE_FALSE)
626 print_report(value_change, KCSAN_REPORT_RACE_SIGNAL, &ai, other_info);
627
628 release_report(&flags, other_info);
629out:
630 lockdep_on();
631 kcsan_enable_current();
658}632}
659 633
660void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type)634void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type)
661{635{
662 const struct access_info ai = prepare_access_info(ptr, size, access_type);636 const struct access_info ai = prepare_access_info(ptr, size, access_type);
637 unsigned long flags;
638
639 kcsan_disable_current();
640 lockdep_off(); /* See kcsan_report_known_origin(). */
641
642 raw_spin_lock_irqsave(&report_lock, flags);
643 print_report(KCSAN_VALUE_CHANGE_TRUE, KCSAN_REPORT_RACE_UNKNOWN_ORIGIN, &ai, NULL);
644 raw_spin_unlock_irqrestore(&report_lock, flags);
663 645
664 kcsan_report(&ai, KCSAN_VALUE_CHANGE_TRUE, KCSAN_REPORT_RACE_UNKNOWN_ORIGIN, NULL);646 lockdep_on();
647 kcsan_enable_current();
665}648}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t