diff mbox series

[v6,2/6] dmaengine: virt-dma: Use lockdep to check locking requirements

Message ID 20200708201906.4546-3-laurent.pinchart@ideasonboard.com (mailing list archive)
State Changes Requested
Headers show
Series dma: Add Xilinx ZynqMP DPDMA driver | expand

Commit Message

Laurent Pinchart July 8, 2020, 8:19 p.m. UTC
A few virt-dma functions are documented as requiring the vc.lock to be
held by the caller. Check this with lockdep.

The vchan_vdesc_fini() and vchan_find_desc() functions gain a lockdep
check as well, because, even though they are not documented with this
requirement (and not documented at all for the latter), they touch
fields documented as protected by vc.lock. All callers have been
manually inspected to verify they call the functions with the lock held.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/dma/virt-dma.c |  2 ++
 drivers/dma/virt-dma.h | 10 ++++++++++
 2 files changed, 12 insertions(+)

Comments

Peter Ujfalusi July 9, 2020, 1:07 p.m. UTC | #1
Hi Laurent,

On 08/07/2020 23.19, Laurent Pinchart wrote:
> A few virt-dma functions are documented as requiring the vc.lock to be
> held by the caller. Check this with lockdep.
> 
> The vchan_vdesc_fini() and vchan_find_desc() functions gain a lockdep

vchan_vdesc_fini() is used outside of held vc->lock via vchan_complete()
and the customized local re-implementation of it in ti/k3-udma.c

This patch did not adds the lockdep_assert_held() to the _fini.
The vchan_complete() can be issue only in  case when the descriptor is
set to DMA_CTRL_REUSE.

