tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: DRM/KMS: vmwgfx driver is now available
> Date: Sun, 23 Jul 2023 22:57:14 +0900
> From: PHO <pho%cielonegro.org@localhost>
>
> On 7/23/23 21:24, Taylor R Campbell wrote:
> > Why can't the loop just use dma_fence_get_rcu and dma_fence_put?
> >
> > Might need to release and reacquire the lock around dma_fence_put.
>
> I tried but it didn't work, apparently because someone was holding a
> pointer to a dying fence and waiting for it to be signaled. Using
> dma_fence_get_rcu() meant we didn't signal such fences, and the kernel
> hanged and eventually got killed by heartbeat().
What exactly did you try and what was the heartbeat panic stack trace?
Nothing here should wait for signalling in a way that trips the kernel
heartbeat monitor -- that should only happen if you hold onto a spin
lock for too long.
(That said: yay, the heartbeat monitor is catching what would
otherwise be a silent nonresponsive hang!)
Thinking about it some more, I see there is a snag with the loop and
dma_fence_put, since
(a) we can only use list_next(&fence->head) if we read it and then use
it under the lock, but
(b) we can only dma_fence_put outside the lock because the release
callback, vmw_fence_obj_destroy, takes the lock,
so there's no way to do the iteration safely as is with an extra
reference count acquire/release cycle. Two options come to mind:
1. Move vmw_fence_obj_destroy to an `RCU' callback so that we can
safely do dma_fence_put under the lock.
2. Create a list on the stack of signalled fences to put in
__vmw_fences_update and put them after the loop, outside the lock:
struct list_head to_put = LIST_HEAD_INIT(to_put);
...
list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
if (dma_fence_get_rcu(fence) != 0) { /* (*) */
list_del_init(&fence->head);
continue;
}
if (seqno - fence->base.seqno < VMW_FENCE_WRAP) {
list_del_init(&fence->head);
list_add(&fence->head, &to_put); /* (*) */
dma_fence_signal_locked(&fence->base);
...
}
break;
}
...
if (fence != NULL) {
spin_unlock(&fman->lock);
dma_fence_put(fence);
spin_lock(&fman->lock);
}
while ((fence = list_first(&to_put)) != NULL) {
list_del_init(&fence->head);
spin_unlock(&fman->lock);
dma_fence_put(fence);
spin_lock(&fman->lock);
}
> > If that doesn't work for some reason and we do have to add a special
> > case, I'd strongly prefer to add a new front end like
> > dma_fence_signal_vmwgfxspecialhack or something (other examples in the
> > tasklet API) that has the relaxed assertion instead of relaxing the
> > assertions for every other driver which isn't bonkers.
>
> Alright. I'll do that.
This should be a last resort (but not as bad as relaxing the
assertions) if we can't figure out a better way to do it.
I'm not sure the patch above is going to be best (if it works), but
I'd like to see if there's a way to do this without abusing the API
semantics too much before giving in to the abuse.
Home |
Main Index |
Thread Index |
Old Index