Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp2707215pxv; Sun, 11 Jul 2021 23:21:23 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyA0Hu13QojH7M/uKkspGB8KX0wCMlhteEhlgh8VElUScuKunUOeYSFTvEIMIOQ5oPcq+na X-Received: by 2002:a92:d84a:: with SMTP id h10mr20616619ilq.55.1626070883375; Sun, 11 Jul 2021 23:21:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626070883; cv=none; d=google.com; s=arc-20160816; b=ywvN5gbNVPhQm3ZJUCQYMvv34tLgRFKkvZBssxR0eGgehft8KIrfH0/+MeLouYGOAp lLLUX8osU96/pkaL3XvKBEUbHxZvdW0KQ1X9iA9dIa1Mp+Y/GUfEfXPuAjE3JQUgUjHM Keux8Vh7kBhkvLygSdOM6VhWrXSfOjOogqwUR0dOoJQoL5oVBTLKcQkgczAZ0DZBlLJU MousVl9KfsghOVu9qsK9KulZnzWv74aY5IGtE58nlveZ++jOE+CiBemtmMFisFUHAzso UI2QZAmy+664v/oPTlhxMuI2J+flxOo9/OHO8XLF293yzxIZHXbMO+Ce+KKYhB1opQ6p twUw== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=d5W5jeYbqBv3wxvLlE1Af/jONUhuUc6ck5d/P0GALV0=; b=WaSAv7Krl+dKvO8M5EF4KdG8ICQxN0AhUpRNTKVv5+XjxhirJJgdjVqOrS4m79dpp8 WM/Vyf0EaAmP/SOw9JjGigrmvJx1oD1v1H+2GA6oncQM6pwfDp5ywTbBgef+RchxAV3M qx7rrYDdjvFhjgm8wytN8So/Rhu6ayfyYyQVM1ypIGrONw5OJ1Lfnnw6EOMfqTA1dnpH JGYnBzPYZaGbcucziUd2BZ6oU+/amSVoraqy5bnEToImZMnCrOy3jM9bjJUu+3fLG/PC UO/FMlkDLdkT3PRBtvOfUdjor9OlxSeutCI4VeQTRn20mTOLUt9qN0CML6AaZTGtFCsq 0yiA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=GGIcSksn; 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=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id p18si12343186jam.27.2021.07.11.23.21.11; Sun, 11 Jul 2021 23:21:23 -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=@linuxfoundation.org header.s=korg header.b=GGIcSksn; 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=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234582AbhGLGWg (ORCPT + 99 others); Mon, 12 Jul 2021 02:22:36 -0400 Received: from mail.kernel.org ([198.145.29.99]:39822 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233893AbhGLGVX (ORCPT ); Mon, 12 Jul 2021 02:21:23 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2866D61153; Mon, 12 Jul 2021 06:18:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1626070710; bh=yxV1JSp0byzG2cM2gN6t7X7YxV+FNspdBcRPK549JUU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GGIcSksnnQI4gzCLs0xvnvEEaOLe7ILCZWwjX+1f4tDUyB1lsJNMgL5EFBkjWZ4wp 8D3ElxHRVvDX4vKl/0PEII4RbQZOyiTTtvvTm5lCOqapQF28TjVuDmxJSjvq3xw0UV tDygmcfnLlIcmJxcSlcKqxM7zzGJ6dYEK68/boDE= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Johannes Berg , Boqun Feng , "Peter Zijlstra (Intel)" , Sasha Levin Subject: [PATCH 5.4 106/348] locking/lockdep: Fix the dep path printing for backwards BFS Date: Mon, 12 Jul 2021 08:08:10 +0200 Message-Id: <20210712060715.647697458@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210712060659.886176320@linuxfoundation.org> References: <20210712060659.886176320@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 7429f1571755..df43bf53e7c5 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1941,7 +1941,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, @@ -1969,6 +2018,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, @@ -2086,7 +2190,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