• Bug#1105129: Please backport ntsync driver from Linux-6.14 to trixie (5

    From Piotr Morgwai Kotarbinski@1:229/2 to All on Sun May 11 22:50:01 2025
    [continued from previous message]

    + struct ntsync_q *q = entry->q;
    + int signaled = -1;
    +
    + if (!event->u.event.signaled)
    + break;
    +
    + if (atomic_try_cmpxchg(&q->signaled, &signaled, entry->index)) {
    + if (!event->u.event.manual)
    + event->u.event.signaled = false;
    + wake_up_process(q->task);
    + }
    + }
    +}
    +
    +/*
    * Actually change the semaphore state, returning -EOVERFLOW if it is made
    * invalid.
    */
    -static int post_sem_state(struct ntsync_obj *sem, __u32 count)
    +static int release_sem_state(struct ntsync_obj *sem, __u32 count)
    {
    __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)
    @@ -71,11 +404,13 @@ static int post_sem_state(struct ntsync_
    return 0;
    }

    -static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
    +static int ntsync_sem_release(struct ntsync_obj *sem, void __user *argp)
    {
    + struct ntsync_device *dev = sem->dev;
    __u32 __user *user_args = argp;
    __u32 prev_count;
    __u32 args;
    + bool all;
    int ret;

    if (copy_from_user(&args, argp, sizeof(args)))
    @@ -84,12 +419,17 @@ static int ntsync_sem_post(struct ntsync
    if (sem->type != NTSYNC_TYPE_SEM)
    return -EINVAL;

    - spin_lock(&sem->lock);
    + all = ntsync_lock_obj(dev, sem);

    prev_count = sem->u.sem.count;
    - ret = post_sem_state(sem, args);
    + ret = release_sem_state(sem, args);
    + if (!ret) {
    + if (all)
    + try_wake_all_obj(dev, sem);
    + try_wake_any_sem(sem);
    + }

    - spin_unlock(&sem->lock);
    + ntsync_unlock_obj(dev, sem, all);

    if (!ret && put_user(prev_count, user_args))
    ret = -EFAULT;
    @@ -97,13 +437,229 @@ static int ntsync_sem_post(struct ntsync
    return ret;
    }

    -static int ntsync_obj_release(struct inode *inode, struct file *file)
    +/*
    + * Actually change the mutex state, returning -EPERM if not the owner.
    + */
    +static int unlock_mutex_state(struct ntsync_obj *mutex,
    + const struct ntsync_mutex_args *args)
    {
    - struct ntsync_obj *obj = file->private_data;
    + ntsync_assert_held(mutex);
    +
    + if (mutex->u.mutex.owner != args->owner)
    + return -EPERM;
    +
    + if (!--mutex->u.mutex.count)
    + mutex->u.mutex.owner = 0;
    + return 0;
    +}
    +
    +static int ntsync_mutex_unlock(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;
    + __u32 prev_count;
    + bool all;
    + int ret;
    +
    + if (copy_from_user(&args, argp, sizeof(args)))
    + return -EFAULT;
    + if (!args.owner)
    + return -EINVAL;
    +
    + if (mutex->type != NTSYNC_TYPE_MUTEX)
    + return -EINVAL;
    +
    + all = ntsync_lock_obj(dev, mutex);
    +
    + 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);
    + }
    +
    + ntsync_unlock_obj(dev, mutex, all);
    +
    + if (!ret && put_user(prev_count, &user_args->count))
    + ret = -EFAULT;
    +
    + return ret;
    +}
    +
    +/*
    + * Actually change the mutex state to mark its owner as dead,
    + * returning -EPERM if not the owner.
    + */
    +static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner)
    +{
    + ntsync_assert_held(mutex);
    +
    + if (mutex->u.mutex.owner != owner)
    + return -EPERM;
    +
    + mutex->u.mutex.ownerdead = true;
    + mutex->u.mutex.owner = 0;
    + mutex->u.mutex.count = 0;
    + return 0;
    +}
    +
    +static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp)
    +{
    + struct ntsync_device *dev = mutex->dev;
    + __u32 owner;
    + bool all;
    + int ret;
    +
    + if (get_user(owner, (__u32 __user *)argp))
    + return -EFAULT;
    + if (!owner)
    + return -EINVAL;
    +
    + if (mutex->type != NTSYNC_TYPE_MUTEX)
    + return -EINVAL;
    +
    + all = ntsync_lock_obj(dev, mutex);
    +
    + ret = kill_mutex_state(mutex, owner);
    + if (!ret) {
    + if (all)
    + try_wake_all_obj(dev, mutex);
    + try_wake_any_mutex(mutex);
    + }
    +
    + ntsync_unlock_obj(dev, mutex, all);
    +
    + return ret;
    +}
    +
    +static int ntsync_event_set(struct ntsync_obj *event, void __user *argp, bool pulse)
    +{
    + struct ntsync_device *dev = event->dev;
    + __u32 prev_state;
    + bool all;
    +
    + if (event->type != NTSYNC_TYPE_EVENT)
    + return -EINVAL;
    +
    + all = ntsync_lock_obj(dev, event);
    +
    + 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;
    +
    + ntsync_unlock_obj(dev, event, all);
    +
    + if (put_user(prev_state, (__u32 __user *)argp))
    + return -EFAULT;
    +
    + return 0;
    +}
    +
    +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;
    +
    + all = ntsync_lock_obj(dev, event);
    +
    + prev_state = event->u.event.signaled;
    + event->u.event.signaled = false;
    +
    + ntsync_unlock_obj(dev, event, all);
    +
    + if (put_user(prev_state, (__u32 __user *)argp))
    + return -EFAULT;
    +
    + return 0;
    +}
    +
    +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;
    +
    + all = ntsync_lock_obj(dev, sem);

    + args.count = sem->u.sem.count;
    + args.max = sem->u.sem.max;
    +
    + ntsync_unlock_obj(dev, sem, all);
    +
    + if (copy_to_user(user_args, &args, sizeof(args)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +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;
    +
    + 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;
    +
    + ntsync_unlock_obj(dev, mutex, all);
    +
    + if (copy_to_user(user_args, &args, sizeof(args)))
    + return -EFAULT;
    + return ret;
    +}
    +
    +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;
    +
    + all = ntsync_lock_obj(dev, event);
    +
    + args.manual = event->u.event.manual;
    + args.signaled = event->u.event.signaled;
    +
    + ntsync_unlock_obj(dev, event, all);
    +
    + if (copy_to_user(user_args, &args, sizeof(args)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +static void ntsync_free_obj(struct ntsync_obj *obj)
    +{
    fput(obj->dev->file);
    kfree(obj);
    +}

    +static int ntsync_obj_release(struct inode *inode, struct file *file)
    +{
    + ntsync_free_obj(file->private_data);
    return 0;
    }

    @@ -114,8 +670,24 @@ static long ntsync_obj_ioctl(struct file
    void __user *argp = (void __user *)parm;

    switch (cmd) {
    - case NTSYNC_IOC_SEM_POST:
    - return ntsync_sem_post(obj, argp);
    + case NTSYNC_IOC_SEM_RELEASE:
    + return ntsync_sem_release(obj, argp);
    + case NTSYNC_IOC_SEM_READ:
    + return ntsync_sem_read(obj, argp);
    + case NTSYNC_IOC_MUTEX_UNLOCK:
    + return ntsync_mutex_unlock(obj, argp);
    + case NTSYNC_IOC_MUTEX_KILL:
    + return ntsync_mutex_kill(obj, argp);
    + case NTSYNC_IOC_MUTEX_READ:
    + return ntsync_mutex_read(obj, argp);
    + case NTSYNC_IOC_EVENT_SET:
    + return ntsync_event_set(obj, argp, false);
    + case NTSYNC_IOC_EVENT_RESET:

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: you cannot sedate... all the things you hate (1:229/2)