On 10/11/2012 08:42 PM, Maarten Lankhorst wrote: > >> Anyway, if you plan to remove the fence lock and protect it with reserve, >> you must >> make sure that a waiting reserve is never done in a destruction path. I >> think this >> mostly concerns the nvidia driver. > Well I don't think any lock should ever be held during destruction time,
What I mean is, that *something* needs to protect the fence pointer. Currently it's the fence lock, and I was assuming you'd protect it with reserve. And neither TTM nor Nvidia should, when a resource is about to be freed, be forced to *block* waiting for reserve just to access the fence pointer. When and if you have a solution that fulfills those requirements, I'm ready to review it. > >>> - no_wait_reserve is ignored if no_wait_gpu is false >>> ttm_bo_reserve_locked can only return true if no_wait_reserve is true, >>> but >>> subsequently it will do a wait_unreserved if no_wait_gpu is false. >>> I'm planning on removing this argument and act like it is always true, since >>> nothing on the lru list should fail to reserve currently. >> Yes, since all buffers that are reserved are removed from the LRU list, there >> should never be a waiting reserve on them, so no_wait_reserve can be removed >> from ttm_mem_evict_first, ttm_bo_evict and possibly other functions in the >> call chain. > I suppose there will stay a small race though, Hmm, where? >>> - effectively unlimited callchain between some functions that all go through >>> ttm_mem_evict_first: >>> >>> /------------------------\ >>> ttm_mem_evict_first - ttm_bo_evict - >>> -ttm_bo_mem_space - ttm_bo_mem_force_space - ttm_mem_evict_first >>> \ ttm_bo_handle_move_mem / >>> I'm not surprised that there was a deadlock before, it seems to me it would >>> be pretty suicidal to ever do a blocking reserve on any of those lists, >>> lockdep would be all over you for this. >> Well, at first this may look worse than it actually is. The driver's >> eviction memory order determines the recursion depth >> and typically it's 0 or 1, since subsequent ttm_mem_evict_first should never >> touch the same LRU lists as the first one. >> What would typically happen is that a BO is evicted from VRAM to TT, and if >> there is no space in TT, another BO is evicted >> to system memory, and the chain is terminated. However a driver could set up >> any eviction order but that would be >> a BUG. >> >> But in essence, as you say, even with a small recursion depth, a waiting >> reserve could cause a deadlock. >> But there should be no waiting reserves in the eviction path currently. > Partially true, ttm_bo_cleanup_refs is currently capable of blocking reserve. > Fixing this might mean that ttm_mem_evict_first may need to become more > aggressive, > since it seems all the callers of this function assume that > ttm_mem_evict_first can only fail > if there is really nothing more to free and blocking nested would really > upset lockdep > and leave you open to the same deadlocks. I can't see how the waiting reserve in ttm_bo_cleanup_refs would cause a deadlock, because the buffer about to be reserved is always *last* in a reservation sequence, and the reservation is always released (or the buffer destroyed) before trying to reserve another buffer. Technically the buffer is not looked up from a LRU list but from the delayed delete list. Could you describe such a deadlock case? (There is a bug in there, though that the reservation is not released if the buffer is no longer on the reservation list here): if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) { spin_unlock(&glob->lru_lock); return ret; } > > An unexpected bonus from adding this skipping would be that the atomic > lru_list > removal on unreserve guarantee becomes a lot easier to drop while keeping > behavior > exactly the same. Only the swapout code would need to be adjusted for to try > the whole > list. Maybe ttm_bo_delayed_delete with remove_all = false too would change > behavior > slightly too, but this seems to be less likely, as it could only ever happen > on delayed > destruction of imported dma-buf's. May I kindly remind you that the atomic lru_list removal stays in TTM until we've had a high level design discussion weighing it against an extended reservation object API. > > Not true, ttm_bo_move_memcpy has no interruptible parameter, so it's not > compatible with driver.move. > The drivers that do use this function have set up their own alias that calls > that function instead, > so I was thinking of dropping those parameters from memcpy since they're > unused and the drivers > that could point their move member to it don't do it, so no point in having > compatibility... OK, then I'm OK with parameter changes in those functions. > > ~Maarten >