Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp3346456pxv; Sun, 4 Jul 2021 16:11:07 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyOL4oa/Vi15FK8JKl2sjorPD4MGhGWaviRHfSnl9RXs0Xofqpi0ytNMjZ4Lkm7Sfc9p4rf X-Received: by 2002:a17:906:f283:: with SMTP id gu3mr10496449ejb.415.1625440267290; Sun, 04 Jul 2021 16:11:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625440267; cv=none; d=google.com; s=arc-20160816; b=xReyHaRIbIlI+AMRt4mZbwLOKZip9rD9ha1gSjFTIvnshiMETMb5NYvQ1QK2wAYM2K q8Lr6M7zcsLU21Vl8a5yfH1dIR5tIPyEwT31YKLNBjofk/xonB89uc2MEwXkV+2MoB6F dZQ35PEL7NB/a74HQddeAXom+OGXnHS6LVR/4zlcsgvKcP06MIVru0hTOXgbRwPW73cE fAb/+P/5P8cp+07bZLtRn5JZBd3ZKYkn/pwDhbq8gMt4wNsyKe9eRrnESPeN4TUzv1Kq Jn9UAUeMrCjOV66iMpa0D5YrYlEhbuQq8K8NarpXbSte/hHs3kZGd2ZVB64KUXuJ0iSV kxtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ZkKg2UMnfY26OIyMsSZJ7cCO3r5Xkqc/gyqoXDt9CNo=; b=mHNJ+TgeEZCJRZa5s++YOOYQ8P0Yh1iqGArfuYEVQh6aSYB/M/WiIYz3KmMKpWNbVT 9kq7RiQi4dV8Hy9mafy7UdmYBV2l4LGVeJzzmbmsGG5P3UMwUpe+6TaQwG1vRT7t4GLv y2MvwAnsOiM7dMB7OtipePCsytpPt4x99nh96oC6C9Uxa+djILLNzWI6TAIMRTT2Lnxe 8i1ztZEqwJJhsG/76Q32nPfwSYDmnga48/mo25yKoJLiv/YtjmRl40nPNQc62+4zWOaB 5+RlLp416rFrLE7z7Y4iiumu1MgWy0pqeNnspu/Y7uKO3L3x4OUBkr0VajwOOuBU/vNl bBuw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=OPraroY0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id nd17si10331915ejc.732.2021.07.04.16.10.43; Sun, 04 Jul 2021 16:11:07 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=OPraroY0; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229997AbhGDXM0 (ORCPT + 99 others); Sun, 4 Jul 2021 19:12:26 -0400 Received: from mail.kernel.org ([198.145.29.99]:48966 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232370AbhGDXKi (ORCPT ); Sun, 4 Jul 2021 19:10:38 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id B52AE61945; Sun, 4 Jul 2021 23:07:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1625440076; bh=wsL/YfWprzMGoybO37okOD27mLT9ca9B+wvgXxhmKbo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OPraroY0aK8dlyZuEsSdpjguY5Vp4gSlvf+rKNecNq48WkPJhmSw9ZHrlRz8J8q6E 6RkBmosbbPpqhMNCEt6gnVlhHai+/Bhwvh0N3kBcfzfFcE5W8kZONjYcjBdsJTdAnw HDckRKwP8Jlz7xvF4ejncWUc6YF+IrvKCfV+g0JCaXcpc4SoybRe+z74xV6Rp2c5QG pqHoqZ7wIoytMDdBQ2kqyMxa92hQIGPuMbm3hK+guLweBHPIkBoRMQRVE/Q23rzI1m ZOJg0lkD2y+4bBmAs0aPFG8kzk8N30QQc3Ra46YCz/uNZlIlZWWNylHV7oQdwHs/CB tm2fK/ApaIJ0g== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Boqun Feng , Johannes Berg , Peter Zijlstra , Sasha Levin Subject: [PATCH AUTOSEL 5.12 75/80] locking/lockdep: Fix the dep path printing for backwards BFS Date: Sun, 4 Jul 2021 19:06:11 -0400 Message-Id: <20210704230616.1489200-75-sashal@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210704230616.1489200-1-sashal@kernel.org> References: <20210704230616.1489200-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Boqun Feng [ Upstream commit 69c7a5fb2482636f525f016c8333fdb9111ecb9d ] We use the same code to print backwards lock dependency path as the forwards lock dependency path, and this could result into incorrect printing because for a backwards lock_list ->trace is not the call trace where the lock of ->class is acquired. Fix this by introducing a separate function on printing the backwards dependency path. Also add a few comments about the printing while we are at it. Reported-by: Johannes Berg Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20210618170110.3699115-2-boqun.feng@gmail.com Signed-off-by: Sasha Levin --- kernel/locking/lockdep.c | 108 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index f39c383c7180..7bd1d9ba6dc0 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -2303,7 +2303,56 @@ static void print_lock_class_header(struct lock_class *class, int depth) } /* - * printk the shortest lock dependencies from @start to @end in reverse order: + * Dependency path printing: + * + * After BFS we get a lock dependency path (linked via ->parent of lock_list), + * printing out each lock in the dependency path will help on understanding how + * the deadlock could happen. Here are some details about dependency path + * printing: + * + * 1) A lock_list can be either forwards or backwards for a lock dependency, + * for a lock dependency A -> B, there are two lock_lists: + * + * a) lock_list in the ->locks_after list of A, whose ->class is B and + * ->links_to is A. In this case, we can say the lock_list is + * "A -> B" (forwards case). + * + * b) lock_list in the ->locks_before list of B, whose ->class is A + * and ->links_to is B. In this case, we can say the lock_list is + * "B <- A" (bacwards case). + * + * The ->trace of both a) and b) point to the call trace where B was + * acquired with A held. + * + * 2) A "helper" lock_list is introduced during BFS, this lock_list doesn't + * represent a certain lock dependency, it only provides an initial entry + * for BFS. For example, BFS may introduce a "helper" lock_list whose + * ->class is A, as a result BFS will search all dependencies starting with + * A, e.g. A -> B or A -> C. + * + * The notation of a forwards helper lock_list is like "-> A", which means + * we should search the forwards dependencies starting with "A", e.g A -> B + * or A -> C. + * + * The notation of a bacwards helper lock_list is like "<- B", which means + * we should search the backwards dependencies ending with "B", e.g. + * B <- A or B <- C. + */ + +/* + * printk the shortest lock dependencies from @root to @leaf in reverse order. + * + * We have a lock dependency path as follow: + * + * @root @leaf + * | | + * V V + * ->parent ->parent + * | lock_list | <--------- | lock_list | ... | lock_list | <--------- | lock_list | + * | -> L1 | | L1 -> L2 | ... |Ln-2 -> Ln-1| | Ln-1 -> Ln| + * + * , so it's natural that we start from @leaf and print every ->class and + * ->trace until we reach the @root. */ static void __used print_shortest_lock_dependencies(struct lock_list *leaf, @@ -2331,6 +2380,61 @@ print_shortest_lock_dependencies(struct lock_list *leaf, } while (entry && (depth >= 0)); } +/* + * printk the shortest lock dependencies from @leaf to @root. + * + * We have a lock dependency path (from a backwards search) as follow: + * + * @leaf @root + * | | + * V V + * ->parent ->parent + * | lock_list | ---------> | lock_list | ... | lock_list | ---------> | lock_list | + * | L2 <- L1 | | L3 <- L2 | ... | Ln <- Ln-1 | | <- Ln | + * + * , so when we iterate from @leaf to @root, we actually print the lock + * dependency path L1 -> L2 -> .. -> Ln in the non-reverse order. + * + * Another thing to notice here is that ->class of L2 <- L1 is L1, while the + * ->trace of L2 <- L1 is the call trace of L2, in fact we don't have the call + * trace of L1 in the dependency path, which is alright, because most of the + * time we can figure out where L1 is held from the call trace of L2. + */ +static void __used +print_shortest_lock_dependencies_backwards(struct lock_list *leaf, + struct lock_list *root) +{ + struct lock_list *entry = leaf; + const struct lock_trace *trace = NULL; + int depth; + + /*compute depth from generated tree by BFS*/ + depth = get_lock_depth(leaf); + + do { + print_lock_class_header(entry->class, depth); + if (trace) { + printk("%*s ... acquired at:\n", depth, ""); + print_lock_trace(trace, 2); + printk("\n"); + } + + /* + * Record the pointer to the trace for the next lock_list + * entry, see the comments for the function. + */ + trace = entry->trace; + + if (depth == 0 && (entry != root)) { + printk("lockdep:%s bad path found in chain graph\n", __func__); + break; + } + + entry = get_lock_parent(entry); + depth--; + } while (entry && (depth >= 0)); +} + static void print_irq_lock_scenario(struct lock_list *safe_entry, struct lock_list *unsafe_entry, @@ -2448,7 +2552,7 @@ print_bad_irq_dependency(struct task_struct *curr, prev_root->trace = save_trace(); if (!prev_root->trace) return; - print_shortest_lock_dependencies(backwards_entry, prev_root); + print_shortest_lock_dependencies_backwards(backwards_entry, prev_root); pr_warn("\nthe dependencies between the lock to be acquired"); pr_warn(" and %s-irq-unsafe lock:\n", irqclass); -- 2.30.2