]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
authorElizabeth Figura <zfigura@codeweavers.com>
Fri, 13 Dec 2024 19:34:47 +0000 (13:34 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Jan 2025 12:18:10 +0000 (13:18 +0100)
This corresponds to the NT syscall NtReleaseMutant().

This syscall decrements the mutex's recursion count by one, and returns the
previous value. If the mutex is not owned by the current task, the function
instead fails and returns -EPERM.

Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
Link: https://lore.kernel.org/r/20241213193511.457338-7-zfigura@codeweavers.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/ntsync.c
include/uapi/linux/ntsync.h

index a2826dbff2f46c2d958e4a119ee04e7472461052..33e26240d9e7c9ac1bcb8adb2ee7ae0b03c63451 100644 (file)
@@ -396,6 +396,57 @@ static int ntsync_sem_release(struct ntsync_obj *sem, void __user *argp)
        return ret;
 }
 
+/*
+ * 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)
+{
+       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;
+}
+
 static int ntsync_obj_release(struct inode *inode, struct file *file)
 {
        struct ntsync_obj *obj = file->private_data;
@@ -415,6 +466,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
        switch (cmd) {
        case NTSYNC_IOC_SEM_RELEASE:
                return ntsync_sem_release(obj, argp);
+       case NTSYNC_IOC_MUTEX_UNLOCK:
+               return ntsync_mutex_unlock(obj, argp);
        default:
                return -ENOIOCTLCMD;
        }
index bb7fb94f585619c9e125f90cff2eff210b98bddb..9186304b253c640b262e37794d292e06ee80ed18 100644 (file)
@@ -40,5 +40,6 @@ struct ntsync_wait_args {
 #define NTSYNC_IOC_CREATE_MUTEX                _IOW ('N', 0x84, struct ntsync_mutex_args)
 
 #define NTSYNC_IOC_SEM_RELEASE         _IOWR('N', 0x81, __u32)
+#define NTSYNC_IOC_MUTEX_UNLOCK                _IOWR('N', 0x85, struct ntsync_mutex_args)
 
 #endif