[PATCH v2 2/2] perf/dwc_pcie: Skip sibling walks for new group leaders

Zhanpeng Zhang <[email protected]>
Newsgroups org.kernel.vger.linux-perf-users,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
for_each_sibling_event() requires the event context lock to be held.
perf_try_init_event() only takes that lock when initializing a group
member.
The DWC PCIe PMU walks the sibling list twice for every event, including a
new group leader whose event_init() method runs without the lock. Although
the leader cannot have siblings yet, the lock assertion is evaluated before
the empty list is walked and produces two lockdep warnings.

Skip both sibling walks while initializing a group leader. Group member
validation is unchanged and continues to run with the event context mutex
held.

Fixes: af9597adc2f1 ("drivers/perf: add DesignWare PCIe PMU driver")
Signed-off-by: Zhanpeng Zhang <[email protected]>
---
A system-wide DWC PCIe PMU perf stat completed successfully with the same
debug configuration, without lockdep reports or kernel taint.

 drivers/perf/dwc_pcie_pmu.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c
index 7b2e28aade73..a6667ac19a99 100644
--- a/drivers/perf/dwc_pcie_pmu.c
+++ b/drivers/perf/dwc_pcie_pmu.c
@@ -417,6 +417,10 @@ static int dwc_pcie_pmu_validate_group(struct perf_event *event)
 		if (dwc_pcie_pmu_validate_add_lane_event(leader, val_lane_events))
 			return -ENOSPC;
 
+	/* A new group leader cannot have any siblings yet. */
+	if (event == leader)
+		return 0;
+
 	for_each_sibling_event(sibling, leader) {
 		type = DWC_PCIE_EVENT_TYPE(sibling);
 		if (type == DWC_PCIE_TIME_BASE_EVENT) {
@@ -452,9 +456,11 @@ static int dwc_pcie_pmu_event_init(struct perf_event *event)
 	if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK)
 		return -EINVAL;
 
-	for_each_sibling_event(sibling, event->group_leader) {
-		if (sibling->pmu != event->pmu && !is_software_event(sibling))
-			return -EINVAL;
+	if (event != event->group_leader) {
+		for_each_sibling_event(sibling, event->group_leader) {
+			if (sibling->pmu != event->pmu && !is_software_event(sibling))
+				return -EINVAL;
+		}
 	}
 
 	if (type < 0 || type >= DWC_PCIE_EVENT_TYPE_MAX)
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.