Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2735306pxj; Mon, 31 May 2021 09:24:56 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzF6gqyKMWodQaSWGucLZ2105rtuD7uk7i7VzrlFUa19nkkRzPBbxjGY7K2/4e/UL482rxU X-Received: by 2002:a92:cc43:: with SMTP id t3mr18773111ilq.250.1622478296282; Mon, 31 May 2021 09:24:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622478296; cv=none; d=google.com; s=arc-20160816; b=sfOjh/NW0XumrN29zUc6ZpG2+Za2AfRu8400lRqJtcCbBQKFgo1s4xOTHBs2Nnr7NX H1uYgihGRDWEher4lD8QKyCDV0Z9xDkBXw9fUdWgjQ+0c4/scabQEvCA/pIG1tIvzrqY o0lYK6U4v/xVckhYSUIIserXDZwnKPvdZ7Lw60aVfOHQ/mZ9djo0BqeK8AfgBmF6LxNy U5H6XfP/6a7fJDRjx5awCGnSwiyKnLlDTPCLyykKGFme4lY+pOPYfHXGdip5Z+0XeDRD rdUfu6D1CWK5g/3BSgIpD1ge6gKbUemJ8LPX3j2VSZEY2vJsgxH7PX/aQ/kZLkCmSBvN t0pw== 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=O6zGr+avTx/nnWYAbBK59tM1liTssDKhG0Y95ZX1phY=; b=IwohXuppjDl8ziKQXljkx+n2tsJtx3cSvjPf3bCYcT2TX978wxKURZ0K/eMvrrKlVB bXLAoTB3Gct/5EQqPdEoUxARFGBgFTKZO8uk/zPHFf2EmoYHAkjl66HfrU3ORJyZOIFb IhKSK1pPVKNgREWDkVAv7xlVxBCS0KvmJdwZiWAf218dq2OTq63nqVvBXakQFOWV5cLJ QC6qlJgK/sT8201O0D2zdA4EV3ETBzB+eKi7tkUD267Oj6GciclRviW0616dLwTMcrxT Aa0lAxscfHGy70i4JIIDTarcW5C8ISOPvq2itXuGdNL2oQi8EjS1p4aERZQ41LaPZS4v i4xQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=XJcChXDS; 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 b15si15879959jat.59.2021.05.31.09.24.43; Mon, 31 May 2021 09:24:56 -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=XJcChXDS; 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 S232515AbhEaQZh (ORCPT + 99 others); Mon, 31 May 2021 12:25:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:38022 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233319AbhEaOni (ORCPT ); Mon, 31 May 2021 10:43:38 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 446A161C75; Mon, 31 May 2021 13:54:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1622469281; bh=HCi1AXBOtmxa8GKjBhYrMrWk+dDUVRBScLcK/48cENE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XJcChXDSH6nLBqOA6LUjV0f85I/g5bsXhuxCTVmZEOKeYxDH60SMrZ92wI3bzUJE0 oISU58ZCK7gfr6+EDt9kVAAIGDdcOmO6TrAsMN0P0eY75u5DSyB5jDvb0x96LM0Fq5 Z6y5QzgUmdtxaqAv/oDeyTw4p28VRX3dD3NpvfOk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "chenxiang (M)" , Saravana Kannan , "Rafael J. Wysocki" Subject: [PATCH 5.12 094/296] drivers: base: Fix device link removal Date: Mon, 31 May 2021 15:12:29 +0200 Message-Id: <20210531130707.072584005@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210531130703.762129381@linuxfoundation.org> References: <20210531130703.762129381@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: Rafael J. Wysocki commit 80dd33cf72d1ab4f0af303f1fa242c6d6c8d328f upstream. When device_link_free() drops references to the supplier and consumer devices of the device link going away and the reference being dropped turns out to be the last one for any of those device objects, its ->release callback will be invoked and it may sleep which goes against the SRCU callback execution requirements. To address this issue, make the device link removal code carry out the device_link_free() actions preceded by SRCU synchronization from a separate work item (the "long" workqueue is used for that, because it does not matter when the device link memory is released and it may take time to get to that point) instead of using SRCU callbacks. While at it, make the code work analogously when SRCU is not enabled to reduce the differences between the SRCU and non-SRCU cases. Fixes: 843e600b8a2b ("driver core: Fix sleeping in invalid context during device link deletion") Cc: stable Reported-by: chenxiang (M) Tested-by: chenxiang (M) Reviewed-by: Saravana Kannan Signed-off-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/5722787.lOV4Wx5bFT@kreacher Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 37 +++++++++++++++++++++++-------------- include/linux/device.h | 6 ++---- 2 files changed, 25 insertions(+), 18 deletions(-) --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -192,6 +192,11 @@ int device_links_read_lock_held(void) { return srcu_read_lock_held(&device_links_srcu); } + +static void device_link_synchronize_removal(void) +{ + synchronize_srcu(&device_links_srcu); +} #else /* !CONFIG_SRCU */ static DECLARE_RWSEM(device_links_lock); @@ -222,6 +227,10 @@ int device_links_read_lock_held(void) return lockdep_is_held(&device_links_lock); } #endif + +static inline void device_link_synchronize_removal(void) +{ +} #endif /* !CONFIG_SRCU */ static bool device_is_ancestor(struct device *dev, struct device *target) @@ -443,8 +452,13 @@ static struct attribute *devlink_attrs[] }; ATTRIBUTE_GROUPS(devlink); -static void device_link_free(struct device_link *link) +static void device_link_release_fn(struct work_struct *work) { + struct device_link *link = container_of(work, struct device_link, rm_work); + + /* Ensure that all references to the link object have been dropped. */ + device_link_synchronize_removal(); + while (refcount_dec_not_one(&link->rpm_active)) pm_runtime_put(link->supplier); @@ -453,24 +467,19 @@ static void device_link_free(struct devi kfree(link); } -#ifdef CONFIG_SRCU -static void __device_link_free_srcu(struct rcu_head *rhead) -{ - device_link_free(container_of(rhead, struct device_link, rcu_head)); -} - static void devlink_dev_release(struct device *dev) { struct device_link *link = to_devlink(dev); - call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); -} -#else -static void devlink_dev_release(struct device *dev) -{ - device_link_free(to_devlink(dev)); + INIT_WORK(&link->rm_work, device_link_release_fn); + /* + * It may take a while to complete this work because of the SRCU + * synchronization in device_link_release_fn() and if the consumer or + * supplier devices get deleted when it runs, so put it into the "long" + * workqueue. + */ + queue_work(system_long_wq, &link->rm_work); } -#endif static struct class devlink_class = { .name = "devlink", --- a/include/linux/device.h +++ b/include/linux/device.h @@ -566,7 +566,7 @@ struct device { * @flags: Link flags. * @rpm_active: Whether or not the consumer device is runtime-PM-active. * @kref: Count repeated addition of the same link. - * @rcu_head: An RCU head to use for deferred execution of SRCU callbacks. + * @rm_work: Work structure used for removing the link. * @supplier_preactivated: Supplier has been made active before consumer probe. */ struct device_link { @@ -579,9 +579,7 @@ struct device_link { u32 flags; refcount_t rpm_active; struct kref kref; -#ifdef CONFIG_SRCU - struct rcu_head rcu_head; -#endif + struct work_struct rm_work; bool supplier_preactivated; /* Owned by consumer probe. */ };