All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vinod Koul <vinod.koul@intel.com>
To: Alexander Kochetkov <al.kochet@gmail.com>,
	Marek Szyprowski <m.szyprowski@samsung.com>,
	Krzysztof Kozlowski <krzk@kernel.org>
Cc: Dan Williams <dan.j.williams@intel.com>,
	dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] dmaengine: pl330: fix descriptor allocation fail
Date: Tue, 26 Sep 2017 23:07:41 +0530	[thread overview]
Message-ID: <20170926173741.GT30097@localhost> (raw)
In-Reply-To: <1504864826-14202-1-git-send-email-al.kochet@gmail.com>

On Fri, Sep 08, 2017 at 01:00:26PM +0300, Alexander Kochetkov wrote:
> Thread A calls pl330_get_desc() to get descriptor. If DMAC descriptor
> pool is empty pl330_get_desc() allocates new descriptor using add_desc()
> and then get newly allocated descriptor using pluck_desc().
> It is possible that another concurrent thread B calls pluck_desc()
> and catch newly allocated descriptor. In that case descriptor allocation
> for thread A will fail with:
> 
> kernel: dma-pl330 20078000.dma-controller: pl330_get_desc:2469 ALERT!
> 
> The commit fix the issue by calling _add_desc() to allocate new descriptor
> to the local on stack pool and than get it from local pool. So the issue
> described will nether happen.

Tested-by please...

> 
> Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
> ---
>  drivers/dma/pl330.c |   44 +++++++++++++++++++++++++++-----------------
>  1 file changed, 27 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index f37f497..0e7f6c9 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -2417,7 +2417,8 @@ static inline void _init_desc(struct dma_pl330_desc *desc)
>  }
>  
>  /* Returns the number of descriptors added to the DMAC pool */
> -static int add_desc(struct pl330_dmac *pl330, gfp_t flg, int count)
> +static int _add_desc(struct list_head *pool, spinlock_t *lock,
> +	gfp_t flg, int count)

right justifed please

>  {
>  	struct dma_pl330_desc *desc;
>  	unsigned long flags;
> @@ -2427,27 +2428,33 @@ static int add_desc(struct pl330_dmac *pl330, gfp_t flg, int count)
>  	if (!desc)
>  		return 0;
>  
> -	spin_lock_irqsave(&pl330->pool_lock, flags);
> +	spin_lock_irqsave(lock, flags);
>  
>  	for (i = 0; i < count; i++) {
>  		_init_desc(&desc[i]);
> -		list_add_tail(&desc[i].node, &pl330->desc_pool);
> +		list_add_tail(&desc[i].node, pool);
>  	}
>  
> -	spin_unlock_irqrestore(&pl330->pool_lock, flags);
> +	spin_unlock_irqrestore(lock, flags);
>  
>  	return count;
>  }
>  
> -static struct dma_pl330_desc *pluck_desc(struct pl330_dmac *pl330)
> +static int add_desc(struct pl330_dmac *pl330, gfp_t flg, int count)
> +{
> +	return _add_desc(&pl330->desc_pool, &pl330->pool_lock, flg, count);

hmmm why add a wrapper?

> +}
> +
> +static struct dma_pl330_desc *_pluck_desc(struct list_head *pool,
> +	spinlock_t *lock)

here too, it helps in readability

>  {
>  	struct dma_pl330_desc *desc = NULL;
>  	unsigned long flags;
>  
> -	spin_lock_irqsave(&pl330->pool_lock, flags);
> +	spin_lock_irqsave(lock, flags);
>  
> -	if (!list_empty(&pl330->desc_pool)) {
> -		desc = list_entry(pl330->desc_pool.next,
> +	if (!list_empty(pool)) {
> +		desc = list_entry(pool->next,
>  				struct dma_pl330_desc, node);
>  
>  		list_del_init(&desc->node);
> @@ -2456,11 +2463,16 @@ static struct dma_pl330_desc *pluck_desc(struct pl330_dmac *pl330)
>  		desc->txd.callback = NULL;
>  	}
>  
> -	spin_unlock_irqrestore(&pl330->pool_lock, flags);
> +	spin_unlock_irqrestore(lock, flags);
>  
>  	return desc;
>  }
>  
> +static struct dma_pl330_desc *pluck_desc(struct pl330_dmac *pl330)
> +{
> +	return _pluck_desc(&pl330->desc_pool, &pl330->pool_lock);

one more wrapper why, we dont have any logic here!

> +}
> +
>  static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
>  {
>  	struct pl330_dmac *pl330 = pch->dmac;
> @@ -2472,16 +2484,14 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
>  
>  	/* If the DMAC pool is empty, alloc new */
>  	if (!desc) {
> -		if (!add_desc(pl330, GFP_ATOMIC, 1))
> -			return NULL;
> +		DEFINE_SPINLOCK(lock);
> +		LIST_HEAD(pool);
>  
> -		/* Try again */
> -		desc = pluck_desc(pl330);
> -		if (!desc) {
> -			dev_err(pch->dmac->ddma.dev,
> -				"%s:%d ALERT!\n", __func__, __LINE__);
> +		if (!_add_desc(&pool, &lock, GFP_ATOMIC, 1))
>  			return NULL;
> -		}
> +
> +		desc = _pluck_desc(&pool, &lock);
> +		WARN_ON(!desc || !list_empty(&pool));
>  	}
>  
>  	/* Initialize the descriptor */
> -- 
> 1.7.9.5
> 

-- 
~Vinod

  reply	other threads:[~2017-09-26 17:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-08 10:00 [PATCH] dmaengine: pl330: fix descriptor allocation fail Alexander Kochetkov
2017-09-26 17:37 ` Vinod Koul [this message]
2017-09-26 18:03   ` Alexander Kochetkov
2017-09-28  7:47     ` Vinod Koul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170926173741.GT30097@localhost \
    --to=vinod.koul@intel.com \
    --cc=al.kochet@gmail.com \
    --cc=dan.j.williams@intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=krzk@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=m.szyprowski@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.