Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932737AbcCHJuo (ORCPT ); Tue, 8 Mar 2016 04:50:44 -0500 Received: from hqemgate15.nvidia.com ([216.228.121.64]:8068 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932210AbcCHJul (ORCPT ); Tue, 8 Mar 2016 04:50:41 -0500 X-PGP-Universal: processed; by hqnvupgp07.nvidia.com on Tue, 08 Mar 2016 01:49:21 -0800 Subject: Re: [PATCH] spi: core: Fix deadlock when sending messages To: Mark Brown References: <1457430543-15179-1-git-send-email-jonathanh@nvidia.com> CC: , , , From: Jon Hunter Message-ID: <56DEA067.8040301@nvidia.com> Date: Tue, 8 Mar 2016 09:50:31 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.5.1 MIME-Version: 1.0 In-Reply-To: <1457430543-15179-1-git-send-email-jonathanh@nvidia.com> X-Originating-IP: [10.26.11.193] X-ClientProxiedBy: UKMAIL101.nvidia.com (10.26.138.13) To UKMAIL101.nvidia.com (10.26.138.13) Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4337 Lines: 119 Adding Vignesh ... On 08/03/16 09:49, Jon Hunter wrote: > The function __spi_pump_messages() is called by spi_pump_messages() and > __spi_sync(). The function __spi_sync() has an argument 'bus_locked' > that indicates if it is called with the SPI bus mutex held or not. If > 'bus_locked' is false then __spi_sync() will acquire the mutex itself. > > Commit 556351f14e74 ("spi: introduce accelerated read support for spi > flash devices") made a change to acquire the SPI bus mutex within > __spi_pump_messages(). However, this change did not check to see if the > mutex is already held. If __spi_sync() is called with the mutex held > (ie. 'bus_locked' is true), then a deadlock occurs when > __spi_pump_messages() is called. > > Fix this deadlock by passing the 'bus_locked' state from __spi_sync() to > __spi_pump_messages() and only acquire the mutex if not already held. In > the case where __spi_pump_messages() is called from spi_pump_messages() > it is assumed that the mutex is not held and so call > __spi_pump_messages() with 'bus_locked' set to false. Finally, move the > unlocking of the mutex to the end of the __spi_pump_messages() function > to simplify the code and only call cond_resched() if there are no > errors. > > Fixes: 556351f14e74 ("spi: introduce accelerated read support for spi flash devices") > > Signed-off-by: Jon Hunter > --- > > This deadlock is seen on the Tegra124 Nyan Big chromebook and prevents > the board from booting -next. > > drivers/spi/spi.c | 28 ++++++++++++++++------------ > 1 file changed, 16 insertions(+), 12 deletions(-) > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c > index fe0196328aa0..e699fec9ddc5 100644 > --- a/drivers/spi/spi.c > +++ b/drivers/spi/spi.c > @@ -1062,7 +1062,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); > * inside spi_sync(); the queue extraction handling at the top of the > * function should deal with this safely. > */ > -static void __spi_pump_messages(struct spi_master *master, bool in_kthread) > +static void __spi_pump_messages(struct spi_master *master, bool in_kthread, > + bool bus_locked) > { > unsigned long flags; > bool was_busy = false; > @@ -1158,7 +1159,9 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) > } > } > > - mutex_lock(&master->bus_lock_mutex); > + if (!bus_locked) > + mutex_lock(&master->bus_lock_mutex); > + > trace_spi_message_start(master->cur_msg); > > if (master->prepare_message) { > @@ -1168,8 +1171,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) > "failed to prepare message: %d\n", ret); > master->cur_msg->status = ret; > spi_finalize_current_message(master); > - mutex_unlock(&master->bus_lock_mutex); > - return; > + goto out; > } > master->cur_msg_prepared = true; > } > @@ -1178,21 +1180,23 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) > if (ret) { > master->cur_msg->status = ret; > spi_finalize_current_message(master); > - mutex_unlock(&master->bus_lock_mutex); > - return; > + goto out; > } > > ret = master->transfer_one_message(master, master->cur_msg); > if (ret) { > dev_err(&master->dev, > "failed to transfer one message from queue\n"); > - mutex_unlock(&master->bus_lock_mutex); > - return; > + goto out; > } > - mutex_unlock(&master->bus_lock_mutex); > + > +out: > + if (!bus_locked) > + mutex_unlock(&master->bus_lock_mutex); > > /* Prod the scheduler in case transfer_one() was busy waiting */ > - cond_resched(); > + if (!ret) > + cond_resched(); > } > > /** > @@ -1204,7 +1208,7 @@ static void spi_pump_messages(struct kthread_work *work) > struct spi_master *master = > container_of(work, struct spi_master, pump_messages); > > - __spi_pump_messages(master, true); > + __spi_pump_messages(master, true, false); > } > > static int spi_init_queue(struct spi_master *master) > @@ -2814,7 +2818,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, > spi_sync_immediate); > SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, > spi_sync_immediate); > - __spi_pump_messages(master, false); > + __spi_pump_messages(master, false, bus_locked); > } > > wait_for_completion(&done); >