* RFC: dma_resv_unlock() and ww_acquire_ctx scope
@ 2023-01-19 10:24 Paul Cercueil
2023-01-19 10:37 ` Maarten Lankhorst
0 siblings, 1 reply; 5+ messages in thread
From: Paul Cercueil @ 2023-01-19 10:24 UTC (permalink / raw)
To: Sumit Semwal, Christian Koenig; +Cc: dri-devel, linux-media
Hi,
Just a reflexion I have after an intensive (and intense) debugging
session.
I had the following code:
int my_dma_resv_lock(struct dma_buf *dmabuf)
{
struct ww_acquire_ctx ctx;
int ret;
ww_acquire_init(&ctx, &reservation_ww_class);
ret = dma_resv_lock_interruptible(dmabuf->resv, &ctx);
if (ret) {
if (ret != -EDEADLK)
return ret;
ret = dma_resv_lock_slow_interruptible(dmabuf->resv,
&ctx);
}
return ret;
}
Then I would eventually unlock the dma_resv object in the caller
function. What made me think this was okay, was that the API itself
suggests it's okay - as dma_resv_unlock() does not take the
"ww_acquire_ctx" object as argument, my assumption was that after the
dma_resv was locked, the variable could go out of scope.
I wonder if it would be possible to change the API a little bit, so
that it is less prone to errors like this. Maybe by doing a struct copy
of the initialized ctx into the dma_resv object (if at all possible),
so that the original can actually go out of scope, or maybe having
dma_resv_unlock() take the ww_acquire_ctx as argument, even if it is
not actually used in the function body - just to make it obvious that
it is needed all the way to the point where the dma_resv is unlocked.
This email doesn't have to result in anything, I just thought I'd share
one point where I feel the API could be made less error-prone.
Cheers,
-Paul
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: dma_resv_unlock() and ww_acquire_ctx scope 2023-01-19 10:24 RFC: dma_resv_unlock() and ww_acquire_ctx scope Paul Cercueil @ 2023-01-19 10:37 ` Maarten Lankhorst 2023-01-19 11:12 ` Daniel Vetter 0 siblings, 1 reply; 5+ messages in thread From: Maarten Lankhorst @ 2023-01-19 10:37 UTC (permalink / raw) To: Paul Cercueil, Sumit Semwal, Christian Koenig; +Cc: dri-devel, linux-media On 2023-01-19 11:24, Paul Cercueil wrote: > Hi, > > Just a reflexion I have after an intensive (and intense) debugging > session. > > I had the following code: > > > int my_dma_resv_lock(struct dma_buf *dmabuf) > { > struct ww_acquire_ctx ctx; > int ret; > > ww_acquire_init(&ctx, &reservation_ww_class); > > ret = dma_resv_lock_interruptible(dmabuf->resv, &ctx); > if (ret) { > if (ret != -EDEADLK) > return ret; > > ret = dma_resv_lock_slow_interruptible(dmabuf->resv, > &ctx); > } > > return ret; > } > > > Then I would eventually unlock the dma_resv object in the caller > function. What made me think this was okay, was that the API itself > suggests it's okay - as dma_resv_unlock() does not take the > "ww_acquire_ctx" object as argument, my assumption was that after the > dma_resv was locked, the variable could go out of scope. > > I wonder if it would be possible to change the API a little bit, so > that it is less prone to errors like this. Maybe by doing a struct copy > of the initialized ctx into the dma_resv object (if at all possible), > so that the original can actually go out of scope, or maybe having > dma_resv_unlock() take the ww_acquire_ctx as argument, even if it is > not actually used in the function body - just to make it obvious that > it is needed all the way to the point where the dma_resv is unlocked. > > This email doesn't have to result in anything, I just thought I'd share > one point where I feel the API could be made less error-prone. Hey, This example code will fail eventually. If you have DEBUG_LOCK_ALLOC enabled, a fake lock is inited in ww_acquire_init. If you don't free it using ww_acquire_fini(), lockdep will see that you free a live lock that was never released. PROVE_LOCKING will also complain that you never unlocked the ctx fake lock. If you do call ww_acquire_fini, you will get a loud complain if you never released all locks, because ctx->acquired is non-zero. Try with PROVE_LOCKING, your example will receive a lockdep splat. :) ~Maarten ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: dma_resv_unlock() and ww_acquire_ctx scope 2023-01-19 10:37 ` Maarten Lankhorst @ 2023-01-19 11:12 ` Daniel Vetter 2023-01-19 11:44 ` Christian König 0 siblings, 1 reply; 5+ messages in thread From: Daniel Vetter @ 2023-01-19 11:12 UTC (permalink / raw) To: Maarten Lankhorst Cc: Paul Cercueil, Sumit Semwal, Christian Koenig, dri-devel, linux-media On Thu, Jan 19, 2023 at 11:37:39AM +0100, Maarten Lankhorst wrote: > > On 2023-01-19 11:24, Paul Cercueil wrote: > > Hi, > > > > Just a reflexion I have after an intensive (and intense) debugging > > session. > > > > I had the following code: > > > > > > int my_dma_resv_lock(struct dma_buf *dmabuf) > > { > > struct ww_acquire_ctx ctx; > > int ret; > > > > ww_acquire_init(&ctx, &reservation_ww_class); > > > > ret = dma_resv_lock_interruptible(dmabuf->resv, &ctx); > > if (ret) { > > if (ret != -EDEADLK) > > return ret; > > > > ret = dma_resv_lock_slow_interruptible(dmabuf->resv, > > &ctx); > > } > > > > return ret; > > } > > > > > > Then I would eventually unlock the dma_resv object in the caller > > function. What made me think this was okay, was that the API itself > > suggests it's okay - as dma_resv_unlock() does not take the > > "ww_acquire_ctx" object as argument, my assumption was that after the > > dma_resv was locked, the variable could go out of scope. > > > > I wonder if it would be possible to change the API a little bit, so > > that it is less prone to errors like this. Maybe by doing a struct copy > > of the initialized ctx into the dma_resv object (if at all possible), > > so that the original can actually go out of scope, or maybe having > > dma_resv_unlock() take the ww_acquire_ctx as argument, even if it is > > not actually used in the function body - just to make it obvious that > > it is needed all the way to the point where the dma_resv is unlocked. > > > > This email doesn't have to result in anything, I just thought I'd share > > one point where I feel the API could be made less error-prone. > > Hey, > > This example code will fail eventually. If you have DEBUG_LOCK_ALLOC > enabled, a fake lock is inited in ww_acquire_init. If you don't free it > using ww_acquire_fini(), lockdep will see that you free a live lock that was > never released. PROVE_LOCKING will also complain that you never unlocked the > ctx fake lock. > > If you do call ww_acquire_fini, you will get a loud complain if you never > released all locks, because ctx->acquired is non-zero. > > Try with PROVE_LOCKING, your example will receive a lockdep splat. :) Also CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y any time you change ww code please. Otherwise it's just not fully tested. -Daniel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: dma_resv_unlock() and ww_acquire_ctx scope 2023-01-19 11:12 ` Daniel Vetter @ 2023-01-19 11:44 ` Christian König 2023-01-24 15:24 ` Paul Cercueil 0 siblings, 1 reply; 5+ messages in thread From: Christian König @ 2023-01-19 11:44 UTC (permalink / raw) To: Daniel Vetter, Maarten Lankhorst Cc: Paul Cercueil, Sumit Semwal, dri-devel, linux-media Am 19.01.23 um 12:12 schrieb Daniel Vetter: > On Thu, Jan 19, 2023 at 11:37:39AM +0100, Maarten Lankhorst wrote: >> On 2023-01-19 11:24, Paul Cercueil wrote: >>> Hi, >>> >>> Just a reflexion I have after an intensive (and intense) debugging >>> session. >>> >>> I had the following code: >>> >>> >>> int my_dma_resv_lock(struct dma_buf *dmabuf) >>> { >>> struct ww_acquire_ctx ctx; >>> int ret; >>> >>> ww_acquire_init(&ctx, &reservation_ww_class); >>> >>> ret = dma_resv_lock_interruptible(dmabuf->resv, &ctx); >>> if (ret) { >>> if (ret != -EDEADLK) >>> return ret; >>> >>> ret = dma_resv_lock_slow_interruptible(dmabuf->resv, >>> &ctx); >>> } >>> >>> return ret; >>> } >>> >>> >>> Then I would eventually unlock the dma_resv object in the caller >>> function. What made me think this was okay, was that the API itself >>> suggests it's okay - as dma_resv_unlock() does not take the >>> "ww_acquire_ctx" object as argument, my assumption was that after the >>> dma_resv was locked, the variable could go out of scope. >>> >>> I wonder if it would be possible to change the API a little bit, so >>> that it is less prone to errors like this. Maybe by doing a struct copy >>> of the initialized ctx into the dma_resv object (if at all possible), >>> so that the original can actually go out of scope, or maybe having >>> dma_resv_unlock() take the ww_acquire_ctx as argument, even if it is >>> not actually used in the function body - just to make it obvious that >>> it is needed all the way to the point where the dma_resv is unlocked. >>> >>> This email doesn't have to result in anything, I just thought I'd share >>> one point where I feel the API could be made less error-prone. >> Hey, >> >> This example code will fail eventually. If you have DEBUG_LOCK_ALLOC >> enabled, a fake lock is inited in ww_acquire_init. If you don't free it >> using ww_acquire_fini(), lockdep will see that you free a live lock that was >> never released. PROVE_LOCKING will also complain that you never unlocked the >> ctx fake lock. >> >> If you do call ww_acquire_fini, you will get a loud complain if you never >> released all locks, because ctx->acquired is non-zero. The problem isn't that dma_resv_unlock() doesn't need the ctx, the problem is that in this example the ctx object isn't properly cleaned up and used. As long as you only need to grab one lock the ctx should be NULL. Only when you grab multiple locks the ctx is used to make sure that you can detect and handle deadlocks between those different locks. So using the ctx correctly also makes the lifetime of that object much more clear since it needs to stay around at least until all locks are taken. >> >> Try with PROVE_LOCKING, your example will receive a lockdep splat. :) > Also CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y any time you change ww code please. > Otherwise it's just not fully tested. Yeah, completely agree to both. Christian. > -Daniel ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: dma_resv_unlock() and ww_acquire_ctx scope 2023-01-19 11:44 ` Christian König @ 2023-01-24 15:24 ` Paul Cercueil 0 siblings, 0 replies; 5+ messages in thread From: Paul Cercueil @ 2023-01-24 15:24 UTC (permalink / raw) To: Christian König, Daniel Vetter, Maarten Lankhorst Cc: Sumit Semwal, dri-devel, linux-media Le jeudi 19 janvier 2023 à 12:44 +0100, Christian König a écrit : > Am 19.01.23 um 12:12 schrieb Daniel Vetter: > > On Thu, Jan 19, 2023 at 11:37:39AM +0100, Maarten Lankhorst wrote: > > > On 2023-01-19 11:24, Paul Cercueil wrote: > > > > Hi, > > > > > > > > Just a reflexion I have after an intensive (and intense) > > > > debugging > > > > session. > > > > > > > > I had the following code: > > > > > > > > > > > > int my_dma_resv_lock(struct dma_buf *dmabuf) > > > > { > > > > struct ww_acquire_ctx ctx; > > > > int ret; > > > > > > > > ww_acquire_init(&ctx, &reservation_ww_class); > > > > > > > > ret = dma_resv_lock_interruptible(dmabuf->resv, &ctx); > > > > if (ret) { > > > > if (ret != -EDEADLK) > > > > return ret; > > > > > > > > ret = dma_resv_lock_slow_interruptible(dmabuf- > > > > >resv, > > > > &ctx); > > > > } > > > > > > > > return ret; > > > > } > > > > > > > > > > > > Then I would eventually unlock the dma_resv object in the > > > > caller > > > > function. What made me think this was okay, was that the API > > > > itself > > > > suggests it's okay - as dma_resv_unlock() does not take the > > > > "ww_acquire_ctx" object as argument, my assumption was that > > > > after the > > > > dma_resv was locked, the variable could go out of scope. > > > > > > > > I wonder if it would be possible to change the API a little > > > > bit, so > > > > that it is less prone to errors like this. Maybe by doing a > > > > struct copy > > > > of the initialized ctx into the dma_resv object (if at all > > > > possible), > > > > so that the original can actually go out of scope, or maybe > > > > having > > > > dma_resv_unlock() take the ww_acquire_ctx as argument, even if > > > > it is > > > > not actually used in the function body - just to make it > > > > obvious that > > > > it is needed all the way to the point where the dma_resv is > > > > unlocked. > > > > > > > > This email doesn't have to result in anything, I just thought > > > > I'd share > > > > one point where I feel the API could be made less error-prone. > > > Hey, > > > > > > This example code will fail eventually. If you have > > > DEBUG_LOCK_ALLOC > > > enabled, a fake lock is inited in ww_acquire_init. If you don't > > > free it > > > using ww_acquire_fini(), lockdep will see that you free a live > > > lock that was > > > never released. PROVE_LOCKING will also complain that you never > > > unlocked the > > > ctx fake lock. > > > > > > If you do call ww_acquire_fini, you will get a loud complain if > > > you never > > > released all locks, because ctx->acquired is non-zero. > > The problem isn't that dma_resv_unlock() doesn't need the ctx, the > problem is that in this example the ctx object isn't properly cleaned > up > and used. Ah, that's a very good point :) > As long as you only need to grab one lock the ctx should be NULL. > Only > when you grab multiple locks the ctx is used to make sure that you > can > detect and handle deadlocks between those different locks. Understood. I will use NULL then. Cheers, -Paul > So using the ctx correctly also makes the lifetime of that object > much > more clear since it needs to stay around at least until all locks are > taken. > > > > > > > Try with PROVE_LOCKING, your example will receive a lockdep > > > splat. :) > > Also CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y any time you change ww code > > please. > > Otherwise it's just not fully tested. > > Yeah, completely agree to both. > > Christian. > > > -Daniel > ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-01-24 15:24 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-01-19 10:24 RFC: dma_resv_unlock() and ww_acquire_ctx scope Paul Cercueil 2023-01-19 10:37 ` Maarten Lankhorst 2023-01-19 11:12 ` Daniel Vetter 2023-01-19 11:44 ` Christian König 2023-01-24 15:24 ` Paul Cercueil
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox