From patchwork Tue Aug 7 16:10:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Liu X-Patchwork-Id: 1286861 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id A3712DF280 for ; Tue, 7 Aug 2012 16:22:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755664Ab2HGQUo (ORCPT ); Tue, 7 Aug 2012 12:20:44 -0400 Received: from mail-gh0-f174.google.com ([209.85.160.174]:58061 "EHLO mail-gh0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755666Ab2HGQUm (ORCPT ); Tue, 7 Aug 2012 12:20:42 -0400 Received: by mail-gh0-f174.google.com with SMTP id r11so3858495ghr.19 for ; Tue, 07 Aug 2012 09:20:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=FM6mVhIVzlWNAMYSONH0rono5YTVEdO2KVa2Wyuo+78=; b=zeZgpsJG8llqU5zcsoZ4VP5tq2q4xaLvBSJiNuNdzzDq3xSrZn98dFAOQmHTuWS6a4 pZ6O+09Gw7f56W4SUoQwvYLwXwFlZWAMpB2b2qmiHbrSWl4AliGZD9w5NYRSRJNZMpmx vkF0qhHxvLwBDJOc/PFpCy2WkwaZW9QIfbeSYZ+Sy+OnAjhV2pbfQcCCgxdja2uaDvJ/ Pz/8s2qOyWIy5gIhn9TMSBk4rXX1oROEswa9HGRS3xbPaJmogjbCTj3ZKLZucketUQlE Hw6PAo2G2Xm24gCRDAL1UbHJi05trMs887KvErzi0p4uNEkojcLFVd7e+WZcZCtBZKMZ HLNw== Received: by 10.68.241.65 with SMTP id wg1mr29209994pbc.25.1344356441920; Tue, 07 Aug 2012 09:20:41 -0700 (PDT) Received: from localhost.localdomain ([58.250.81.2]) by mx.google.com with ESMTPS id pt2sm11429362pbb.58.2012.08.07.09.20.32 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 07 Aug 2012 09:20:40 -0700 (PDT) From: Jiang Liu To: Bjorn Helgaas , Don Dutile , Yinghai Lu , Greg KH , Kenji Kaneshige Cc: Jiang Liu , Taku Izumi , "Rafael J . Wysocki" , Yijing Wang , Xinwei Hu , linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Jiang Liu Subject: [RFC PATCH v1 14/22] PCI/sysfs: use PCI bus lock to avoid race conditions Date: Wed, 8 Aug 2012 00:10:54 +0800 Message-Id: <1344355862-2726-15-git-send-email-jiang.liu@huawei.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1344355862-2726-1-git-send-email-jiang.liu@huawei.com> References: <1344355862-2726-1-git-send-email-jiang.liu@huawei.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org This patch uses PCI bus lock mechanism to avoid race conditions when doing PCI device/host bridge hotplug through PCI sysfs interfaces. Signed-off-by: Jiang Liu --- drivers/pci/pci-sysfs.c | 26 +++++++++++++++++++++----- drivers/pci/probe.c | 17 +++++++++++------ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 99fefbe..11043b4 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -298,7 +298,10 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, pci_host_bridge_hotplug_lock(); mutex_lock(&pci_remove_rescan_mutex); while ((b = pci_find_next_bus(b)) != NULL) - pci_rescan_bus(b); + if (pci_bus_lock_states(b, PCI_BUS_STATE_WORKING) > 0) { + pci_rescan_bus(b); + pci_bus_unlock(b); + } mutex_unlock(&pci_remove_rescan_mutex); pci_host_bridge_hotplug_unlock(); } @@ -321,8 +324,14 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, return -EINVAL; if (val) { + struct pci_bus *bus = pdev->bus; + mutex_lock(&pci_remove_rescan_mutex); - pci_rescan_bus(pdev->bus); + if (pci_bus_lock_states(bus, PCI_BUS_STATE_WORKING) > 0) { + if (pdev->is_added) + pci_rescan_bus(bus); + pci_bus_unlock(bus); + } mutex_unlock(&pci_remove_rescan_mutex); } return count; @@ -331,9 +340,14 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, static void remove_callback(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *bus = pdev->bus; mutex_lock(&pci_remove_rescan_mutex); - pci_stop_and_remove_bus_device(pdev); + if (pci_bus_lock_states(bus, PCI_BUS_STATE_WORKING) > 0) { + pci_bus_get(bus); + pci_stop_and_remove_bus_device(pdev); + pci_unlock_and_put_bus(bus); + } mutex_unlock(&pci_remove_rescan_mutex); } @@ -369,10 +383,12 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, if (val) { mutex_lock(&pci_remove_rescan_mutex); - if (!pci_is_root_bus(bus) && list_empty(&bus->devices)) + if (!pci_is_root_bus(bus)) pci_rescan_bus_bridge_resize(bus->self); - else + else if (pci_bus_lock_states(bus, PCI_BUS_STATE_WORKING) > 0) { pci_rescan_bus(bus); + pci_bus_unlock(bus); + } mutex_unlock(&pci_remove_rescan_mutex); } return count; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 47bf071..da6f04c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1919,12 +1919,17 @@ EXPORT_SYMBOL(pci_scan_bus); unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) { unsigned int max = -1; - struct pci_bus *bus = bridge->subordinate; - - if (pci_bus_lock_states(bus, PCI_BUS_STATE_WORKING) > 0) { - max = pci_scan_child_bus(bus); - pci_assign_unassigned_bridge_resources(bridge); - pci_bus_add_devices(bus); + struct pci_bus *bus; + + bus = pci_lock_subordinate(bridge, PCI_BUS_STATE_WORKING); + if (bus) { + if (list_empty(&bus->devices)) { + max = pci_scan_child_bus(bus); + pci_assign_unassigned_bridge_resources(bridge); + pci_bus_add_devices(bus); + } else { + pci_rescan_bus(bus); + } pci_bus_unlock(bus); }