From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.linuxfoundation.org ([140.211.169.12]:36795 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932790AbcHHTVM (ORCPT ); Mon, 8 Aug 2016 15:21:12 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Alexander Shishkin Subject: [PATCH 4.6 94/96] intel_th: Fix a deadlock in modprobing Date: Mon, 8 Aug 2016 21:11:57 +0200 Message-Id: <20160808180248.028783147@linuxfoundation.org> In-Reply-To: <20160808180243.898163389@linuxfoundation.org> References: <20160808180243.898163389@linuxfoundation.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: stable-owner@vger.kernel.org List-ID: 4.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Alexander Shishkin commit a36aa80f3cb2540fb1dbad6240852de4365a2e82 upstream. Driver initialization tries to request a hub (GTH) driver module from its probe callback, resulting in a deadlock. This patch solves the problem by adding a deferred work for requesting the hub module. Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/core.c | 35 +++++++++++++++++++++++++++++++++- drivers/hwtracing/intel_th/intel_th.h | 3 ++ 2 files changed, 37 insertions(+), 1 deletion(-) --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -440,6 +440,38 @@ static struct intel_th_subdevice { }, }; +#ifdef CONFIG_MODULES +static void __intel_th_request_hub_module(struct work_struct *work) +{ + struct intel_th *th = container_of(work, struct intel_th, + request_module_work); + + request_module("intel_th_%s", th->hub->name); +} + +static int intel_th_request_hub_module(struct intel_th *th) +{ + INIT_WORK(&th->request_module_work, __intel_th_request_hub_module); + schedule_work(&th->request_module_work); + + return 0; +} + +static void intel_th_request_hub_module_flush(struct intel_th *th) +{ + flush_work(&th->request_module_work); +} +#else +static inline int intel_th_request_hub_module(struct intel_th *th) +{ + return -EINVAL; +} + +static inline void intel_th_request_hub_module_flush(struct intel_th *th) +{ +} +#endif /* CONFIG_MODULES */ + static int intel_th_populate(struct intel_th *th, struct resource *devres, unsigned int ndevres, int irq) { @@ -510,7 +542,7 @@ static int intel_th_populate(struct inte /* need switch driver to be loaded to enumerate the rest */ if (subdev->type == INTEL_TH_SWITCH && !req) { th->hub = thdev; - err = request_module("intel_th_%s", subdev->name); + err = intel_th_request_hub_module(th); if (!err) req++; } @@ -627,6 +659,7 @@ void intel_th_free(struct intel_th *th) { int i; + intel_th_request_hub_module_flush(th); for (i = 0; i < TH_SUBDEVICE_MAX; i++) if (th->thdev[i] != th->hub) intel_th_device_remove(th->thdev[i]); --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -199,6 +199,9 @@ struct intel_th { int id; int major; +#ifdef CONFIG_MODULES + struct work_struct request_module_work; +#endif /* CONFIG_MODULES */ #ifdef CONFIG_INTEL_TH_DEBUG struct dentry *dbg; #endif