On Tue, Apr 16, 2024 at 05:53:45PM +0200, Peter Zijlstra wrote: > On Tue, Apr 16, 2024 at 05:50:14PM +0200, Peter Zijlstra wrote: > > On Tue, Apr 16, 2024 at 10:14:21AM +0200, Peter Zijlstra wrote: > > > > > > Some aspects of the implementation may deserve particular comment: > > > > > > > > * In the interest of performance, each object is governed only by a single > > > > spinlock. However, NTSYNC_IOC_WAIT_ALL requires that the state of multiple > > > > objects be changed as a single atomic operation. In order to achieve this, we > > > > first take a device-wide lock ("wait_all_lock") any time we are going to lock > > > > more than one object at a time. > > > > > > > > The maximum number of objects that can be used in a vectored wait, and > > > > therefore the maximum that can be locked simultaneously, is 64. This number is > > > > NT's own limit. > > > > AFAICT: > > > > spin_lock(&dev->wait_all_lock); > > list_for_each_entry(entry, &obj->all_waiters, node) > > for (i=0; i<count; i++) > > spin_lock_nest_lock(q->entries[i].obj->lock, &dev->wait_all_lock); > > > > Where @count <= NTSYNC_MAX_WAIT_COUNT. > > > > So while this nests at most 65 spinlocks, there is no actual bound on > > the amount of nested lock sections in total. That is, all_waiters list > > can be grown without limits. > > > > Can we pretty please make wait_all_lock a mutex ? > > Hurmph, it's worse, you do that list walk while holding some obj->lock > spinlokc too. Still need to figure out how all that works.... So the point of having that other lock around is so that things like: try_wake_all_obj(dev, sem) try_wake_any_sem(sem) are done under the same lock? Where I seem to note that both those functions do that same list iteration. Can't you write things like: static void try_wake_all_obj(struct nysync_device *dev, struct ntsync_obj *obj, void (*wake_obj)(struct ntsync_obj *obj)) { list_for_each_entry(entry, &obj->all_waiters, node) { spin_lock(&obj->lock); try_wake_all(dev, event->q, obj); wake_obj(obj); spin_unlock(&obj->lock); } } And then instead of the above, write: try_wake_all_obj(dev, sem, wake_sem); [[ Also, should not something like try_wake_any_sem -- wake_sem in the above -- have something like: WARN_ON_ONCE(sem->type != NTSYNC_TYPE_SEM); ]]