> check as well, because, even though they are not documented with this
> requirement (and not documented at all for the latter), they touch
> fields documented as protected by vc.lock. All callers have been
> manually inspected to verify they call the functions with the lock held.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  drivers/dma/virt-dma.c |  2 ++
>  drivers/dma/virt-dma.h | 10 ++++++++++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
> index 23e33a85f033..1cb36ab3d9c1 100644
> --- a/drivers/dma/virt-dma.c
> +++ b/drivers/dma/virt-dma.c
> @@ -68,6 +68,8 @@ struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
>  {
>  	struct virt_dma_desc *vd;
>  
> +	lockdep_assert_held(&vc->lock);
> +
>  	list_for_each_entry(vd, &vc->desc_issued, node)
>  		if (vd->tx.cookie == cookie)
>  			return vd;
> diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
> index e9f5250fbe4d..59d9eabc8b67 100644
> --- a/drivers/dma/virt-dma.h
> +++ b/drivers/dma/virt-dma.h
> @@ -81,6 +81,8 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
>   */
>  static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
>  {
> +	lockdep_assert_held(&vc->lock);
> +
>  	list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued);
>  	return !list_empty(&vc->desc_issued);
>  }
> @@ -96,6 +98,8 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
>  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
>  	dma_cookie_t cookie;
>  
> +	lockdep_assert_held(&vc->lock);
> +
>  	cookie = vd->tx.cookie;
>  	dma_cookie_complete(&vd->tx);
>  	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
> @@ -146,6 +150,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
>  {
>  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
>  
> +	lockdep_assert_held(&vc->lock);
> +
>  	list_add_tail(&vd->node, &vc->desc_terminated);
>  
>  	if (vc->cyclic == vd)
> @@ -160,6 +166,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
>   */
>  static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
>  {
> +	lockdep_assert_held(&vc->lock);
> +
>  	return list_first_entry_or_null(&vc->desc_issued,
>  					struct virt_dma_desc, node);
>  }
> @@ -177,6 +185,8 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
>  static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
>  	struct list_head *head)
>  {
> +	lockdep_assert_held(&vc->lock);
> +
>  	list_splice_tail_init(&vc->desc_allocated, head);
>  	list_splice_tail_init(&vc->desc_submitted, head);
>  	list_splice_tail_init(&vc->desc_issued, head);
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
Laurent Pinchart July 11, 2020, 7:53 p.m. UTC | #2
Hi Peter,

On Thu, Jul 09, 2020 at 04:07:38PM +0300, Peter Ujfalusi wrote:
> On 08/07/2020 23.19, Laurent Pinchart wrote:
> > A few virt-dma functions are documented as requiring the vc.lock to be
> > held by the caller. Check this with lockdep.
> > 
> > The vchan_vdesc_fini() and vchan_find_desc() functions gain a lockdep
> 
> vchan_vdesc_fini() is used outside of held vc->lock via vchan_complete()
> and the customized local re-implementation of it in ti/k3-udma.c
> 
> This patch did not adds the lockdep_assert_held() to the _fini.
> The vchan_complete() can be issue only in  case when the descriptor is
> set to DMA_CTRL_REUSE.

I'll drop the patch completely, I don't need it for this series. I still
think it's useful though, so if someone wants to pick it up and fix it,
please don't hesitate.

> > check as well, because, even though they are not documented with this
> > requirement (and not documented at all for the latter), they touch
> > fields documented as protected by vc.lock. All callers have been
> > manually inspected to verify they call the functions with the lock held.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  drivers/dma/virt-dma.c |  2 ++
> >  drivers/dma/virt-dma.h | 10 ++++++++++
> >  2 files changed, 12 insertions(+)
> > 
> > diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
> > index 23e33a85f033..1cb36ab3d9c1 100644
> > --- a/drivers/dma/virt-dma.c
> > +++ b/drivers/dma/virt-dma.c
> > @@ -68,6 +68,8 @@ struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
> >  {
> >  	struct virt_dma_desc *vd;
> >  
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	list_for_each_entry(vd, &vc->desc_issued, node)
> >  		if (vd->tx.cookie == cookie)
> >  			return vd;
> > diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
> > index e9f5250fbe4d..59d9eabc8b67 100644
> > --- a/drivers/dma/virt-dma.h
> > +++ b/drivers/dma/virt-dma.h
> > @@ -81,6 +81,8 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
> >   */
> >  static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
> >  {
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued);
> >  	return !list_empty(&vc->desc_issued);
> >  }
> > @@ -96,6 +98,8 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
> >  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
> >  	dma_cookie_t cookie;
> >  
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	cookie = vd->tx.cookie;
> >  	dma_cookie_complete(&vd->tx);
> >  	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
> > @@ -146,6 +150,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
> >  {
> >  	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
> >  
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	list_add_tail(&vd->node, &vc->desc_terminated);
> >  
> >  	if (vc->cyclic == vd)
> > @@ -160,6 +166,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
> >   */
> >  static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
> >  {
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	return list_first_entry_or_null(&vc->desc_issued,
> >  					struct virt_dma_desc, node);
> >  }
> > @@ -177,6 +185,8 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
> >  static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
> >  	struct list_head *head)
> >  {
> > +	lockdep_assert_held(&vc->lock);
> > +
> >  	list_splice_tail_init(&vc->desc_allocated, head);
> >  	list_splice_tail_init(&vc->desc_submitted, head);
> >  	list_splice_tail_init(&vc->desc_issued, head);
diff mbox series

Patch

diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 23e33a85f033..1cb36ab3d9c1 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -68,6 +68,8 @@  struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
 {
 	struct virt_dma_desc *vd;
 
+	lockdep_assert_held(&vc->lock);
+
 	list_for_each_entry(vd, &vc->desc_issued, node)
 		if (vd->tx.cookie == cookie)
 			return vd;
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index e9f5250fbe4d..59d9eabc8b67 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -81,6 +81,8 @@  static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
  */
 static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
 {
+	lockdep_assert_held(&vc->lock);
+
 	list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued);
 	return !list_empty(&vc->desc_issued);
 }
@@ -96,6 +98,8 @@  static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
 	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
 	dma_cookie_t cookie;
 
+	lockdep_assert_held(&vc->lock);
+
 	cookie = vd->tx.cookie;
 	dma_cookie_complete(&vd->tx);
 	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
@@ -146,6 +150,8 @@  static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
 {
 	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
 
+	lockdep_assert_held(&vc->lock);
+
 	list_add_tail(&vd->node, &vc->desc_terminated);
 
 	if (vc->cyclic == vd)
@@ -160,6 +166,8 @@  static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
  */
 static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 {
+	lockdep_assert_held(&vc->lock);
+
 	return list_first_entry_or_null(&vc->desc_issued,
 					struct virt_dma_desc, node);
 }
@@ -177,6 +185,8 @@  static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
 	struct list_head *head)
 {
+	lockdep_assert_held(&vc->lock);
+
 	list_splice_tail_init(&vc->desc_allocated, head);
 	list_splice_tail_init(&vc->desc_submitted, head);
 	list_splice_tail_init(&vc->desc_issued, head);