Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp995570yba; Thu, 4 Apr 2019 02:01:51 -0700 (PDT) X-Google-Smtp-Source: APXvYqzyssjcqPRCvYDjBwRP4ksEzTTcbg09294qAMotr9HcSmQliyS/CP3IC9J/YLeYC7X9osvo X-Received: by 2002:a17:902:9048:: with SMTP id w8mr5218631plz.195.1554368510911; Thu, 04 Apr 2019 02:01:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1554368510; cv=none; d=google.com; s=arc-20160816; b=wirmvlVzll1GdHNLrnwlKYVSi0efHRHA93n8jbyxEohFLaivTzVBNz+zBa5AwdJQrM Xl9hkUboFZjQ+52QA0MjBbj0Z1vuMUgS9WsSakbTG57lNdT5eNKLPqvmzvIT7oP482V0 SZAhSsElIylc1VrqHfIESGGMs5OqQttyXpgrXcssoCNV21d+OTX944vGiXFXSumZR5te XvwdC46W7EMozNAr/XjB50blsndSxZRF3ZUNyzjF8EioI2haklZp4v43DwAaBmqKOurY CoFMHvVJ7mH0NUQOEfajTRef3G9ALNuSbTDZDK/QCyH82khwO5JyEu5OOUUR1yl4vW9H cW+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=y6myB+riV/O1iT5WzB7+wk06UqZELbUgFSPfNGfWJyU=; b=Ic7cTp5LwZ9+c+fatD5DhRLSe6RbdXvyX+DDvJ6SmZnioJ0e8xilzN5vawQV0LFv8s k4yeWUJmCTEsxnsU2WZVqvCjD1t8VIo+h2rJAZbex9b/4PbvyN3RGu5kUKAkHCdefcaz 0UJ6Alr1gQlHWlNAPI7gb8nVmZNXyf8vbPAriMq59hAOhBx4lDeM5C8j4/f81XZwuNFX 4jX6V2H8AlbWWL0D/7D7nKyYrahFySjO+mwtAlORTwaD74eQQED8YO0bXjbaNFqpt2l/ E92Tmx6SpzFHcsD3jo8aYXWssFiKXEIEVg6XaP+8JnnVdpd1CqAqXX92g7s3iMFfL5ow t3ew== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=gT0DV+w0; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w11si16088929pge.187.2019.04.04.02.01.35; Thu, 04 Apr 2019 02:01:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=gT0DV+w0; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731100AbfDDJBB (ORCPT + 99 others); Thu, 4 Apr 2019 05:01:01 -0400 Received: from mail.kernel.org ([198.145.29.99]:37912 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730446AbfDDJA6 (ORCPT ); Thu, 4 Apr 2019 05:00:58 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C1BE021741; Thu, 4 Apr 2019 09:00:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1554368458; bh=4XIy8ausXwRG50qEb8o5OPx30PZNQa6C8LkBeUiYgds=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gT0DV+w0kIqthFB+xHTQK17lDYI5e4+24XFMvQMoo2dW/1gUfuNsepVhyMUk92yLi VYSvvPyfONqgvzOiwEDGDI4Id0NuQryJwSCqXAMgan7cDOFoHiN18boepkdOdEGPbf KcopX/WOfgQz+rQI8bjrN82VtMHzoKFoKcXXq0VU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dongdong Liu , "Rafael J. Wysocki" , Bjorn Helgaas , Sasha Levin Subject: [PATCH 4.19 047/187] PCI/PME: Fix hotplug/sysfs remove deadlock in pcie_pme_remove() Date: Thu, 4 Apr 2019 10:46:24 +0200 Message-Id: <20190404084605.281401256@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190404084603.119654039@linuxfoundation.org> References: <20190404084603.119654039@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.19-stable review patch. If anyone has any objections, please let me know. ------------------ [ Upstream commit 95c80bc6952b6a5badc7b702d23e5bf14d251e7c ] Dongdong reported a deadlock triggered by a hotplug event during a sysfs "remove" operation: pciehp 0000:00:0c.0:pcie004: Slot(0-1): Link Up # echo 1 > 0000:00:0c.0/remove PME and hotplug share an MSI/MSI-X vector. The sysfs "remove" side is: remove_store pci_stop_and_remove_bus_device_locked pci_lock_rescan_remove pci_stop_and_remove_bus_device ... pcie_pme_remove pcie_pme_suspend synchronize_irq # wait for hotplug IRQ handler pci_unlock_rescan_remove The hotplug side is: pciehp_ist pciehp_handle_presence_or_link_change pciehp_configure_device pci_lock_rescan_remove # wait for pci_unlock_rescan_remove() INFO: task bash:10913 blocked for more than 120 seconds. # ps -ax |grep D PID TTY STAT TIME COMMAND 10913 ttyAMA0 Ds+ 0:00 -bash 14022 ? D 0:00 [irq/745-pciehp] # cat /proc/14022/stack __switch_to+0x94/0xd8 pci_lock_rescan_remove+0x20/0x28 pciehp_configure_device+0x30/0x140 pciehp_handle_presence_or_link_change+0x324/0x458 pciehp_ist+0x1dc/0x1e0 # cat /proc/10913/stack __switch_to+0x94/0xd8 synchronize_irq+0x8c/0xc0 pcie_pme_suspend+0xa4/0x118 pcie_pme_remove+0x20/0x40 pcie_port_remove_service+0x3c/0x58 ... pcie_port_device_remove+0x2c/0x48 pcie_portdrv_remove+0x68/0x78 pci_device_remove+0x48/0x120 ... pci_stop_bus_device+0x84/0xc0 pci_stop_and_remove_bus_device_locked+0x24/0x40 remove_store+0xa4/0xb8 dev_attr_store+0x44/0x60 sysfs_kf_write+0x58/0x80 It is incorrect to call pcie_pme_suspend() from pcie_pme_remove() for two reasons. First, pcie_pme_suspend() calls synchronize_irq(), which will wait for the native hotplug interrupt handler as well as for the PME one, because they share one IRQ (as per the spec). That may deadlock if hotplug is signaled while pcie_pme_remove() is running and the latter calls pci_lock_rescan_remove() before the former. Second, if pcie_pme_suspend() figures out that wakeup needs to be enabled for the port, it will return without disabling the interrupt as expected by pcie_pme_remove() which was overlooked by commit c7b5a4e6e8fb ("PCI / PM: Fix native PME handling during system suspend/resume"). To fix that, rework pcie_pme_remove() to disable the PME interrupt, clear its status and prevent the PME worker function from re-enabling it before calling free_irq() on it, which should be sufficient. Fixes: c7b5a4e6e8fb ("PCI / PM: Fix native PME handling during system suspend/resume") Link: https://lore.kernel.org/linux-pci/c7697e7c-e1af-13e4-8491-0a3996e6ab5d@huawei.com Reported-by: Dongdong Liu Signed-off-by: Rafael J. Wysocki [bhelgaas: add URL and deadlock details from Dongdong] Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/pcie/pme.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 3ed67676ea2a..e85c5a8206c4 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -363,6 +363,16 @@ static bool pcie_pme_check_wakeup(struct pci_bus *bus) return false; } +static void pcie_pme_disable_interrupt(struct pci_dev *port, + struct pcie_pme_service_data *data) +{ + spin_lock_irq(&data->lock); + pcie_pme_interrupt_enable(port, false); + pcie_clear_root_pme_status(port); + data->noirq = true; + spin_unlock_irq(&data->lock); +} + /** * pcie_pme_suspend - Suspend PCIe PME service device. * @srv: PCIe service device to suspend. @@ -387,11 +397,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) return 0; } - spin_lock_irq(&data->lock); - pcie_pme_interrupt_enable(port, false); - pcie_clear_root_pme_status(port); - data->noirq = true; - spin_unlock_irq(&data->lock); + pcie_pme_disable_interrupt(port, data); synchronize_irq(srv->irq); @@ -427,9 +433,11 @@ static int pcie_pme_resume(struct pcie_device *srv) */ static void pcie_pme_remove(struct pcie_device *srv) { - pcie_pme_suspend(srv); + struct pcie_pme_service_data *data = get_service_data(srv); + + pcie_pme_disable_interrupt(srv->port, data); free_irq(srv->irq, srv); - kfree(get_service_data(srv)); + kfree(data); } static struct pcie_port_service_driver pcie_pme_driver = { -- 2.19.1