Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2024
- 6 participants
- 79 messages
[PATCH v2 04/31] ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
by Elizabeth Figura
This corresponds to part of the functionality of the NT syscall
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
the third argument (wait_any) is TRUE, and it does not handle alertable waits.
Those features have been split out into separate patches to ease review.
NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike
poll(), it "consumes" objects when they are signaled. For semaphores, this means
decreasing one from the internal counter. At most one object can be consumed by
this function.
Up to 64 objects can be waited on at once. As soon as one is signaled, the
object with the lowest index is consumed, and that index is returned via the
"index" field.
A timeout is supported. The timeout is passed as a u64 nanosecond value, which
represents absolute time measured against the MONOTONIC clock. If U64_MAX is
passed, the ioctl waits indefinitely.
This ioctl validates that all objects belong to the relevant device. This is not
necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be
necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch.
Wait ioctls need to take a temporary reference to each object being waited on.
As with the device, the reference count of struct file is used for ntsync_obj.
Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
---
drivers/misc/ntsync.c | 239 ++++++++++++++++++++++++++++++++++++
include/uapi/linux/ntsync.h | 12 ++
2 files changed, 251 insertions(+)
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
index 3c2f743c58b0..ad93ca0f8b84 100644
--- a/drivers/misc/ntsync.c
+++ b/drivers/misc/ntsync.c
@@ -6,11 +6,16 @@
*/
#include <linux/anon_inodes.h>
+#include <linux/atomic.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/overflow.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <uapi/linux/ntsync.h>
@@ -30,6 +35,8 @@ enum ntsync_type {
*
* Both rely on struct file for reference counting. Individual
* ntsync_obj objects take a reference to the device when created.
+ * Wait operations take a reference to each object being waited on for
+ * the duration of the wait.
*/
struct ntsync_obj {
@@ -47,12 +54,55 @@ struct ntsync_obj {
__u32 max;
} sem;
} u;
+
+ struct list_head any_waiters;
+};
+
+struct ntsync_q_entry {
+ struct list_head node;
+ struct ntsync_q *q;
+ struct ntsync_obj *obj;
+ __u32 index;
+};
+
+struct ntsync_q {
+ struct task_struct *task;
+ __u32 owner;
+
+ /*
+ * Protected via atomic_cmpxchg(). Only the thread that wins the
+ * compare-and-swap may actually change object states and wake this
+ * task.
+ */
+ atomic_t signaled;
+
+ __u32 count;
+ struct ntsync_q_entry entries[];
};
struct ntsync_device {
struct file *file;
};
+static void try_wake_any_sem(struct ntsync_obj *sem)
+{
+ struct ntsync_q_entry *entry;
+
+ lockdep_assert_held(&sem->lock);
+
+ list_for_each_entry(entry, &sem->any_waiters, node) {
+ struct ntsync_q *q = entry->q;
+
+ if (!sem->u.sem.count)
+ break;
+
+ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) {
+ sem->u.sem.count--;
+ wake_up_process(q->task);
+ }
+ }
+}
+
/*
* Actually change the semaphore state, returning -EOVERFLOW if it is made
* invalid.
@@ -88,6 +138,8 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
prev_count = sem->u.sem.count;
ret = post_sem_state(sem, args);
+ if (!ret)
+ try_wake_any_sem(sem);
spin_unlock(&sem->lock);
@@ -141,6 +193,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
obj->dev = dev;
get_file(dev->file);
spin_lock_init(&obj->lock);
+ INIT_LIST_HEAD(&obj->any_waiters);
return obj;
}
@@ -191,6 +244,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
return put_user(fd, &user_args->sem);
}
+static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
+{
+ struct file *file = fget(fd);
+ struct ntsync_obj *obj;
+
+ if (file->f_op != &ntsync_obj_fops) {
+ fput(file);
+ return NULL;
+ }
+
+ obj = file->private_data;
+ if (obj->dev != dev) {
+ fput(file);
+ return NULL;
+ }
+
+ return obj;
+}
+
+static void put_obj(struct ntsync_obj *obj)
+{
+ fput(obj->file);
+}
+
+static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_args *args)
+{
+ ktime_t timeout = ns_to_ktime(args->timeout);
+ ktime_t *timeout_ptr;
+ int ret = 0;
+
+ timeout_ptr = (args->timeout == U64_MAX ? NULL : &timeout);
+
+ do {
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&q->signaled) != -1) {
+ ret = 0;
+ break;
+ }
+ ret = schedule_hrtimeout(timeout_ptr, HRTIMER_MODE_ABS);
+ } while (ret < 0);
+ __set_current_state(TASK_RUNNING);
+
+ return ret;
+}
+
+/*
+ * Allocate and initialize the ntsync_q structure, but do not queue us yet.
+ */
+static int setup_wait(struct ntsync_device *dev,
+ const struct ntsync_wait_args *args,
+ struct ntsync_q **ret_q)
+{
+ const __u32 count = args->count;
+ int fds[NTSYNC_MAX_WAIT_COUNT];
+ struct ntsync_q *q;
+ __u32 i, j;
+
+ if (!args->owner || args->pad)
+ return -EINVAL;
+
+ if (args->count > NTSYNC_MAX_WAIT_COUNT)
+ return -EINVAL;
+
+ if (copy_from_user(fds, u64_to_user_ptr(args->objs),
+ array_size(count, sizeof(*fds))))
+ return -EFAULT;
+
+ q = kmalloc(struct_size(q, entries, count), GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ q->task = current;
+ q->owner = args->owner;
+ atomic_set(&q->signaled, -1);
+ q->count = count;
+
+ for (i = 0; i < count; i++) {
+ struct ntsync_q_entry *entry = &q->entries[i];
+ struct ntsync_obj *obj = get_obj(dev, fds[i]);
+
+ if (!obj)
+ goto err;
+
+ entry->obj = obj;
+ entry->q = q;
+ entry->index = i;
+ }
+
+ *ret_q = q;
+ return 0;
+
+err:
+ for (j = 0; j < i; j++)
+ put_obj(q->entries[j].obj);
+ kfree(q);
+ return -EINVAL;
+}
+
+static void try_wake_any_obj(struct ntsync_obj *obj)
+{
+ switch (obj->type) {
+ case NTSYNC_TYPE_SEM:
+ try_wake_any_sem(obj);
+ break;
+ }
+}
+
+static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
+{
+ struct ntsync_wait_args args;
+ struct ntsync_q *q;
+ int signaled;
+ __u32 i;
+ int ret;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ ret = setup_wait(dev, &args, &q);
+ if (ret < 0)
+ return ret;
+
+ /* queue ourselves */
+
+ for (i = 0; i < args.count; i++) {
+ struct ntsync_q_entry *entry = &q->entries[i];
+ struct ntsync_obj *obj = entry->obj;
+
+ spin_lock(&obj->lock);
+ list_add_tail(&entry->node, &obj->any_waiters);
+ spin_unlock(&obj->lock);
+ }
+
+ /* check if we are already signaled */
+
+ for (i = 0; i < args.count; i++) {
+ struct ntsync_obj *obj = q->entries[i].obj;
+
+ if (atomic_read(&q->signaled) != -1)
+ break;
+
+ spin_lock(&obj->lock);
+ try_wake_any_obj(obj);
+ spin_unlock(&obj->lock);
+ }
+
+ /* sleep */
+
+ ret = ntsync_schedule(q, &args);
+
+ /* and finally, unqueue */
+
+ for (i = 0; i < args.count; i++) {
+ struct ntsync_q_entry *entry = &q->entries[i];
+ struct ntsync_obj *obj = entry->obj;
+
+ spin_lock(&obj->lock);
+ list_del(&entry->node);
+ spin_unlock(&obj->lock);
+
+ put_obj(obj);
+ }
+
+ signaled = atomic_read(&q->signaled);
+ if (signaled != -1) {
+ struct ntsync_wait_args __user *user_args = argp;
+
+ /* even if we caught a signal, we need to communicate success */
+ ret = 0;
+
+ if (put_user(signaled, &user_args->index))
+ ret = -EFAULT;
+ } else if (!ret) {
+ ret = -ETIMEDOUT;
+ }
+
+ kfree(q);
+ return ret;
+}
+
static int ntsync_char_open(struct inode *inode, struct file *file)
{
struct ntsync_device *dev;
@@ -222,6 +459,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case NTSYNC_IOC_CREATE_SEM:
return ntsync_create_sem(dev, argp);
+ case NTSYNC_IOC_WAIT_ANY:
+ return ntsync_wait_any(dev, argp);
default:
return -ENOIOCTLCMD;
}
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
index dcfa38fdc93c..56b643fab611 100644
--- a/include/uapi/linux/ntsync.h
+++ b/include/uapi/linux/ntsync.h
@@ -16,7 +16,19 @@ struct ntsync_sem_args {
__u32 max;
};
+struct ntsync_wait_args {
+ __u64 timeout;
+ __u64 objs;
+ __u32 count;
+ __u32 owner;
+ __u32 index;
+ __u32 pad;
+};
+
+#define NTSYNC_MAX_WAIT_COUNT 64
+
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
+#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
--
2.43.0
Feb. 19, 2024
[PATCH v2 03/31] ntsync: Introduce NTSYNC_IOC_SEM_POST.
by Elizabeth Figura
This corresponds to the NT syscall NtReleaseSemaphore().
This increases the semaphore's internal counter by the given value, and returns
the previous value. If the counter would overflow the defined maximum, the
function instead fails and returns -EOVERFLOW.
Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
---
drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++--
include/uapi/linux/ntsync.h | 2 ++
2 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
index 20158ec148bc..3c2f743c58b0 100644
--- a/drivers/misc/ntsync.c
+++ b/drivers/misc/ntsync.c
@@ -10,7 +10,9 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <uapi/linux/ntsync.h>
#define NTSYNC_NAME "ntsync"
@@ -31,23 +33,70 @@ enum ntsync_type {
*/
struct ntsync_obj {
+ spinlock_t lock;
+
enum ntsync_type type;
+ struct file *file;
+ struct ntsync_device *dev;
+
+ /* The following fields are protected by the object lock. */
union {
struct {
__u32 count;
__u32 max;
} sem;
} u;
-
- struct file *file;
- struct ntsync_device *dev;
};
struct ntsync_device {
struct file *file;
};
+/*
+ * Actually change the semaphore state, returning -EOVERFLOW if it is made
+ * invalid.
+ */
+static int post_sem_state(struct ntsync_obj *sem, __u32 count)
+{
+ __u32 sum;
+
+ lockdep_assert_held(&sem->lock);
+
+ if (check_add_overflow(sem->u.sem.count, count, &sum) ||
+ sum > sem->u.sem.max)
+ return -EOVERFLOW;
+
+ sem->u.sem.count = sum;
+ return 0;
+}
+
+static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
+{
+ __u32 __user *user_args = argp;
+ __u32 prev_count;
+ __u32 args;
+ int ret;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ if (sem->type != NTSYNC_TYPE_SEM)
+ return -EINVAL;
+
+ spin_lock(&sem->lock);
+
+ prev_count = sem->u.sem.count;
+ ret = post_sem_state(sem, args);
+
+ spin_unlock(&sem->lock);
+
+ if (!ret && put_user(prev_count, user_args))
+ ret = -EFAULT;
+
+ return ret;
+}
+
static int ntsync_obj_release(struct inode *inode, struct file *file)
{
struct ntsync_obj *obj = file->private_data;
@@ -58,9 +107,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file)
return 0;
}
+static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
+ unsigned long parm)
+{
+ struct ntsync_obj *obj = file->private_data;
+ void __user *argp = (void __user *)parm;
+
+ switch (cmd) {
+ case NTSYNC_IOC_SEM_POST:
+ return ntsync_sem_post(obj, argp);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
static const struct file_operations ntsync_obj_fops = {
.owner = THIS_MODULE,
.release = ntsync_obj_release,
+ .unlocked_ioctl = ntsync_obj_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.llseek = no_llseek,
};
@@ -75,6 +140,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
obj->type = type;
obj->dev = dev;
get_file(dev->file);
+ spin_lock_init(&obj->lock);
return obj;
}
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
index 6a4867a6c97b..dcfa38fdc93c 100644
--- a/include/uapi/linux/ntsync.h
+++ b/include/uapi/linux/ntsync.h
@@ -18,4 +18,6 @@ struct ntsync_sem_args {
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
+#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
+
#endif
--
2.43.0
Feb. 19, 2024
[PATCH v2 02/31] ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
by Elizabeth Figura
This corresponds to the NT syscall NtCreateSemaphore().
Semaphores are one of three types of object to be implemented in this driver,
the others being mutexes and events.
An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
when the counter is nonzero. The counter has a maximum value which is specified
at creation time. The initial value of the semaphore is also specified at
creation time. There are no restrictions on the maximum and initial value.
Each object is exposed as an file, to which any number of fds may be opened.
When all fds are closed, the object is deleted.
Objects hold a pointer to the ntsync_device that created them. The device's
reference count is driven by struct file.
Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
---
.../userspace-api/ioctl/ioctl-number.rst | 2 +
drivers/misc/ntsync.c | 131 ++++++++++++++++++
include/uapi/linux/ntsync.h | 21 +++
3 files changed, 154 insertions(+)
create mode 100644 include/uapi/linux/ntsync.h
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 457e16f06e04..2f5c6994f042 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -173,6 +173,8 @@ Code Seq# Include File Comments
'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
'N' 00-1F drivers/usb/scanner.h
'N' 40-7F drivers/block/nvme.c
+'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
+ <mailto:wine-devel(a)winehq.org>
'O' 00-06 mtd/ubi-user.h UBI
'P' all linux/soundcard.h conflict!
'P' 60-6F sound/sscape_ioctl.h conflict!
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
index bd76e653d83e..20158ec148bc 100644
--- a/drivers/misc/ntsync.c
+++ b/drivers/misc/ntsync.c
@@ -5,26 +5,157 @@
* Copyright (C) 2024 Elizabeth Figura <zfigura(a)codeweavers.com>
*/
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
+#include <linux/slab.h>
+#include <uapi/linux/ntsync.h>
#define NTSYNC_NAME "ntsync"
+enum ntsync_type {
+ NTSYNC_TYPE_SEM,
+};
+
+/*
+ * Individual synchronization primitives are represented by
+ * struct ntsync_obj, and each primitive is backed by a file.
+ *
+ * The whole namespace is represented by a struct ntsync_device also
+ * backed by a file.
+ *
+ * Both rely on struct file for reference counting. Individual
+ * ntsync_obj objects take a reference to the device when created.
+ */
+
+struct ntsync_obj {
+ enum ntsync_type type;
+
+ union {
+ struct {
+ __u32 count;
+ __u32 max;
+ } sem;
+ } u;
+
+ struct file *file;
+ struct ntsync_device *dev;
+};
+
+struct ntsync_device {
+ struct file *file;
+};
+
+static int ntsync_obj_release(struct inode *inode, struct file *file)
+{
+ struct ntsync_obj *obj = file->private_data;
+
+ fput(obj->dev->file);
+ kfree(obj);
+
+ return 0;
+}
+
+static const struct file_operations ntsync_obj_fops = {
+ .owner = THIS_MODULE,
+ .release = ntsync_obj_release,
+ .llseek = no_llseek,
+};
+
+static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
+ enum ntsync_type type)
+{
+ struct ntsync_obj *obj;
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (!obj)
+ return NULL;
+ obj->type = type;
+ obj->dev = dev;
+ get_file(dev->file);
+
+ return obj;
+}
+
+static int ntsync_obj_get_fd(struct ntsync_obj *obj)
+{
+ struct file *file;
+ int fd;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+ file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR);
+ if (IS_ERR(file)) {
+ put_unused_fd(fd);
+ return PTR_ERR(file);
+ }
+ obj->file = file;
+ fd_install(fd, file);
+
+ return fd;
+}
+
+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
+{
+ struct ntsync_sem_args __user *user_args = argp;
+ struct ntsync_sem_args args;
+ struct ntsync_obj *sem;
+ int fd;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ if (args.count > args.max)
+ return -EINVAL;
+
+ sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM);
+ if (!sem)
+ return -ENOMEM;
+ sem->u.sem.count = args.count;
+ sem->u.sem.max = args.max;
+ fd = ntsync_obj_get_fd(sem);
+ if (fd < 0) {
+ kfree(sem);
+ return fd;
+ }
+
+ return put_user(fd, &user_args->sem);
+}
+
static int ntsync_char_open(struct inode *inode, struct file *file)
{
+ struct ntsync_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ file->private_data = dev;
+ dev->file = file;
return nonseekable_open(inode, file);
}
static int ntsync_char_release(struct inode *inode, struct file *file)
{
+ struct ntsync_device *dev = file->private_data;
+
+ kfree(dev);
+
return 0;
}
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
unsigned long parm)
{
+ struct ntsync_device *dev = file->private_data;
+ void __user *argp = (void __user *)parm;
+
switch (cmd) {
+ case NTSYNC_IOC_CREATE_SEM:
+ return ntsync_create_sem(dev, argp);
default:
return -ENOIOCTLCMD;
}
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
new file mode 100644
index 000000000000..6a4867a6c97b
--- /dev/null
+++ b/include/uapi/linux/ntsync.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Kernel support for NT synchronization primitive emulation
+ *
+ * Copyright (C) 2021-2022 Elizabeth Figura <zfigura(a)codeweavers.com>
+ */
+
+#ifndef __LINUX_NTSYNC_H
+#define __LINUX_NTSYNC_H
+
+#include <linux/types.h>
+
+struct ntsync_sem_args {
+ __u32 sem;
+ __u32 count;
+ __u32 max;
+};
+
+#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
+
+#endif
--
2.43.0
Feb. 19, 2024
[PATCH v2 01/31] ntsync: Introduce the ntsync driver and character device.
by Elizabeth Figura
ntsync uses a misc device as the simplest and least intrusive uAPI interface.
Each file description on the device represents an isolated NT instance, intended
to correspond to a single NT virtual machine.
Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
---
drivers/misc/Kconfig | 11 +++++++++
drivers/misc/Makefile | 1 +
drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 64 insertions(+)
create mode 100644 drivers/misc/ntsync.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4fb291f0bf7c..801ed229ed7d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -506,6 +506,17 @@ config OPEN_DICE
If unsure, say N.
+config NTSYNC
+ tristate "NT synchronization primitive emulation"
+ help
+ This module provides kernel support for emulation of Windows NT
+ synchronization primitives. It is not a hardware driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ntsync.
+
+ If unsure, say N.
+
config VCPU_STALL_DETECTOR
tristate "Guest vCPU stall detector"
depends on OF && HAS_IOMEM
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index ea6ea5bbbc9c..153a3f4837e8 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_PVPANIC) += pvpanic/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
+obj-$(CONFIG_NTSYNC) += ntsync.o
obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
obj-$(CONFIG_OPEN_DICE) += open-dice.o
obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
new file mode 100644
index 000000000000..bd76e653d83e
--- /dev/null
+++ b/drivers/misc/ntsync.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ntsync.c - Kernel driver for NT synchronization primitives
+ *
+ * Copyright (C) 2024 Elizabeth Figura <zfigura(a)codeweavers.com>
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+
+#define NTSYNC_NAME "ntsync"
+
+static int ntsync_char_open(struct inode *inode, struct file *file)
+{
+ return nonseekable_open(inode, file);
+}
+
+static int ntsync_char_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
+ unsigned long parm)
+{
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static const struct file_operations ntsync_fops = {
+ .owner = THIS_MODULE,
+ .open = ntsync_char_open,
+ .release = ntsync_char_release,
+ .unlocked_ioctl = ntsync_char_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice ntsync_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = NTSYNC_NAME,
+ .fops = &ntsync_fops,
+};
+
+module_misc_device(ntsync_misc);
+
+MODULE_AUTHOR("Elizabeth Figura <zfigura(a)codeweavers.com>");
+MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives");
+MODULE_LICENSE("GPL");
--
2.43.0
Feb. 19, 2024
[PATCH v2 00/31] NT synchronization primitive driver
by Elizabeth Figura
This patch series introduces a new char misc driver, /dev/ntsync, which is used
to implement Windows NT synchronization primitives.
This was previously submitted as an RFC [1]. Since there were no major changes
requested to the last RFC revision, I've stripped the RFC prefix.
[1] https://lore.kernel.org/lkml/20240131021356.10322-1-zfigura(a)codeweavers.c…
== Background ==
The Wine project emulates the Windows API in user space. One particular part of
that API, namely the NT synchronization primitives, have historically been
implemented via RPC to a dedicated "kernel" process. However, more recent
applications use these APIs more strenuously, and the overhead of RPC has become
a bottleneck.
The NT synchronization APIs are too complex to implement on top of existing
primitives without sacrificing correctness. Certain operations, such as
NtPulseEvent() or the "wait-for-all" mode of NtWaitForMultipleObjects(), require
direct control over the underlying wait queue, and implementing a wait queue
sufficiently robust for Wine in user space is not possible. This proposed
driver, therefore, implements the problematic interfaces directly in the Linux
kernel.
This driver was presented at Linux Plumbers Conference 2023. For those further
interested in the history of synchronization in Wine and past attempts to solve
this problem in user space, a recording of the presentation can be viewed here:
https://www.youtube.com/watch?v=NjU4nyWyhU8
== Performance ==
The gain in performance varies wildly depending on the application in question
and the user's hardware. For some games NT synchronization is not a bottleneck
and no change can be observed, but for others frame rate improvements of 50 to
150 percent are not atypical. The following table lists frame rate measurements
from a variety of games on a variety of hardware, taken by users Dmitry
Skvortsov, FuzzyQuils, OnMars, and myself:
Game Upstream ntsync improvement
===========================================================================
Anger Foot 69 99 43%
Call of Juarez 99.8 224.1 125%
Dirt 3 110.6 860.7 678%
Forza Horizon 5 108 160 48%
Lara Croft: Temple of Osiris 141 326 131%
Metro 2033 164.4 199.2 21%
Resident Evil 2 26 77 196%
The Crew 26 51 96%
Tiny Tina's Wonderlands 130 360 177%
Total War Saga: Troy 109 146 34%
===========================================================================
== Patches ==
The intended semantics of the patches are broadly intended to match those of the
corresponding Windows functions. For those not already familiar with the Windows
functions (or their undocumented behaviour), patch 31/31 provides a detailed
specification, and individual patches also include a brief description of the
API they are implementing.
The patches making use of this driver in Wine can be retrieved or browsed here:
https://repo.or.cz/wine/zf.git/shortlog/refs/heads/ntsync5
== Implementation ==
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.
The acquisition of multiple spinlocks will degrade performance. This is a
conscious choice, however. Wait-for-all is known to be a very rare operation
in practice, especially with counts that approach the maximum, and it is the
intent of the ntsync driver to optimize wait-for-any at the expense of
wait-for-all as much as possible.
* NT mutexes are tied to their threads on an OS level, and the kernel includes
builtin support for "robust" mutexes. In order to keep the ntsync driver
self-contained and avoid touching more code than necessary, it does not hook
into task exit nor use pids.
Instead, the user space emulator is expected to manage thread IDs and pass
them as an argument to any relevant functions; this is the "owner" field of
ntsync_wait_args and ntsync_mutex_args.
When the emulator detects that a thread dies, it should therefore call
NTSYNC_IOC_MUTEX_KILL on any open mutexes.
* ntsync is module-capable mostly because there was nothing preventing it, and
because it aided development. It is not a hard requirement, though.
== Previous versions ==
Changes from v1:
* Fix a broken rebase that stole part of the Kconfig documentation from the
neighbouring entry, per Randy Dunlap.
* Add my email address to copyright and MODULE_AUTHOR lines, per Randy Dunlap.
* Document the reference counting behaviour more clearly, per Greg
Kroah-Hartman.
* Hopefully submit all the patches this time the right way.
* Link to v1: https://lore.kernel.org/lkml/20240214233645.9273-1-zfigura(a)codeweavers.co…
* Link to RFC v2: https://lore.kernel.org/lkml/20240131021356.10322-1-zfigura(a)codeweavers.c…
* Link to RFC v1: https://lore.kernel.org/lkml/20240124004028.16826-1-zfigura(a)codeweavers.c…
Elizabeth Figura (31):
ntsync: Introduce the ntsync driver and character device.
ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
ntsync: Introduce NTSYNC_IOC_SEM_POST.
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
ntsync: Introduce NTSYNC_IOC_EVENT_SET.
ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
ntsync: Introduce NTSYNC_IOC_SEM_READ.
ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
ntsync: Introduce NTSYNC_IOC_EVENT_READ.
ntsync: Introduce alertable waits.
ntsync: Allow waits to use the REALTIME clock.
selftests: ntsync: Add some tests for semaphore state.
selftests: ntsync: Add some tests for mutex state.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for manual-reset event state.
selftests: ntsync: Add some tests for auto-reset event state.
selftests: ntsync: Add some tests for wakeup signaling with events.
selftests: ntsync: Add tests for alertable waits.
selftests: ntsync: Add some tests for wakeup signaling via alerts.
selftests: ntsync: Add a stress test for contended waits.
maintainers: Add an entry for ntsync.
docs: ntsync: Add documentation for the ntsync uAPI.
Elizabeth Figura (31):
ntsync: Introduce the ntsync driver and character device.
ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
ntsync: Introduce NTSYNC_IOC_SEM_POST.
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
ntsync: Introduce NTSYNC_IOC_EVENT_SET.
ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
ntsync: Introduce NTSYNC_IOC_SEM_READ.
ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
ntsync: Introduce NTSYNC_IOC_EVENT_READ.
ntsync: Introduce alertable waits.
ntsync: Allow waits to use the REALTIME clock.
selftests: ntsync: Add some tests for semaphore state.
selftests: ntsync: Add some tests for mutex state.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for manual-reset event state.
selftests: ntsync: Add some tests for auto-reset event state.
selftests: ntsync: Add some tests for wakeup signaling with events.
selftests: ntsync: Add tests for alertable waits.
selftests: ntsync: Add some tests for wakeup signaling via alerts.
selftests: ntsync: Add a stress test for contended waits.
maintainers: Add an entry for ntsync.
docs: ntsync: Add documentation for the ntsync uAPI.
Documentation/userspace-api/index.rst | 1 +
.../userspace-api/ioctl/ioctl-number.rst | 2 +
Documentation/userspace-api/ntsync.rst | 399 +++++
MAINTAINERS | 9 +
drivers/misc/Kconfig | 11 +
drivers/misc/Makefile | 1 +
drivers/misc/ntsync.c | 1159 ++++++++++++++
include/uapi/linux/ntsync.h | 62 +
tools/testing/selftests/Makefile | 1 +
.../testing/selftests/drivers/ntsync/Makefile | 8 +
tools/testing/selftests/drivers/ntsync/config | 1 +
.../testing/selftests/drivers/ntsync/ntsync.c | 1407 +++++++++++++++++
12 files changed, 3061 insertions(+)
create mode 100644 Documentation/userspace-api/ntsync.rst
create mode 100644 drivers/misc/ntsync.c
create mode 100644 include/uapi/linux/ntsync.h
create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile
create mode 100644 tools/testing/selftests/drivers/ntsync/config
create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c
base-commit: 8d11c6d9b14f7a87f65529cb33edc5fed846ed9d
--
2.43.0
Feb. 19, 2024
Re: [PATCH 02/31] ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
by Elizabeth Figura
On Saturday, 17 February 2024 02:03:15 CST Greg Kroah-Hartman wrote:
> On Thu, Feb 15, 2024 at 01:22:01PM -0600, Elizabeth Figura wrote:
> > On Thursday, 15 February 2024 01:28:32 CST Greg Kroah-Hartman wrote:
> > > On Wed, Feb 14, 2024 at 05:36:38PM -0600, Elizabeth Figura wrote:
> > > > This corresponds to the NT syscall NtCreateSemaphore().
> > > >
> > > > Semaphores are one of three types of object to be implemented in this driver,
> > > > the others being mutexes and events.
> > > >
> > > > An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
> > > > when the counter is nonzero. The counter has a maximum value which is specified
> > > > at creation time. The initial value of the semaphore is also specified at
> > > > creation time. There are no restrictions on the maximum and initial value.
> > > >
> > > > Each object is exposed as an file, to which any number of fds may be opened.
> > > > When all fds are closed, the object is deleted.
> > > >
> > > > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > > > ---
> > > > .../userspace-api/ioctl/ioctl-number.rst | 2 +
> > > > drivers/misc/ntsync.c | 120 ++++++++++++++++++
> > > > include/uapi/linux/ntsync.h | 21 +++
> > > > 3 files changed, 143 insertions(+)
> > > > create mode 100644 include/uapi/linux/ntsync.h
> > > >
> > > > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > index 457e16f06e04..2f5c6994f042 100644
> > > > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > @@ -173,6 +173,8 @@ Code Seq# Include File Comments
> > > > 'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
> > > > 'N' 00-1F drivers/usb/scanner.h
> > > > 'N' 40-7F drivers/block/nvme.c
> > > > +'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
> > > > + <mailto:wine-devel(a)winehq.org>
> > > > 'O' 00-06 mtd/ubi-user.h UBI
> > > > 'P' all linux/soundcard.h conflict!
> > > > 'P' 60-6F sound/sscape_ioctl.h conflict!
> > > > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > > > index e4969ef90722..3ad86d98b82d 100644
> > > > --- a/drivers/misc/ntsync.c
> > > > +++ b/drivers/misc/ntsync.c
> > > > @@ -5,26 +5,146 @@
> > > > * Copyright (C) 2024 Elizabeth Figura
> > > > */
> > > >
> > > > +#include <linux/anon_inodes.h>
> > > > +#include <linux/file.h>
> > > > #include <linux/fs.h>
> > > > #include <linux/miscdevice.h>
> > > > #include <linux/module.h>
> > > > +#include <linux/slab.h>
> > > > +#include <uapi/linux/ntsync.h>
> > > >
> > > > #define NTSYNC_NAME "ntsync"
> > > >
> > > > +enum ntsync_type {
> > > > + NTSYNC_TYPE_SEM,
> > > > +};
> > > > +
> > > > +struct ntsync_obj {
> > > > + enum ntsync_type type;
> > > > +
> > > > + union {
> > > > + struct {
> > > > + __u32 count;
> > > > + __u32 max;
> > > > + } sem;
> > > > + } u;
> > > > +
> > > > + struct file *file;
> > > > + struct ntsync_device *dev;
> > > > +};
> > > > +
> > > > +struct ntsync_device {
> > > > + struct file *file;
> > > > +};
> > >
> > > No reference counting is needed for your ntsync_device? Or are you
> > > relying on the reference counting of struct file here?
> > >
> > > You pass around pointers to this structure, and save it off into other
> > > structures, how do you know it is "safe" to do so?
> >
> > Yes, this relies on the reference counting of struct file. The sync
> > objects (semaphore etc.) grab a reference when they're created, via
> > get_file(), and release it when they're destroyed. This reference is
> > taken from within ioctls on the ntsync_device, so the file must be
> > valid when we grab a reference. Maybe I'm missing something, though?
>
> If the reference count is driven by struct file, that's fine, and great,
> otherwise you end up with two different reference counts and keeping
> them in sync is impossible.
>
> But as it wasn't obvious, a comment somewhere here would be helpful for
> reviewing and figuring out how this all works in 4 years when someone
> has to touch it again.
Ah, makes sense. I'll add comments to be clearer about the refcounting
relationships, thanks.
--Zeb
Feb. 19, 2024
Moving Wine Mono
by Esme Povirk
I'm starting the process of moving Wine Mono off of my personal Github
account and onto the Winehq Gitlab in the organization here:
https://gitlab.winehq.org/wine-mono
Obviously, I haven't gotten very far yet, as the main repo for Wine Mono
itself doesn't exist, but the intent is to move every submodule that we've
forked (as well as projects I've started just for Wine Mono) over to
Winehq, set up CI there, and archive my Github repos. The procedure for
contributing will be to fork the repository and create merge requests
(which I will also do for my own contributions, once we're set up for it).
I'm also rethinking the branch structure. The Mono repo will have three
mainline branches: upstream (the upstream project as it exists in the
official repos), main (upstream plus further development that I will review
and maintain), and wine-mono (main plus changes we have only in Wine). The
"upstream" and "main" branches should be the same for any upstream that is
responsive and cares about preserving ABI compatibility (right now that's
just FNA and monoDX). The wine-mono branch should only exist for projects
that have a general use case in which Wine's changes don't make sense (I
think that's just Mono, corefx, and FNA).
The answer to "which branch should I send my MR to?" will almost always be
main. There should be a very few changes on wine-mono only. The ones I can
think of off the top of my head are: enabling native dll loading without
coree hooks, renaming a bunch of assemblies to start with "WineMono.",
winforms hooks in FNA, and proprietary media formats in FNA. Over the years
we've been doing a lot of development on top of Mono that, in my opinion,
belongs upstream.
I will also accept changes to Mono that have nothing to do with Wine, such
as winforms changes, and I will try to keep the main branch working for use
cases outside of Wine and Windows, to the extent that it's feasible (there
are a bunch of configurations I can't easily test, like PowerPC, ARM,
Android, and iOS, and I can't see myself doing development to support new
platforms like M1). I don't know how much development interest there will
be, but I seem to be in a unique position to maintain Framework Mono, and I
think it is needed.
Feb. 16, 2024
Re: [PATCH 02/31] ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
by Elizabeth Figura
On Thursday, 15 February 2024 01:28:32 CST Greg Kroah-Hartman wrote:
> On Wed, Feb 14, 2024 at 05:36:38PM -0600, Elizabeth Figura wrote:
> > This corresponds to the NT syscall NtCreateSemaphore().
> >
> > Semaphores are one of three types of object to be implemented in this driver,
> > the others being mutexes and events.
> >
> > An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
> > when the counter is nonzero. The counter has a maximum value which is specified
> > at creation time. The initial value of the semaphore is also specified at
> > creation time. There are no restrictions on the maximum and initial value.
> >
> > Each object is exposed as an file, to which any number of fds may be opened.
> > When all fds are closed, the object is deleted.
> >
> > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > ---
> > .../userspace-api/ioctl/ioctl-number.rst | 2 +
> > drivers/misc/ntsync.c | 120 ++++++++++++++++++
> > include/uapi/linux/ntsync.h | 21 +++
> > 3 files changed, 143 insertions(+)
> > create mode 100644 include/uapi/linux/ntsync.h
> >
> > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > index 457e16f06e04..2f5c6994f042 100644
> > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > @@ -173,6 +173,8 @@ Code Seq# Include File Comments
> > 'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
> > 'N' 00-1F drivers/usb/scanner.h
> > 'N' 40-7F drivers/block/nvme.c
> > +'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
> > + <mailto:wine-devel(a)winehq.org>
> > 'O' 00-06 mtd/ubi-user.h UBI
> > 'P' all linux/soundcard.h conflict!
> > 'P' 60-6F sound/sscape_ioctl.h conflict!
> > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > index e4969ef90722..3ad86d98b82d 100644
> > --- a/drivers/misc/ntsync.c
> > +++ b/drivers/misc/ntsync.c
> > @@ -5,26 +5,146 @@
> > * Copyright (C) 2024 Elizabeth Figura
> > */
> >
> > +#include <linux/anon_inodes.h>
> > +#include <linux/file.h>
> > #include <linux/fs.h>
> > #include <linux/miscdevice.h>
> > #include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <uapi/linux/ntsync.h>
> >
> > #define NTSYNC_NAME "ntsync"
> >
> > +enum ntsync_type {
> > + NTSYNC_TYPE_SEM,
> > +};
> > +
> > +struct ntsync_obj {
> > + enum ntsync_type type;
> > +
> > + union {
> > + struct {
> > + __u32 count;
> > + __u32 max;
> > + } sem;
> > + } u;
> > +
> > + struct file *file;
> > + struct ntsync_device *dev;
> > +};
> > +
> > +struct ntsync_device {
> > + struct file *file;
> > +};
>
> No reference counting is needed for your ntsync_device? Or are you
> relying on the reference counting of struct file here?
>
> You pass around pointers to this structure, and save it off into other
> structures, how do you know it is "safe" to do so?
Yes, this relies on the reference counting of struct file. The sync
objects (semaphore etc.) grab a reference when they're created, via
get_file(), and release it when they're destroyed. This reference is
taken from within ioctls on the ntsync_device, so the file must be
valid when we grab a reference. Maybe I'm missing something, though?
Feb. 15, 2024
Re: [PATCH 01/31] ntsync: Introduce the ntsync driver and character device.
by Elizabeth Figura
On Wednesday, 14 February 2024 19:57:23 CST Randy Dunlap wrote:
> Hi,
>
> On 2/14/24 15:36, Elizabeth Figura wrote:
> > ntsync uses a misc device as the simplest and least intrusive uAPI interface.
> >
> > Each file description on the device represents an isolated NT instance, intended
> > to correspond to a single NT virtual machine.
> >
> > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > ---
> > drivers/misc/Kconfig | 9 ++++++++
> > drivers/misc/Makefile | 1 +
> > drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 62 insertions(+)
> > create mode 100644 drivers/misc/ntsync.c
> >
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> > index 4fb291f0bf7c..bdd8a71bd853 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -504,6 +504,15 @@ config OPEN_DICE
> > measured boot flow. Userspace can use CDIs for remote attestation
> > and sealing.
> >
> > +config NTSYNC
> > + tristate "NT synchronization primitive emulation"
> > + help
> > + This module provides kernel support for emulation of Windows NT
> > + synchronization primitives. It is not a hardware driver.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called ntsync.
> > +
> > If unsure, say N.
>
> It looks like the "If unsure" line belongs to the OPEN_DICE kconfig entry
> above here. If you want one for NTSYNC, please add one.
Oops, looks like that was a bad rebase :-(
>
> >
> > config VCPU_STALL_DETECTOR
>
>
> > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > new file mode 100644
> > index 000000000000..e4969ef90722
> > --- /dev/null
> > +++ b/drivers/misc/ntsync.c
> > @@ -0,0 +1,52 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * ntsync.c - Kernel driver for NT synchronization primitives
> > + *
> > + * Copyright (C) 2024 Elizabeth Figura
>
> It would be nice to have your email address above...
>
> > + */
> > +
>
> > +
> > +MODULE_AUTHOR("Elizabeth Figura");
>
> but at least please add it in MODULE_AUTHOR(). Yes it's optional, but
> roughly 7900 of 10400 entries do include it (according to my rough
> grepping).
>
> Yes, I know that it's in MAINTAINERS.
Will add, thanks. As you guessed I did just pick an arbitrary module to copy.
Feb. 15, 2024
Re: [PATCH 00/31] NT synchronization primitive driver
by Elizabeth Figura
On Wednesday, 14 February 2024 17:36:36 CST Elizabeth Figura wrote:
> This patch series introduces a new char misc driver, /dev/ntsync, which is used
> to implement Windows NT synchronization primitives.
Ugh, sorry, I made a bit of a mess while sending this revision. I accidentally
sent 000* instead of 00*, and then tried to fix it by sending the rest with
--in-reply-to but forgot to also add --no-thread. Please let me know if I should
resend the whole series.
--Zeb
Feb. 15, 2024