Received: by 2002:a25:ef43:0:0:0:0:0 with SMTP id w3csp122870ybm; Tue, 26 May 2020 12:20:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJymCOi9jYy/3batvYqz73pGezQRWQCbwlt3IfSI1pKvw/r1wP+yTTf6rJAjS3uc9+4HZjwb X-Received: by 2002:a17:906:c7d1:: with SMTP id dc17mr2598276ejb.166.1590520830713; Tue, 26 May 2020 12:20:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1590520830; cv=none; d=google.com; s=arc-20160816; b=BkXVw9pIYLFVsFGhMXS/x+8FT/PHfgcdcPBShrTrqIni3Xs/1yClHfsa3v18FtRdGG FAd8MTI7Nf8RymaeAfTiC5pbmQYXwRf4gY92zG6Y2Flajp59cquffmk5PLYd55J4GpZW CW+7vZ7/xZDWXN0pIiL2W0YoYtDsGuvWAEAT14F3TnpmhXEZXDyAA57lRPnFtaGuik+T 6JdWaaSfqrfkSFva0mIUm1Z/D45ufTKhWKf4SjrJqQNxpAl13V5npNF5pZXlPlFfgpXq O0jVwJCgm7JeV4c6ulcWy3ZhoqmOKnSTbswq4kKfwQukpap3JBZfqNLXCxewTVesHJX+ /0Hw== 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=NYuH9JcxynGmNyfOvEkhbOnzbLBJ0Mymy4GIrOUtQKA=; b=QvNkWLnFlKyqIg51l/B92qyKRBSBLFnalAUn4ervf/4E7Zce+7dnfM+ShkKfJr5png T0oZvvi+1au6EA5Nxc7QK4Ubdq0ug+K9HvqxIDPfM6LUxy+7TLak6/BQ17TpuktHdVG7 ZSfBbFYKZeecj0t5Fg+x37AEH6oZDl3RDvcxNcX2a4raLe9pKTgJGvmTYpwgwdv166k6 2JIsYQBGeVaCmQswUOHqmOUX47rJdOzF/Hk+Xz7iszy/XndYWSWR0vfX572LzgcgxLVj thb5yqnGf5zS/xjuM/t8LpCZJbUkduz7NM2Dji5NypS1E/cOqXm7AE6QmUb6mqavw2uf TrRw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=I+9RhNuS; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id dn20si609809ejc.319.2020.05.26.12.20.06; Tue, 26 May 2020 12:20:30 -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=default header.b=I+9RhNuS; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392125AbgEZTOz (ORCPT + 99 others); Tue, 26 May 2020 15:14:55 -0400 Received: from mail.kernel.org ([198.145.29.99]:46064 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392218AbgEZTOv (ORCPT ); Tue, 26 May 2020 15:14:51 -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 588D9208A7; Tue, 26 May 2020 19:14:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1590520490; bh=W0NrlpBBLbhhjgg9G7Odx/xWAoRBKox2cXnYyWaIKGY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I+9RhNuSqPBIULSUug94rTx4a8+H4mwmEPcRm/+I0uZcw2nYALWhF/5dQWYj2gJR7 3OsQ+2C/VxuTUaufK5e9/G/w5HC9TVpYWIYWnIMZVSfN/Y0OixcwB4HUPkpCzk+LHT yGeDzMtGNd8PNJB37RmzX40gmLUwM2OCyCkwZTxg= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Saravana Kannan , "Rafael J. Wysocki" Subject: [PATCH 5.6 099/126] driver core: Fix SYNC_STATE_ONLY device link implementation Date: Tue, 26 May 2020 20:53:56 +0200 Message-Id: <20200526183946.089959904@linuxfoundation.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200526183937.471379031@linuxfoundation.org> References: <20200526183937.471379031@linuxfoundation.org> User-Agent: quilt/0.66 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 From: Saravana Kannan commit 21c27f06587d2c18150d27ca2382a509ec55c482 upstream. When SYNC_STATE_ONLY support was added in commit 05ef983e0d65 ("driver core: Add device link support for SYNC_STATE_ONLY flag"), device_link_add() incorrectly skipped adding the new SYNC_STATE_ONLY device link to the supplier's and consumer's "device link" list. This causes multiple issues: - The device link is lost forever from driver core if the caller didn't keep track of it (caller typically isn't expected to). This is a memory leak. - The device link is also never visible to any other code path after device_link_add() returns. If we fix the "device link" list handling, that exposes a bunch of issues. 1. The device link "status" state management code rightfully doesn't handle the case where a DL_FLAG_MANAGED device link exists between a supplier and consumer, but the consumer manages to probe successfully before the supplier. The addition of DL_FLAG_SYNC_STATE_ONLY links break this assumption. This causes device_links_driver_bound() to throw a warning when this happens. Since DL_FLAG_SYNC_STATE_ONLY device links are mainly used for creating proxy device links for child device dependencies and aren't useful once the consumer device probes successfully, this patch just deletes DL_FLAG_SYNC_STATE_ONLY device links once its consumer device probes. This way, we avoid the warning, free up some memory and avoid complicating the device links "status" state management code. 2. Creating a DL_FLAG_STATELESS device link between two devices that already have a DL_FLAG_SYNC_STATE_ONLY device link will result in the DL_FLAG_STATELESS flag not getting set correctly. This patch also fixes this. Lastly, this patch also fixes minor whitespace issues. Cc: stable@vger.kernel.org Fixes: 05ef983e0d65 ("driver core: Add device link support for SYNC_STATE_ONLY flag") Signed-off-by: Saravana Kannan Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20200519063000.128819-1-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 61 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 22 deletions(-) --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -360,13 +360,12 @@ struct device_link *device_link_add(stru if (flags & DL_FLAG_STATELESS) { kref_get(&link->kref); + link->flags |= DL_FLAG_STATELESS; if (link->flags & DL_FLAG_SYNC_STATE_ONLY && - !(link->flags & DL_FLAG_STATELESS)) { - link->flags |= DL_FLAG_STATELESS; + !(link->flags & DL_FLAG_STATELESS)) goto reorder; - } else { + else goto out; - } } /* @@ -433,12 +432,16 @@ struct device_link *device_link_add(stru flags & DL_FLAG_PM_RUNTIME) pm_runtime_resume(supplier); + list_add_tail_rcu(&link->s_node, &supplier->links.consumers); + list_add_tail_rcu(&link->c_node, &consumer->links.suppliers); + if (flags & DL_FLAG_SYNC_STATE_ONLY) { dev_dbg(consumer, "Linked as a sync state only consumer to %s\n", dev_name(supplier)); goto out; } + reorder: /* * Move the consumer and all of the devices depending on it to the end @@ -449,12 +452,9 @@ reorder: */ device_reorder_to_tail(consumer, NULL); - list_add_tail_rcu(&link->s_node, &supplier->links.consumers); - list_add_tail_rcu(&link->c_node, &consumer->links.suppliers); - dev_dbg(consumer, "Linked as a consumer to %s\n", dev_name(supplier)); - out: +out: device_pm_unlock(); device_links_write_unlock(); @@ -829,6 +829,13 @@ static void __device_links_supplier_defe list_add_tail(&sup->links.defer_sync, &deferred_sync); } +static void device_link_drop_managed(struct device_link *link) +{ + link->flags &= ~DL_FLAG_MANAGED; + WRITE_ONCE(link->status, DL_STATE_NONE); + kref_put(&link->kref, __device_link_del); +} + /** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. @@ -842,7 +849,7 @@ static void __device_links_supplier_defe */ void device_links_driver_bound(struct device *dev) { - struct device_link *link; + struct device_link *link, *ln; LIST_HEAD(sync_list); /* @@ -882,18 +889,35 @@ void device_links_driver_bound(struct de else __device_links_queue_sync_state(dev, &sync_list); - list_for_each_entry(link, &dev->links.suppliers, c_node) { + list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) { + struct device *supplier; + if (!(link->flags & DL_FLAG_MANAGED)) continue; - WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); - WRITE_ONCE(link->status, DL_STATE_ACTIVE); + supplier = link->supplier; + if (link->flags & DL_FLAG_SYNC_STATE_ONLY) { + /* + * When DL_FLAG_SYNC_STATE_ONLY is set, it means no + * other DL_MANAGED_LINK_FLAGS have been set. So, it's + * save to drop the managed link completely. + */ + device_link_drop_managed(link); + } else { + WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); + WRITE_ONCE(link->status, DL_STATE_ACTIVE); + } + /* + * This needs to be done even for the deleted + * DL_FLAG_SYNC_STATE_ONLY device link in case it was the last + * device link that was preventing the supplier from getting a + * sync_state() call. + */ if (defer_sync_state_count) - __device_links_supplier_defer_sync(link->supplier); + __device_links_supplier_defer_sync(supplier); else - __device_links_queue_sync_state(link->supplier, - &sync_list); + __device_links_queue_sync_state(supplier, &sync_list); } dev->links.status = DL_DEV_DRIVER_BOUND; @@ -903,13 +927,6 @@ void device_links_driver_bound(struct de device_links_flush_sync_list(&sync_list, dev); } -static void device_link_drop_managed(struct device_link *link) -{ - link->flags &= ~DL_FLAG_MANAGED; - WRITE_ONCE(link->status, DL_STATE_NONE); - kref_put(&link->kref, __device_link_del); -} - /** * __device_links_no_driver - Update links of a device without a driver. * @dev: Device without a drvier.