From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966536AbdAKNUx (ORCPT ); Wed, 11 Jan 2017 08:20:53 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:59843 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S937784AbdAKNUO (ORCPT ); Wed, 11 Jan 2017 08:20:14 -0500 X-AuditID: cbfec7f4-f79716d000006f65-75-587631085380 Subject: Re: [PATCH] dmaengine: pl330: fix double lock To: iari@itu.dk Cc: Bartlomiej Zolnierkiewicz , Vinod Koul , Krzysztof Kozlowski , Dan Williams , dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org, Iago Abal From: Marek Szyprowski Message-id: Date: Wed, 11 Jan 2017 14:20:06 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-version: 1.0 In-reply-to: <1484139621-18706-1-git-send-email-iari@itu.dk> Content-type: text/plain; charset=utf-8; format=flowed Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprFKsWRmVeSWpSXmKPExsWy7djPc7ochmURBufP6VpsnLGe1WL61AuM Fqun/mW12Npxksni/PkN7BaXd81hs5jTv4/F4mXffhYHDo9pTz8weSze85LJY+PFpYwem1Z1 snn0bVnF6PF5k1wAWxSXTUpqTmZZapG+XQJXxo/HV9gLNmhVrN8zk6WBcZ5SFyMnh4SAicTi /qmsELaYxIV769m6GLk4hASWMkq8mzeJCcL5zCix8vYBxi5GDrCOw/csIOLLGCXmNF+FKnrO KLHqcDMLSJGwgJnE/2n5IFNFBPglNn/6BzaVWaCDSWLul61MIAk2AUOJrrddbCA2r4CdxK4f Z8HiLAKqEtPOfwGzRQViJBpO/WSHqBGU+DH5HguIzSlgI3F70RmwXmYBK4ln/1pZIWx5ic1r 3jKDLJMQ2MQu8WrmORaIq2UlNh1ghnjTRWLf8SYWCFtY4tXxLewQtozE5cndUPF+RommVm0I ewajxLm3vBC2tcTh4xehdvFJTNo2nRliPK9ER5sQRImHxPSlv5kgbEeJuW+OMkLCB2jk5sXT 2Ccwys9C8s4sJC/MQvLCAkbmVYwiqaXFuempxSZ6xYm5xaV56XrJ+bmbGIEp5vS/4192MC4+ ZnWIUYCDUYmH1+J1SYQQa2JZcWXuIUYJDmYlEV4mvbIIId6UxMqq1KL8+KLSnNTiQ4zSHCxK 4rx7FlwJFxJITyxJzU5NLUgtgskycXBKNTDWXj692Dt4K+O5z4G81VKZp5yDF/W3S/YHLjYR 6Z212uDoTZV8yRWMWscTY9+5B93McauUy1p0W82wobn65uOoi3OPmp46W3LzsR5fyurrP0/0 GavONOzallvdE+HP1Dx1j4Xoozepb3VnOMe//L7u8PmW6Hvuh95PmdFk8uJs8C7XhQ/dX0oq sRRnJBpqMRcVJwIA1YctFS0DAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrNIsWRmVeSWpSXmKPExsVy+t/xa7oMhmURBm+6DC02zljPajF96gVG i9VT/7JabO04yWRx/vwGdovLu+awWczp38di8bJvP4sDh8e0px+YPBbvecnksfHiUkaPTas6 2Tz6tqxi9Pi8SS6ALcrNJiM1MSW1SCE1Lzk/JTMv3VYpNMRN10JJIS8xN9VWKULXNyRISaEs MacUyDMyQAMOzgHuwUr6dgluGT8eX2Ev2KBVsX7PTJYGxnlKXYwcHBICJhKH71l0MXICmWIS F+6tZ+ti5OIQEljCKDHz/H0o5zmjROvNqawgDcICZhL/p+WDNIgI8Ets/vQPqmYio8Tp5qdg DrNAB5PEk5dzmUCq2AQMJbredrGB2LwCdhK7fpwFi7MIqEpMO/8FzBYViJF4u345O0SNoMSP yfdYQGxOARuJ24vOgPUyAy3+8vIwK4QtL7F5zVvmCYwCs5C0zEJSNgtJ2QJG5lWMIqmlxbnp ucVGesWJucWleel6yfm5mxiBEbft2M8tOxi73gUfYhTgYFTi4bV4XRIhxJpYVlyZe4hRgoNZ SYSXSa8sQog3JbGyKrUoP76oNCe1+BCjKdATE5mlRJPzgckgryTe0MTQ3NLQyNjCwtzISEmc d+qHK+FCAumJJanZqakFqUUwfUwcnFINjMW7tu3fwi7d4n0lpVTNsP3H9LMHmlXVdflaOgKV ktg+sjHNn1qgZK9+pbR8VuCftCLXKC6V6pxj/7+4ypirz9J/96b6Vgzrvu4/crXPlk/lPLxy qZ2Zx9GSNCbh/7endzxzVNiwz0Cku3uB5J67Hf+OLFB8fHOBUNfaGxJC1zQP3lErf1N1UIml OCPRUIu5qDgRAGuGBWLOAgAA X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20170111132008eucas1p156152b6683ede8496f3ed587c03a0bd6 X-Msg-Generator: CA X-Sender-IP: 182.198.249.180 X-Local-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRs=?= =?UTF-8?B?7IK87ISx7KCE7J6QG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Global-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRtT?= =?UTF-8?B?YW1zdW5nIEVsZWN0cm9uaWNzG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTI=?= CMS-TYPE: 201P X-HopCount: 7 X-CMS-RootMailID: 20170111130113epcas5p3e450202a65d15a1479701a0ef0d674a0 X-RootMTR: 20170111130113epcas5p3e450202a65d15a1479701a0ef0d674a0 References: <1484139621-18706-1-git-send-email-iari@itu.dk> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Iago, On 2017-01-11 14:00, iari@itu.dk wrote: > From: Iago Abal > > The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the > following double-lock bug: > > Double lock: > 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; > 2. call to function `pl330_release_channel' immediately after; > 3. call to function `dma_pl330_rqcb' in line 1753; > 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. > > I have fixed it as suggested by Marek Szyprowski. > > First, I have replaced `pch->lock' with `pl330->lock' in functions > `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids > the double-lock by acquiring a different lock than `dma_pl330_rqcb'. > > NOTE that, as a result, `pl330_free_chan_resources' executes > `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', > whereas in the rest of the code `pch->work_list' is protected by > `pch->lock'. I don't know if this may cause race conditions. Similarly > `pch->cyclic' is written by `pl330_alloc_chan_resources' under > `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. At the moment of initialization and releasing resources this is not a problem. > Second, I have removed locking from `pl330_request_channel' and > `pl330_release_channel' functions. Function `pl330_request_channel' is > only called from `pl330_alloc_chan_resources', so the lock is already > held. Function `pl330_release_channel' is called from > `pl330_free_chan_resources', which already holds the lock, and from > `pl330_del'. Function `pl330_del' is called in an error path of > `pl330_probe' and at the end of `pl330_remove', but I assume that there > cannot be concurrent accesses to the protected data at those points. > > Signed-off-by: Iago Abal Reviewed-by: Marek Szyprowski > --- > drivers/dma/pl330.c | 19 ++++++------------- > 1 file changed, 6 insertions(+), 13 deletions(-) > > diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c > index 87fd015..3370e56 100644 > --- a/drivers/dma/pl330.c > +++ b/drivers/dma/pl330.c > @@ -1696,7 +1696,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i) > static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) > { > struct pl330_thread *thrd = NULL; > - unsigned long flags; > int chans, i; > > if (pl330->state == DYING) > @@ -1704,8 +1703,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) > > chans = pl330->pcfg.num_chan; > > - spin_lock_irqsave(&pl330->lock, flags); > - > for (i = 0; i < chans; i++) { > thrd = &pl330->channels[i]; > if ((thrd->free) && (!_manager_ns(thrd) || > @@ -1723,8 +1720,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) > thrd = NULL; > } > > - spin_unlock_irqrestore(&pl330->lock, flags); > - > return thrd; > } > > @@ -1742,7 +1737,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev) > static void pl330_release_channel(struct pl330_thread *thrd) > { > struct pl330_dmac *pl330; > - unsigned long flags; > > if (!thrd || thrd->free) > return; > @@ -1754,10 +1748,8 @@ static void pl330_release_channel(struct pl330_thread *thrd) > > pl330 = thrd->dmac; > > - spin_lock_irqsave(&pl330->lock, flags); > _free_event(thrd, thrd->ev); > thrd->free = true; > - spin_unlock_irqrestore(&pl330->lock, flags); > } > > /* Initialize the structure for PL330 configuration, that can be used > @@ -2117,20 +2109,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) > struct pl330_dmac *pl330 = pch->dmac; > unsigned long flags; > > - spin_lock_irqsave(&pch->lock, flags); > + spin_lock_irqsave(&pl330->lock, flags); > > dma_cookie_init(chan); > pch->cyclic = false; > > pch->thread = pl330_request_channel(pl330); > if (!pch->thread) { > - spin_unlock_irqrestore(&pch->lock, flags); > + spin_unlock_irqrestore(&pl330->lock, flags); > return -ENOMEM; > } > > tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); > > - spin_unlock_irqrestore(&pch->lock, flags); > + spin_unlock_irqrestore(&pl330->lock, flags); > > return 1; > } > @@ -2228,12 +2220,13 @@ static int pl330_pause(struct dma_chan *chan) > static void pl330_free_chan_resources(struct dma_chan *chan) > { > struct dma_pl330_chan *pch = to_pchan(chan); > + struct pl330_dmac *pl330 = pch->dmac; > unsigned long flags; > > tasklet_kill(&pch->task); > > pm_runtime_get_sync(pch->dmac->ddma.dev); > - spin_lock_irqsave(&pch->lock, flags); > + spin_lock_irqsave(&pl330->lock, flags); > > pl330_release_channel(pch->thread); > pch->thread = NULL; > @@ -2241,7 +2234,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) > if (pch->cyclic) > list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); > > - spin_unlock_irqrestore(&pch->lock, flags); > + spin_unlock_irqrestore(&pl330->lock, flags); > pm_runtime_mark_last_busy(pch->dmac->ddma.dev); > pm_runtime_put_autosuspend(pch->dmac->ddma.dev); > } Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland