Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp5965457imu; Tue, 13 Nov 2018 14:48:23 -0800 (PST) X-Google-Smtp-Source: AJdET5c9F4EZq9SCSn/y/jciMe8vn+dRM/uIuCvcQqPwyX8PGZ4IMWhhg2IWzl/oLSp6i+pAQUKH X-Received: by 2002:a63:3f44:: with SMTP id m65mr6636370pga.115.1542149303905; Tue, 13 Nov 2018 14:48:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1542149303; cv=none; d=google.com; s=arc-20160816; b=lc52Iv2LSyQGcNO0Q7NvxBa66AQOzgtS5xq2FNgloRbpx8JrUWYfFuFPbjsOx9RcIl UR8FydmfPFOLGFdSQr1OzBFORbNpaPOvXAcfMyMWGnupTbeWpz28T3Q3LmsRYyt836oz Bnu92fobP179GdNIyOy+wHtYGk4b3j2AMJ4dBYYqATNo0sYRTVibpq/Z0DldGT+XIp6B juctDXEWgpbcia2D1cRADWvZ82tMxxrUw84YtRFV9RpWL1Bj2THFQc9wwXPD116Y0nWH H1KK6xBSup6t47f9dkc7YQY+cg4uXTSzw+H47v1RUa9ZM4hM53pnbp47nOhQE/zoCtoA t5jA== 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 :message-id:date:subject:cc:to:from; bh=PToAdXhJqv7MbGL07QjBpl3qi5HN2ANrIm+mWgPTNnY=; b=IankPzv00tDQ3HtxY8/VGWgmE9JxBRlsMuA4RKIyx06thhnnHhb8Cmath5E0hp2cp4 y11JlZEGyrDmUoshJKt2q9RKMjrXOlLcm98traONWUpzYOKszedPxs5Fy1SU3K9dRqmN c/bg4XTuVj0lUU3MH50YkVjnrr21/ryGA5tdOTe5wjw6aDZXewvPrGfotwUQfyEjcny5 h0qOjcaDPVyqQ2loOMP3SuMtUVew3RK1KYtzEHkY9r/rMO2g2hO9INIAYC6gzsyoaoM+ 1mAVE96qe/UdJPr0tjWLTO+O7mqWILRYxF2D3zlcjWKagYAFHPShxUR0niPk5ajDkjQ4 9kqA== ARC-Authentication-Results: i=1; mx.google.com; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id be8-v6si21692230plb.143.2018.11.13.14.48.08; Tue, 13 Nov 2018 14:48:23 -0800 (PST) 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; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731566AbeKNIr1 (ORCPT + 99 others); Wed, 14 Nov 2018 03:47:27 -0500 Received: from mx1.redhat.com ([209.132.183.28]:38358 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726022AbeKNIr1 (ORCPT ); Wed, 14 Nov 2018 03:47:27 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6AF1285546; Tue, 13 Nov 2018 22:47:07 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 73E2E1001F59; Tue, 13 Nov 2018 22:47:01 +0000 (UTC) From: Lyude Paul To: dri-devel@lists.freedesktop.org Cc: Jerry Zuo , Harry Wentland , stable@vger.kernel.org, Maarten Lankhorst , Maxime Ripard , Sean Paul , David Airlie , linux-kernel@vger.kernel.org Subject: [PATCH] drm/dp_mst: Skip validating ports during destruction, just ref Date: Tue, 13 Nov 2018 17:46:14 -0500 Message-Id: <20181113224613.28809-1-lyude@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 13 Nov 2018 22:47:07 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Jerry Zuo pointed out a rather obscure hotplugging issue that it seems I accidentally introduced into DRM two years ago. Pretend we have a topology like this: |- DP-1: mst_primary |- DP-4: active display |- DP-5: disconnected |- DP-6: active hub |- DP-7: active display |- DP-8: disconnected |- DP-9: disconnected If we unplug DP-6, the topology starting at DP-7 will be destroyed but it's payloads will live on in DP-1's VCPI allocations and thus require removal. However, this removal currently fails because drm_dp_update_payload_part1() will (rightly so) try to validate the port before accessing it, fail then abort. If we keep going, eventually we run the MST hub out of bandwidth and all new allocations will start to fail (or in my case; all new displays just start flickering a ton). We could just teach drm_dp_update_payload_part1() not to drop the port ref in this case, but then we also need to teach drm_dp_destroy_payload_step1() to do the same thing, then hope no one ever adds anything to the that requires a validated port reference in drm_dp_destroy_connector_work(). Kind of sketchy. So let's go with a more clever solution: any port that drm_dp_destroy_connector_work() interacts with is guaranteed to still exist in memory until we say so. While said port might not be valid we don't really care: that's the whole reason we're destroying it in the first place! So, teach drm_dp_get_validated_port_ref() to use the all mighty current_work() function to avoid attempting to validate ports from the context of mgr->destroy_connector_work. I can't see any situation where this wouldn't be safe, and this avoids having to play whack-a-mole in the future of trying to work around port validation. Signed-off-by: Lyude Paul Fixes: 263efde31f97 ("drm/dp/mst: Get validated port ref in drm_dp_update_payload_part1()") Reported-by: Jerry Zuo Cc: Jerry Zuo Cc: Harry Wentland Cc: # v4.6+ --- drivers/gpu/drm/drm_dp_mst_topology.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 529414556962..08978ad72f33 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1023,9 +1023,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { struct drm_dp_mst_port *rport = NULL; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) - rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); + /* + * Port may or may not be 'valid' but we don't care about that when + * destroying the port and we are guaranteed that the port pointer + * will be valid until we've finished + */ + if (current_work() == &mgr->destroy_connector_work) { + kref_get(&port->kref); + rport = port; + } else if (mgr->mst_primary) { + rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, + port); + } mutex_unlock(&mgr->lock); return rport; } -- 2.19.1