Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bus: arm-ccn: Move event cleanup routine

The function cleaning up an initialized event
was called from the "event_del" handler, instead
of being used as the "destroy" callback. In case of
events group allocation this caused NULL pointer
dereference (as events are added and deleted
multiple times then). Fixed now.

Signed-off-by: Pawel Moll <mail@pawelmoll.com>
Signed-off-by: Kevin Hilman <khilman@linaro.org>

authored by

Pawel Moll and committed by
Kevin Hilman
8fb22264 95f6e814

+25 -26
+25 -26
drivers/bus/arm-ccn.c
··· 586 586 return 0; 587 587 } 588 588 589 + static void arm_ccn_pmu_event_destroy(struct perf_event *event) 590 + { 591 + struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); 592 + struct hw_perf_event *hw = &event->hw; 593 + 594 + if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) { 595 + clear_bit(CCN_IDX_PMU_CYCLE_COUNTER, ccn->dt.pmu_counters_mask); 596 + } else { 597 + struct arm_ccn_component *source = 598 + ccn->dt.pmu_counters[hw->idx].source; 599 + 600 + if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP && 601 + CCN_CONFIG_EVENT(event->attr.config) == 602 + CCN_EVENT_WATCHPOINT) 603 + clear_bit(hw->config_base, source->xp.dt_cmp_mask); 604 + else 605 + clear_bit(hw->config_base, source->pmu_events_mask); 606 + clear_bit(hw->idx, ccn->dt.pmu_counters_mask); 607 + } 608 + 609 + ccn->dt.pmu_counters[hw->idx].source = NULL; 610 + ccn->dt.pmu_counters[hw->idx].event = NULL; 611 + } 612 + 589 613 static int arm_ccn_pmu_event_init(struct perf_event *event) 590 614 { 591 615 struct arm_ccn *ccn; ··· 623 599 return -ENOENT; 624 600 625 601 ccn = pmu_to_arm_ccn(event->pmu); 602 + event->destroy = arm_ccn_pmu_event_destroy; 626 603 627 604 if (hw->sample_period) { 628 605 dev_warn(ccn->dev, "Sampling not supported!\n"); ··· 754 729 ccn->dt.pmu_counters[hw->idx].event = event; 755 730 756 731 return 0; 757 - } 758 - 759 - static void arm_ccn_pmu_event_free(struct perf_event *event) 760 - { 761 - struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); 762 - struct hw_perf_event *hw = &event->hw; 763 - 764 - if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) { 765 - clear_bit(CCN_IDX_PMU_CYCLE_COUNTER, ccn->dt.pmu_counters_mask); 766 - } else { 767 - struct arm_ccn_component *source = 768 - ccn->dt.pmu_counters[hw->idx].source; 769 - 770 - if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP && 771 - CCN_CONFIG_EVENT(event->attr.config) == 772 - CCN_EVENT_WATCHPOINT) 773 - clear_bit(hw->config_base, source->xp.dt_cmp_mask); 774 - else 775 - clear_bit(hw->config_base, source->pmu_events_mask); 776 - clear_bit(hw->idx, ccn->dt.pmu_counters_mask); 777 - } 778 - 779 - ccn->dt.pmu_counters[hw->idx].source = NULL; 780 - ccn->dt.pmu_counters[hw->idx].event = NULL; 781 732 } 782 733 783 734 static u64 arm_ccn_pmu_read_counter(struct arm_ccn *ccn, int idx) ··· 1028 1027 static void arm_ccn_pmu_event_del(struct perf_event *event, int flags) 1029 1028 { 1030 1029 arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE); 1031 - 1032 - arm_ccn_pmu_event_free(event); 1033 1030 } 1034 1031 1035 1032 static void arm_ccn_pmu_event_read(struct perf_event *event)