From 7166fde7437c2a45330530b8c86a9486de7bb486 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Thu, 23 May 2024 18:17:08 +0200 Subject: [PATCH] 6.8: Update NTSync Signed-off-by: Peter Jung --- 6.8/0009-ntsync.patch | 374 ++++++++++++++++------------ 6.8/all/0001-cachyos-base-all.patch | 374 ++++++++++++++++------------ 2 files changed, 438 insertions(+), 310 deletions(-) diff --git a/6.8/0009-ntsync.patch b/6.8/0009-ntsync.patch index 5b497f87..f8e83289 100644 --- a/6.8/0009-ntsync.patch +++ b/6.8/0009-ntsync.patch @@ -1,24 +1,24 @@ -From f78774db3d643ccd769728ce11687f81ef0a243b Mon Sep 17 00:00:00 2001 +From 53778621a2aeb70dfa59f6806b7a924e36bc58b4 Mon Sep 17 00:00:00 2001 From: Peter Jung -Date: Fri, 17 May 2024 14:28:03 +0200 -Subject: [PATCH 09/10] ntsync +Date: Mon, 20 May 2024 11:28:24 +0200 +Subject: [PATCH] ntsync Signed-off-by: Peter Jung --- Documentation/userspace-api/index.rst | 1 + .../userspace-api/ioctl/ioctl-number.rst | 2 + - Documentation/userspace-api/ntsync.rst | 399 +++++ + Documentation/userspace-api/ntsync.rst | 398 +++++ MAINTAINERS | 9 + drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + - drivers/misc/ntsync.c | 1166 ++++++++++++++ + drivers/misc/ntsync.c | 1232 +++++++++++++++ include/uapi/linux/ntsync.h | 62 + tools/testing/selftests/Makefile | 1 + .../selftests/drivers/ntsync/.gitignore | 1 + .../testing/selftests/drivers/ntsync/Makefile | 7 + tools/testing/selftests/drivers/ntsync/config | 1 + .../testing/selftests/drivers/ntsync/ntsync.c | 1407 +++++++++++++++++ - 13 files changed, 3068 insertions(+) + 13 files changed, 3133 insertions(+) create mode 100644 Documentation/userspace-api/ntsync.rst create mode 100644 drivers/misc/ntsync.c create mode 100644 include/uapi/linux/ntsync.h @@ -54,10 +54,10 @@ index 457e16f06e04..2f5c6994f042 100644 'P' 60-6F sound/sscape_ioctl.h conflict! diff --git a/Documentation/userspace-api/ntsync.rst b/Documentation/userspace-api/ntsync.rst new file mode 100644 -index 000000000000..202c2350d3af +index 000000000000..767844637a7d --- /dev/null +++ b/Documentation/userspace-api/ntsync.rst -@@ -0,0 +1,399 @@ +@@ -0,0 +1,398 @@ +=================================== +NT synchronization primitive driver +=================================== @@ -81,10 +81,11 @@ index 000000000000..202c2350d3af +semaphores, mutexes, and events. + +A semaphore holds a single volatile 32-bit counter, and a static 32-bit -+integer denoting the maximum value. It is considered signaled when the -+counter is nonzero. The counter is decremented by one when a wait is -+satisfied. Both the initial and maximum count are established when the -+semaphore is created. ++integer denoting the maximum value. It is considered signaled (that is, ++can be acquired without contention, or will wake up a waiting thread) ++when the counter is nonzero. The counter is decremented by one when a ++wait is satisfied. Both the initial and maximum count are established ++when the semaphore is created. + +A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit +identifier denoting its owner. A mutex is considered signaled when its @@ -104,10 +105,11 @@ index 000000000000..202c2350d3af +driver does not actually validate that a calling thread provides +consistent or unique identifiers. + -+An event holds a volatile boolean state denoting whether it is signaled -+or not. There are two types of events, auto-reset and manual-reset. An -+auto-reset event is designaled when a wait is satisfied; a manual-reset -+event is not. The event type is specified when the event is created. ++An event is similar to a semaphore with a maximum count of one. It holds ++a volatile boolean state denoting whether it is signaled or not. There ++are two types of events, auto-reset and manual-reset. An auto-reset ++event is designaled when a wait is satisfied; a manual-reset event is ++not. The event type is specified when the event is created. + +Unless specified otherwise, all operations on an object are atomic and +totally ordered with respect to other operations on the same object. @@ -400,8 +402,7 @@ index 000000000000..202c2350d3af + operations on the same object. If two wait operations (with different + ``owner`` identifiers) are queued on the same mutex, only one is + signaled. If two wait operations are queued on the same semaphore, -+ and a value of one is posted to it, only one is signaled. The order -+ in which threads are signaled is not specified. ++ and a value of one is posted to it, only one is signaled. + + If an abandoned mutex is acquired, the ioctl fails with + ``EOWNERDEAD``. Although this is a failure return, the function may @@ -410,9 +411,7 @@ index 000000000000..202c2350d3af + abandoned, and ``index`` is still set to the index of the mutex. + + The ``alert`` argument is an "extra" event which can terminate the -+ wait, independently of all other objects. If members of ``objs`` and -+ ``alert`` are both simultaneously signaled, a member of ``objs`` will -+ always be given priority and acquired first. ++ wait, independently of all other objects. + + It is valid to pass the same object more than once, including by + passing the same event in the ``objs`` array and in ``alert``. If a @@ -513,10 +512,10 @@ index ea6ea5bbbc9c..153a3f4837e8 100644 obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..19fd70ac3f50 +index 000000000000..87a24798a5c7 --- /dev/null +++ b/drivers/misc/ntsync.c -@@ -0,0 +1,1166 @@ +@@ -0,0 +1,1232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives @@ -532,6 +531,7 @@ index 000000000000..19fd70ac3f50 +#include +#include +#include ++#include +#include +#include +#include @@ -562,6 +562,7 @@ index 000000000000..19fd70ac3f50 + +struct ntsync_obj { + spinlock_t lock; ++ int dev_locked; + + enum ntsync_type type; + @@ -576,7 +577,7 @@ index 000000000000..19fd70ac3f50 + } sem; + struct { + __u32 count; -+ __u32 owner; ++ pid_t owner; + bool ownerdead; + } mutex; + struct { @@ -605,10 +606,6 @@ index 000000000000..19fd70ac3f50 + * Therefore we first check whether all_hint is zero, and, if it is, + * we skip trying to wake "all" waiters. + * -+ * This hint isn't protected by any lock. It might change during the -+ * course of a wake, but there's no meaningful race there; it's only a -+ * hint. -+ * + * Since wait requests must originate from user-space threads, we're + * limited here by PID_MAX_LIMIT, so there's no risk of overflow. + */ @@ -646,19 +643,111 @@ index 000000000000..19fd70ac3f50 + * If one thread is trying to acquire several objects, another thread + * cannot touch the object at the same time. + * -+ * We achieve this by grabbing multiple object locks at the same time. -+ * However, this creates a lock ordering problem. To solve that problem, -+ * wait_all_lock is taken first whenever multiple objects must be locked -+ * at the same time. ++ * This device-wide lock is used to serialize wait-for-all ++ * operations, and operations on an object that is involved in a ++ * wait-for-all. + */ -+ spinlock_t wait_all_lock; ++ struct mutex wait_all_lock; + + struct file *file; +}; + ++/* ++ * Single objects are locked using obj->lock. ++ * ++ * Multiple objects are 'locked' while holding dev->wait_all_lock. ++ * In this case however, individual objects are not locked by holding ++ * obj->lock, but by setting obj->dev_locked. ++ * ++ * This means that in order to lock a single object, the sequence is slightly ++ * more complicated than usual. Specifically it needs to check obj->dev_locked ++ * after acquiring obj->lock, if set, it needs to drop the lock and acquire ++ * dev->wait_all_lock in order to serialize against the multi-object operation. ++ */ ++ ++static void dev_lock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ lockdep_assert_held(&dev->wait_all_lock); ++ lockdep_assert(obj->dev == dev); ++ spin_lock(&obj->lock); ++ /* ++ * By setting obj->dev_locked inside obj->lock, it is ensured that ++ * anyone holding obj->lock must see the value. ++ */ ++ obj->dev_locked = 1; ++ spin_unlock(&obj->lock); ++} ++ ++static void dev_unlock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ lockdep_assert_held(&dev->wait_all_lock); ++ lockdep_assert(obj->dev == dev); ++ spin_lock(&obj->lock); ++ obj->dev_locked = 0; ++ spin_unlock(&obj->lock); ++} ++ ++static void obj_lock(struct ntsync_obj *obj) ++{ ++ struct ntsync_device *dev = obj->dev; ++ ++ for (;;) { ++ spin_lock(&obj->lock); ++ if (likely(!obj->dev_locked)) ++ break; ++ ++ spin_unlock(&obj->lock); ++ mutex_lock(&dev->wait_all_lock); ++ spin_lock(&obj->lock); ++ /* ++ * obj->dev_locked should be set and released under the same ++ * wait_all_lock section, since we now own this lock, it should ++ * be clear. ++ */ ++ lockdep_assert(!obj->dev_locked); ++ spin_unlock(&obj->lock); ++ mutex_unlock(&dev->wait_all_lock); ++ } ++} ++ ++static void obj_unlock(struct ntsync_obj *obj) ++{ ++ spin_unlock(&obj->lock); ++} ++ ++static bool ntsync_lock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ bool all; ++ ++ obj_lock(obj); ++ all = atomic_read(&obj->all_hint); ++ if (unlikely(all)) { ++ obj_unlock(obj); ++ mutex_lock(&dev->wait_all_lock); ++ dev_lock_obj(dev, obj); ++ } ++ ++ return all; ++} ++ ++static void ntsync_unlock_obj(struct ntsync_device *dev, struct ntsync_obj *obj, bool all) ++{ ++ if (all) { ++ dev_unlock_obj(dev, obj); ++ mutex_unlock(&dev->wait_all_lock); ++ } else { ++ obj_unlock(obj); ++ } ++} ++ ++#define ntsync_assert_held(obj) \ ++ lockdep_assert((lockdep_is_held(&(obj)->lock) != LOCK_STATE_NOT_HELD) || \ ++ ((lockdep_is_held(&(obj)->dev->wait_all_lock) != LOCK_STATE_NOT_HELD) && \ ++ (obj)->dev_locked)) ++ +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ -+ lockdep_assert_held(&obj->lock); ++ ntsync_assert_held(obj); + + switch (obj->type) { + case NTSYNC_TYPE_SEM: @@ -690,11 +779,11 @@ index 000000000000..19fd70ac3f50 + + lockdep_assert_held(&dev->wait_all_lock); + if (locked_obj) -+ lockdep_assert_held(&locked_obj->lock); ++ lockdep_assert(locked_obj->dev_locked); + + for (i = 0; i < count; i++) { + if (q->entries[i].obj != locked_obj) -+ spin_lock_nest_lock(&q->entries[i].obj->lock, &dev->wait_all_lock); ++ dev_lock_obj(dev, q->entries[i].obj); + } + + for (i = 0; i < count; i++) { @@ -730,7 +819,7 @@ index 000000000000..19fd70ac3f50 + + for (i = 0; i < count; i++) { + if (q->entries[i].obj != locked_obj) -+ spin_unlock(&q->entries[i].obj->lock); ++ dev_unlock_obj(dev, q->entries[i].obj); + } +} + @@ -739,7 +828,7 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry; + + lockdep_assert_held(&dev->wait_all_lock); -+ lockdep_assert_held(&obj->lock); ++ lockdep_assert(obj->dev_locked); + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); @@ -749,7 +838,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&sem->lock); ++ ntsync_assert_held(sem); ++ lockdep_assert(sem->type == NTSYNC_TYPE_SEM); + + list_for_each_entry(entry, &sem->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -769,7 +859,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); ++ lockdep_assert(mutex->type == NTSYNC_TYPE_MUTEX); + + list_for_each_entry(entry, &mutex->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -795,7 +886,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&event->lock); ++ ntsync_assert_held(event); ++ lockdep_assert(event->type == NTSYNC_TYPE_EVENT); + + list_for_each_entry(entry, &event->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -820,7 +912,7 @@ index 000000000000..19fd70ac3f50 +{ + __u32 sum; + -+ lockdep_assert_held(&sem->lock); ++ ntsync_assert_held(sem); + + if (check_add_overflow(sem->u.sem.count, count, &sum) || + sum > sem->u.sem.max) @@ -836,6 +928,7 @@ index 000000000000..19fd70ac3f50 + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -844,30 +937,18 @@ index 000000000000..19fd70ac3f50 + if (sem->type != NTSYNC_TYPE_SEM) + return -EINVAL; + -+ if (atomic_read(&sem->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, sem); + -+ prev_count = sem->u.sem.count; -+ ret = post_sem_state(sem, args); -+ if (!ret) { ++ prev_count = sem->u.sem.count; ++ ret = post_sem_state(sem, args); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, sem); -+ try_wake_any_sem(sem); -+ } -+ -+ spin_unlock(&sem->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = post_sem_state(sem, args); -+ if (!ret) -+ try_wake_any_sem(sem); -+ -+ spin_unlock(&sem->lock); ++ try_wake_any_sem(sem); + } + ++ ntsync_unlock_obj(dev, sem, all); ++ + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; + @@ -880,7 +961,7 @@ index 000000000000..19fd70ac3f50 +static int unlock_mutex_state(struct ntsync_obj *mutex, + const struct ntsync_mutex_args *args) +{ -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); + + if (mutex->u.mutex.owner != args->owner) + return -EPERM; @@ -896,6 +977,7 @@ index 000000000000..19fd70ac3f50 + struct ntsync_device *dev = mutex->dev; + struct ntsync_mutex_args args; + __u32 prev_count; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -906,30 +988,18 @@ index 000000000000..19fd70ac3f50 + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, mutex); + -+ prev_count = mutex->u.mutex.count; -+ ret = unlock_mutex_state(mutex, &args); -+ if (!ret) { ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = unlock_mutex_state(mutex, &args); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); ++ try_wake_any_mutex(mutex); + } + ++ ntsync_unlock_obj(dev, mutex, all); ++ + if (!ret && put_user(prev_count, &user_args->count)) + ret = -EFAULT; + @@ -942,7 +1012,7 @@ index 000000000000..19fd70ac3f50 + */ +static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner) +{ -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); + + if (mutex->u.mutex.owner != owner) + return -EPERM; @@ -957,6 +1027,7 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_device *dev = mutex->dev; + __u32 owner; ++ bool all; + int ret; + + if (get_user(owner, (__u32 __user *)argp)) @@ -967,28 +1038,17 @@ index 000000000000..19fd70ac3f50 + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, mutex); + -+ ret = kill_mutex_state(mutex, owner); -+ if (!ret) { ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ ret = kill_mutex_state(mutex, owner); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); ++ try_wake_any_mutex(mutex); + } + ++ ntsync_unlock_obj(dev, mutex, all); ++ + return ret; +} + @@ -996,34 +1056,22 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_device *dev = event->dev; + __u32 prev_state; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + -+ if (atomic_read(&event->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, event); + -+ prev_state = event->u.event.signaled; -+ event->u.event.signaled = true; ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ if (all) + try_wake_all_obj(dev, event); -+ try_wake_any_event(event); -+ if (pulse) -+ event->u.event.signaled = false; -+ -+ spin_unlock(&event->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&event->lock); ++ try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + -+ prev_state = event->u.event.signaled; -+ event->u.event.signaled = true; -+ try_wake_any_event(event); -+ if (pulse) -+ event->u.event.signaled = false; -+ -+ spin_unlock(&event->lock); -+ } ++ ntsync_unlock_obj(dev, event, all); + + if (put_user(prev_state, (__u32 __user *)argp)) + return -EFAULT; @@ -1033,17 +1081,19 @@ index 000000000000..19fd70ac3f50 + +static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) +{ ++ struct ntsync_device *dev = event->dev; + __u32 prev_state; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + -+ spin_lock(&event->lock); ++ all = ntsync_lock_obj(dev, event); + + prev_state = event->u.event.signaled; + event->u.event.signaled = false; + -+ spin_unlock(&event->lock); ++ ntsync_unlock_obj(dev, event, all); + + if (put_user(prev_state, (__u32 __user *)argp)) + return -EFAULT; @@ -1054,16 +1104,21 @@ index 000000000000..19fd70ac3f50 +static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) +{ + struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_device *dev = sem->dev; + struct ntsync_sem_args args; ++ bool all; + + if (sem->type != NTSYNC_TYPE_SEM) + return -EINVAL; + + args.sem = 0; -+ spin_lock(&sem->lock); ++ ++ all = ntsync_lock_obj(dev, sem); ++ + args.count = sem->u.sem.count; + args.max = sem->u.sem.max; -+ spin_unlock(&sem->lock); ++ ++ ntsync_unlock_obj(dev, sem, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -1073,18 +1128,23 @@ index 000000000000..19fd70ac3f50 +static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) +{ + struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_device *dev = mutex->dev; + struct ntsync_mutex_args args; ++ bool all; + int ret; + + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + + args.mutex = 0; -+ spin_lock(&mutex->lock); ++ ++ all = ntsync_lock_obj(dev, mutex); ++ + args.count = mutex->u.mutex.count; + args.owner = mutex->u.mutex.owner; + ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0; -+ spin_unlock(&mutex->lock); ++ ++ ntsync_unlock_obj(dev, mutex, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -1094,16 +1154,21 @@ index 000000000000..19fd70ac3f50 +static int ntsync_event_read(struct ntsync_obj *event, void __user *argp) +{ + struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_device *dev = event->dev; + struct ntsync_event_args args; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + + args.event = 0; -+ spin_lock(&event->lock); ++ ++ all = ntsync_lock_obj(dev, event); ++ + args.manual = event->u.event.manual; + args.signaled = event->u.event.signaled; -+ spin_unlock(&event->lock); ++ ++ ntsync_unlock_obj(dev, event, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -1344,9 +1409,6 @@ index 000000000000..19fd70ac3f50 + __u32 total_count; + __u32 i, j; + -+ if (!args->owner) -+ return -EINVAL; -+ + if (args->pad || (args->flags & ~NTSYNC_WAIT_REALTIME)) + return -EINVAL; + @@ -1426,6 +1488,7 @@ index 000000000000..19fd70ac3f50 + __u32 i, total_count; + struct ntsync_q *q; + int signaled; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -1445,9 +1508,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + + /* @@ -1464,9 +1527,9 @@ index 000000000000..19fd70ac3f50 + if (atomic_read(&q->signaled) != -1) + break; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + try_wake_any_obj(obj); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + + /* sleep */ @@ -1479,9 +1542,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + list_del(&entry->node); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + + put_obj(obj); + } @@ -1520,7 +1583,7 @@ index 000000000000..19fd70ac3f50 + + /* queue ourselves */ + -+ spin_lock(&dev->wait_all_lock); ++ mutex_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; @@ -1539,16 +1602,16 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[args.count]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ dev_lock_obj(dev, obj); + list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); ++ dev_unlock_obj(dev, obj); + } + + /* check if we are already signaled */ + + try_wake_all(dev, q, NULL); + -+ spin_unlock(&dev->wait_all_lock); ++ mutex_unlock(&dev->wait_all_lock); + + /* + * Check if the alert event is signaled, making sure to do so only @@ -1559,9 +1622,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_obj *obj = q->entries[args.count].obj; + + if (atomic_read(&q->signaled) == -1) { -+ spin_lock(&obj->lock); ++ bool all = ntsync_lock_obj(dev, obj); + try_wake_any_obj(obj); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + } + @@ -1571,7 +1634,7 @@ index 000000000000..19fd70ac3f50 + + /* and finally, unqueue */ + -+ spin_lock(&dev->wait_all_lock); ++ mutex_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; @@ -1587,19 +1650,21 @@ index 000000000000..19fd70ac3f50 + + put_obj(obj); + } ++ ++ mutex_unlock(&dev->wait_all_lock); ++ + if (args.alert) { + struct ntsync_q_entry *entry = &q->entries[args.count]; + struct ntsync_obj *obj = entry->obj; ++ bool all; + -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, obj); + list_del(&entry->node); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + + put_obj(obj); + } + -+ spin_unlock(&dev->wait_all_lock); -+ + signaled = atomic_read(&q->signaled); + if (signaled != -1) { + struct ntsync_wait_args __user *user_args = argp; @@ -1625,7 +1690,7 @@ index 000000000000..19fd70ac3f50 + if (!dev) + return -ENOMEM; + -+ spin_lock_init(&dev->wait_all_lock); ++ mutex_init(&dev->wait_all_lock); + + file->private_data = dev; + dev->file = file; @@ -1685,7 +1750,7 @@ index 000000000000..19fd70ac3f50 +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h new file mode 100644 -index 000000000000..f21dbac42164 +index 000000000000..4a8095a3fc34 --- /dev/null +++ b/include/uapi/linux/ntsync.h @@ -0,0 +1,62 @@ @@ -1725,9 +1790,9 @@ index 000000000000..f21dbac42164 + __u64 timeout; + __u64 objs; + __u32 count; -+ __u32 owner; + __u32 index; + __u32 flags; ++ __u32 owner; + __u32 alert; + __u32 pad; +}; @@ -3205,4 +3270,3 @@ index 000000000000..5fa2c9a0768c +TEST_HARNESS_MAIN -- 2.45.1 - diff --git a/6.8/all/0001-cachyos-base-all.patch b/6.8/all/0001-cachyos-base-all.patch index 98c3a1a0..ade1b62b 100644 --- a/6.8/all/0001-cachyos-base-all.patch +++ b/6.8/all/0001-cachyos-base-all.patch @@ -21678,27 +21678,27 @@ index faad00cce269..c7c9eb656468 100644 -- 2.45.1 -From f78774db3d643ccd769728ce11687f81ef0a243b Mon Sep 17 00:00:00 2001 +From 53778621a2aeb70dfa59f6806b7a924e36bc58b4 Mon Sep 17 00:00:00 2001 From: Peter Jung -Date: Fri, 17 May 2024 14:28:03 +0200 -Subject: [PATCH 09/10] ntsync +Date: Mon, 20 May 2024 11:28:24 +0200 +Subject: [PATCH] ntsync Signed-off-by: Peter Jung --- Documentation/userspace-api/index.rst | 1 + .../userspace-api/ioctl/ioctl-number.rst | 2 + - Documentation/userspace-api/ntsync.rst | 399 +++++ + Documentation/userspace-api/ntsync.rst | 398 +++++ MAINTAINERS | 9 + drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + - drivers/misc/ntsync.c | 1166 ++++++++++++++ + drivers/misc/ntsync.c | 1232 +++++++++++++++ include/uapi/linux/ntsync.h | 62 + tools/testing/selftests/Makefile | 1 + .../selftests/drivers/ntsync/.gitignore | 1 + .../testing/selftests/drivers/ntsync/Makefile | 7 + tools/testing/selftests/drivers/ntsync/config | 1 + .../testing/selftests/drivers/ntsync/ntsync.c | 1407 +++++++++++++++++ - 13 files changed, 3068 insertions(+) + 13 files changed, 3133 insertions(+) create mode 100644 Documentation/userspace-api/ntsync.rst create mode 100644 drivers/misc/ntsync.c create mode 100644 include/uapi/linux/ntsync.h @@ -21734,10 +21734,10 @@ index 457e16f06e04..2f5c6994f042 100644 'P' 60-6F sound/sscape_ioctl.h conflict! diff --git a/Documentation/userspace-api/ntsync.rst b/Documentation/userspace-api/ntsync.rst new file mode 100644 -index 000000000000..202c2350d3af +index 000000000000..767844637a7d --- /dev/null +++ b/Documentation/userspace-api/ntsync.rst -@@ -0,0 +1,399 @@ +@@ -0,0 +1,398 @@ +=================================== +NT synchronization primitive driver +=================================== @@ -21761,10 +21761,11 @@ index 000000000000..202c2350d3af +semaphores, mutexes, and events. + +A semaphore holds a single volatile 32-bit counter, and a static 32-bit -+integer denoting the maximum value. It is considered signaled when the -+counter is nonzero. The counter is decremented by one when a wait is -+satisfied. Both the initial and maximum count are established when the -+semaphore is created. ++integer denoting the maximum value. It is considered signaled (that is, ++can be acquired without contention, or will wake up a waiting thread) ++when the counter is nonzero. The counter is decremented by one when a ++wait is satisfied. Both the initial and maximum count are established ++when the semaphore is created. + +A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit +identifier denoting its owner. A mutex is considered signaled when its @@ -21784,10 +21785,11 @@ index 000000000000..202c2350d3af +driver does not actually validate that a calling thread provides +consistent or unique identifiers. + -+An event holds a volatile boolean state denoting whether it is signaled -+or not. There are two types of events, auto-reset and manual-reset. An -+auto-reset event is designaled when a wait is satisfied; a manual-reset -+event is not. The event type is specified when the event is created. ++An event is similar to a semaphore with a maximum count of one. It holds ++a volatile boolean state denoting whether it is signaled or not. There ++are two types of events, auto-reset and manual-reset. An auto-reset ++event is designaled when a wait is satisfied; a manual-reset event is ++not. The event type is specified when the event is created. + +Unless specified otherwise, all operations on an object are atomic and +totally ordered with respect to other operations on the same object. @@ -22080,8 +22082,7 @@ index 000000000000..202c2350d3af + operations on the same object. If two wait operations (with different + ``owner`` identifiers) are queued on the same mutex, only one is + signaled. If two wait operations are queued on the same semaphore, -+ and a value of one is posted to it, only one is signaled. The order -+ in which threads are signaled is not specified. ++ and a value of one is posted to it, only one is signaled. + + If an abandoned mutex is acquired, the ioctl fails with + ``EOWNERDEAD``. Although this is a failure return, the function may @@ -22090,9 +22091,7 @@ index 000000000000..202c2350d3af + abandoned, and ``index`` is still set to the index of the mutex. + + The ``alert`` argument is an "extra" event which can terminate the -+ wait, independently of all other objects. If members of ``objs`` and -+ ``alert`` are both simultaneously signaled, a member of ``objs`` will -+ always be given priority and acquired first. ++ wait, independently of all other objects. + + It is valid to pass the same object more than once, including by + passing the same event in the ``objs`` array and in ``alert``. If a @@ -22193,10 +22192,10 @@ index ea6ea5bbbc9c..153a3f4837e8 100644 obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..19fd70ac3f50 +index 000000000000..87a24798a5c7 --- /dev/null +++ b/drivers/misc/ntsync.c -@@ -0,0 +1,1166 @@ +@@ -0,0 +1,1232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives @@ -22212,6 +22211,7 @@ index 000000000000..19fd70ac3f50 +#include +#include +#include ++#include +#include +#include +#include @@ -22242,6 +22242,7 @@ index 000000000000..19fd70ac3f50 + +struct ntsync_obj { + spinlock_t lock; ++ int dev_locked; + + enum ntsync_type type; + @@ -22256,7 +22257,7 @@ index 000000000000..19fd70ac3f50 + } sem; + struct { + __u32 count; -+ __u32 owner; ++ pid_t owner; + bool ownerdead; + } mutex; + struct { @@ -22285,10 +22286,6 @@ index 000000000000..19fd70ac3f50 + * Therefore we first check whether all_hint is zero, and, if it is, + * we skip trying to wake "all" waiters. + * -+ * This hint isn't protected by any lock. It might change during the -+ * course of a wake, but there's no meaningful race there; it's only a -+ * hint. -+ * + * Since wait requests must originate from user-space threads, we're + * limited here by PID_MAX_LIMIT, so there's no risk of overflow. + */ @@ -22326,19 +22323,111 @@ index 000000000000..19fd70ac3f50 + * If one thread is trying to acquire several objects, another thread + * cannot touch the object at the same time. + * -+ * We achieve this by grabbing multiple object locks at the same time. -+ * However, this creates a lock ordering problem. To solve that problem, -+ * wait_all_lock is taken first whenever multiple objects must be locked -+ * at the same time. ++ * This device-wide lock is used to serialize wait-for-all ++ * operations, and operations on an object that is involved in a ++ * wait-for-all. + */ -+ spinlock_t wait_all_lock; ++ struct mutex wait_all_lock; + + struct file *file; +}; + ++/* ++ * Single objects are locked using obj->lock. ++ * ++ * Multiple objects are 'locked' while holding dev->wait_all_lock. ++ * In this case however, individual objects are not locked by holding ++ * obj->lock, but by setting obj->dev_locked. ++ * ++ * This means that in order to lock a single object, the sequence is slightly ++ * more complicated than usual. Specifically it needs to check obj->dev_locked ++ * after acquiring obj->lock, if set, it needs to drop the lock and acquire ++ * dev->wait_all_lock in order to serialize against the multi-object operation. ++ */ ++ ++static void dev_lock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ lockdep_assert_held(&dev->wait_all_lock); ++ lockdep_assert(obj->dev == dev); ++ spin_lock(&obj->lock); ++ /* ++ * By setting obj->dev_locked inside obj->lock, it is ensured that ++ * anyone holding obj->lock must see the value. ++ */ ++ obj->dev_locked = 1; ++ spin_unlock(&obj->lock); ++} ++ ++static void dev_unlock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ lockdep_assert_held(&dev->wait_all_lock); ++ lockdep_assert(obj->dev == dev); ++ spin_lock(&obj->lock); ++ obj->dev_locked = 0; ++ spin_unlock(&obj->lock); ++} ++ ++static void obj_lock(struct ntsync_obj *obj) ++{ ++ struct ntsync_device *dev = obj->dev; ++ ++ for (;;) { ++ spin_lock(&obj->lock); ++ if (likely(!obj->dev_locked)) ++ break; ++ ++ spin_unlock(&obj->lock); ++ mutex_lock(&dev->wait_all_lock); ++ spin_lock(&obj->lock); ++ /* ++ * obj->dev_locked should be set and released under the same ++ * wait_all_lock section, since we now own this lock, it should ++ * be clear. ++ */ ++ lockdep_assert(!obj->dev_locked); ++ spin_unlock(&obj->lock); ++ mutex_unlock(&dev->wait_all_lock); ++ } ++} ++ ++static void obj_unlock(struct ntsync_obj *obj) ++{ ++ spin_unlock(&obj->lock); ++} ++ ++static bool ntsync_lock_obj(struct ntsync_device *dev, struct ntsync_obj *obj) ++{ ++ bool all; ++ ++ obj_lock(obj); ++ all = atomic_read(&obj->all_hint); ++ if (unlikely(all)) { ++ obj_unlock(obj); ++ mutex_lock(&dev->wait_all_lock); ++ dev_lock_obj(dev, obj); ++ } ++ ++ return all; ++} ++ ++static void ntsync_unlock_obj(struct ntsync_device *dev, struct ntsync_obj *obj, bool all) ++{ ++ if (all) { ++ dev_unlock_obj(dev, obj); ++ mutex_unlock(&dev->wait_all_lock); ++ } else { ++ obj_unlock(obj); ++ } ++} ++ ++#define ntsync_assert_held(obj) \ ++ lockdep_assert((lockdep_is_held(&(obj)->lock) != LOCK_STATE_NOT_HELD) || \ ++ ((lockdep_is_held(&(obj)->dev->wait_all_lock) != LOCK_STATE_NOT_HELD) && \ ++ (obj)->dev_locked)) ++ +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ -+ lockdep_assert_held(&obj->lock); ++ ntsync_assert_held(obj); + + switch (obj->type) { + case NTSYNC_TYPE_SEM: @@ -22370,11 +22459,11 @@ index 000000000000..19fd70ac3f50 + + lockdep_assert_held(&dev->wait_all_lock); + if (locked_obj) -+ lockdep_assert_held(&locked_obj->lock); ++ lockdep_assert(locked_obj->dev_locked); + + for (i = 0; i < count; i++) { + if (q->entries[i].obj != locked_obj) -+ spin_lock_nest_lock(&q->entries[i].obj->lock, &dev->wait_all_lock); ++ dev_lock_obj(dev, q->entries[i].obj); + } + + for (i = 0; i < count; i++) { @@ -22410,7 +22499,7 @@ index 000000000000..19fd70ac3f50 + + for (i = 0; i < count; i++) { + if (q->entries[i].obj != locked_obj) -+ spin_unlock(&q->entries[i].obj->lock); ++ dev_unlock_obj(dev, q->entries[i].obj); + } +} + @@ -22419,7 +22508,7 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry; + + lockdep_assert_held(&dev->wait_all_lock); -+ lockdep_assert_held(&obj->lock); ++ lockdep_assert(obj->dev_locked); + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); @@ -22429,7 +22518,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&sem->lock); ++ ntsync_assert_held(sem); ++ lockdep_assert(sem->type == NTSYNC_TYPE_SEM); + + list_for_each_entry(entry, &sem->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -22449,7 +22539,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); ++ lockdep_assert(mutex->type == NTSYNC_TYPE_MUTEX); + + list_for_each_entry(entry, &mutex->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -22475,7 +22566,8 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_q_entry *entry; + -+ lockdep_assert_held(&event->lock); ++ ntsync_assert_held(event); ++ lockdep_assert(event->type == NTSYNC_TYPE_EVENT); + + list_for_each_entry(entry, &event->any_waiters, node) { + struct ntsync_q *q = entry->q; @@ -22500,7 +22592,7 @@ index 000000000000..19fd70ac3f50 +{ + __u32 sum; + -+ lockdep_assert_held(&sem->lock); ++ ntsync_assert_held(sem); + + if (check_add_overflow(sem->u.sem.count, count, &sum) || + sum > sem->u.sem.max) @@ -22516,6 +22608,7 @@ index 000000000000..19fd70ac3f50 + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -22524,30 +22617,18 @@ index 000000000000..19fd70ac3f50 + if (sem->type != NTSYNC_TYPE_SEM) + return -EINVAL; + -+ if (atomic_read(&sem->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, sem); + -+ prev_count = sem->u.sem.count; -+ ret = post_sem_state(sem, args); -+ if (!ret) { ++ prev_count = sem->u.sem.count; ++ ret = post_sem_state(sem, args); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, sem); -+ try_wake_any_sem(sem); -+ } -+ -+ spin_unlock(&sem->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = post_sem_state(sem, args); -+ if (!ret) -+ try_wake_any_sem(sem); -+ -+ spin_unlock(&sem->lock); ++ try_wake_any_sem(sem); + } + ++ ntsync_unlock_obj(dev, sem, all); ++ + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; + @@ -22560,7 +22641,7 @@ index 000000000000..19fd70ac3f50 +static int unlock_mutex_state(struct ntsync_obj *mutex, + const struct ntsync_mutex_args *args) +{ -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); + + if (mutex->u.mutex.owner != args->owner) + return -EPERM; @@ -22576,6 +22657,7 @@ index 000000000000..19fd70ac3f50 + struct ntsync_device *dev = mutex->dev; + struct ntsync_mutex_args args; + __u32 prev_count; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -22586,30 +22668,18 @@ index 000000000000..19fd70ac3f50 + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, mutex); + -+ prev_count = mutex->u.mutex.count; -+ ret = unlock_mutex_state(mutex, &args); -+ if (!ret) { ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = unlock_mutex_state(mutex, &args); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); ++ try_wake_any_mutex(mutex); + } + ++ ntsync_unlock_obj(dev, mutex, all); ++ + if (!ret && put_user(prev_count, &user_args->count)) + ret = -EFAULT; + @@ -22622,7 +22692,7 @@ index 000000000000..19fd70ac3f50 + */ +static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner) +{ -+ lockdep_assert_held(&mutex->lock); ++ ntsync_assert_held(mutex); + + if (mutex->u.mutex.owner != owner) + return -EPERM; @@ -22637,6 +22707,7 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_device *dev = mutex->dev; + __u32 owner; ++ bool all; + int ret; + + if (get_user(owner, (__u32 __user *)argp)) @@ -22647,28 +22718,17 @@ index 000000000000..19fd70ac3f50 + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, mutex); + -+ ret = kill_mutex_state(mutex, owner); -+ if (!ret) { ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) { ++ if (all) + try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ ret = kill_mutex_state(mutex, owner); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); ++ try_wake_any_mutex(mutex); + } + ++ ntsync_unlock_obj(dev, mutex, all); ++ + return ret; +} + @@ -22676,34 +22736,22 @@ index 000000000000..19fd70ac3f50 +{ + struct ntsync_device *dev = event->dev; + __u32 prev_state; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + -+ if (atomic_read(&event->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, event); + -+ prev_state = event->u.event.signaled; -+ event->u.event.signaled = true; ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ if (all) + try_wake_all_obj(dev, event); -+ try_wake_any_event(event); -+ if (pulse) -+ event->u.event.signaled = false; -+ -+ spin_unlock(&event->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&event->lock); -+ -+ prev_state = event->u.event.signaled; -+ event->u.event.signaled = true; -+ try_wake_any_event(event); -+ if (pulse) -+ event->u.event.signaled = false; ++ try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + -+ spin_unlock(&event->lock); -+ } ++ ntsync_unlock_obj(dev, event, all); + + if (put_user(prev_state, (__u32 __user *)argp)) + return -EFAULT; @@ -22713,17 +22761,19 @@ index 000000000000..19fd70ac3f50 + +static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) +{ ++ struct ntsync_device *dev = event->dev; + __u32 prev_state; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + -+ spin_lock(&event->lock); ++ all = ntsync_lock_obj(dev, event); + + prev_state = event->u.event.signaled; + event->u.event.signaled = false; + -+ spin_unlock(&event->lock); ++ ntsync_unlock_obj(dev, event, all); + + if (put_user(prev_state, (__u32 __user *)argp)) + return -EFAULT; @@ -22734,16 +22784,21 @@ index 000000000000..19fd70ac3f50 +static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) +{ + struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_device *dev = sem->dev; + struct ntsync_sem_args args; ++ bool all; + + if (sem->type != NTSYNC_TYPE_SEM) + return -EINVAL; + + args.sem = 0; -+ spin_lock(&sem->lock); ++ ++ all = ntsync_lock_obj(dev, sem); ++ + args.count = sem->u.sem.count; + args.max = sem->u.sem.max; -+ spin_unlock(&sem->lock); ++ ++ ntsync_unlock_obj(dev, sem, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -22753,18 +22808,23 @@ index 000000000000..19fd70ac3f50 +static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) +{ + struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_device *dev = mutex->dev; + struct ntsync_mutex_args args; ++ bool all; + int ret; + + if (mutex->type != NTSYNC_TYPE_MUTEX) + return -EINVAL; + + args.mutex = 0; -+ spin_lock(&mutex->lock); ++ ++ all = ntsync_lock_obj(dev, mutex); ++ + args.count = mutex->u.mutex.count; + args.owner = mutex->u.mutex.owner; + ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0; -+ spin_unlock(&mutex->lock); ++ ++ ntsync_unlock_obj(dev, mutex, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -22774,16 +22834,21 @@ index 000000000000..19fd70ac3f50 +static int ntsync_event_read(struct ntsync_obj *event, void __user *argp) +{ + struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_device *dev = event->dev; + struct ntsync_event_args args; ++ bool all; + + if (event->type != NTSYNC_TYPE_EVENT) + return -EINVAL; + + args.event = 0; -+ spin_lock(&event->lock); ++ ++ all = ntsync_lock_obj(dev, event); ++ + args.manual = event->u.event.manual; + args.signaled = event->u.event.signaled; -+ spin_unlock(&event->lock); ++ ++ ntsync_unlock_obj(dev, event, all); + + if (copy_to_user(user_args, &args, sizeof(args))) + return -EFAULT; @@ -23024,9 +23089,6 @@ index 000000000000..19fd70ac3f50 + __u32 total_count; + __u32 i, j; + -+ if (!args->owner) -+ return -EINVAL; -+ + if (args->pad || (args->flags & ~NTSYNC_WAIT_REALTIME)) + return -EINVAL; + @@ -23106,6 +23168,7 @@ index 000000000000..19fd70ac3f50 + __u32 i, total_count; + struct ntsync_q *q; + int signaled; ++ bool all; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) @@ -23125,9 +23188,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + + /* @@ -23144,9 +23207,9 @@ index 000000000000..19fd70ac3f50 + if (atomic_read(&q->signaled) != -1) + break; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + try_wake_any_obj(obj); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + + /* sleep */ @@ -23159,9 +23222,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock(&obj->lock); ++ all = ntsync_lock_obj(dev, obj); + list_del(&entry->node); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + + put_obj(obj); + } @@ -23200,7 +23263,7 @@ index 000000000000..19fd70ac3f50 + + /* queue ourselves */ + -+ spin_lock(&dev->wait_all_lock); ++ mutex_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; @@ -23219,16 +23282,16 @@ index 000000000000..19fd70ac3f50 + struct ntsync_q_entry *entry = &q->entries[args.count]; + struct ntsync_obj *obj = entry->obj; + -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ dev_lock_obj(dev, obj); + list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); ++ dev_unlock_obj(dev, obj); + } + + /* check if we are already signaled */ + + try_wake_all(dev, q, NULL); + -+ spin_unlock(&dev->wait_all_lock); ++ mutex_unlock(&dev->wait_all_lock); + + /* + * Check if the alert event is signaled, making sure to do so only @@ -23239,9 +23302,9 @@ index 000000000000..19fd70ac3f50 + struct ntsync_obj *obj = q->entries[args.count].obj; + + if (atomic_read(&q->signaled) == -1) { -+ spin_lock(&obj->lock); ++ bool all = ntsync_lock_obj(dev, obj); + try_wake_any_obj(obj); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + } + } + @@ -23251,7 +23314,7 @@ index 000000000000..19fd70ac3f50 + + /* and finally, unqueue */ + -+ spin_lock(&dev->wait_all_lock); ++ mutex_lock(&dev->wait_all_lock); + + for (i = 0; i < args.count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; @@ -23267,19 +23330,21 @@ index 000000000000..19fd70ac3f50 + + put_obj(obj); + } ++ ++ mutex_unlock(&dev->wait_all_lock); ++ + if (args.alert) { + struct ntsync_q_entry *entry = &q->entries[args.count]; + struct ntsync_obj *obj = entry->obj; ++ bool all; + -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ all = ntsync_lock_obj(dev, obj); + list_del(&entry->node); -+ spin_unlock(&obj->lock); ++ ntsync_unlock_obj(dev, obj, all); + + put_obj(obj); + } + -+ spin_unlock(&dev->wait_all_lock); -+ + signaled = atomic_read(&q->signaled); + if (signaled != -1) { + struct ntsync_wait_args __user *user_args = argp; @@ -23305,7 +23370,7 @@ index 000000000000..19fd70ac3f50 + if (!dev) + return -ENOMEM; + -+ spin_lock_init(&dev->wait_all_lock); ++ mutex_init(&dev->wait_all_lock); + + file->private_data = dev; + dev->file = file; @@ -23365,7 +23430,7 @@ index 000000000000..19fd70ac3f50 +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h new file mode 100644 -index 000000000000..f21dbac42164 +index 000000000000..4a8095a3fc34 --- /dev/null +++ b/include/uapi/linux/ntsync.h @@ -0,0 +1,62 @@ @@ -23405,9 +23470,9 @@ index 000000000000..f21dbac42164 + __u64 timeout; + __u64 objs; + __u32 count; -+ __u32 owner; + __u32 index; + __u32 flags; ++ __u32 owner; + __u32 alert; + __u32 pad; +}; @@ -24885,7 +24950,6 @@ index 000000000000..5fa2c9a0768c +TEST_HARNESS_MAIN -- 2.45.1 - From 02ff530c07f9271a085e94f51bce3424c85edff5 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Fri, 17 May 2024 14:28:37 +0200