History

ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.

This corresponds to the NT syscall NtCreateMutant(). An NT mutex is recursive, with a 32-bit recursion counter. When acquired via NtWaitForMultipleObjects(), the recursion counter is incremented by one. The OS records the thread which acquired it. The OS records the thread which acquired it. However, in order to keep this driver self-contained, the owning thread ID is managed by user-space, and passed as a parameter to all relevant ioctls. The initial owner and recursion count, if any, are specified when the mutex is created.

Elizabeth Figura committed 1 year ago

Commit 5bc24791 parent cdbb9972 files · +79 −4Browse files

Unified · Split

2 files
  1. drivers/misc/ntsync.c +71 −3
  2. include/uapi/linux/ntsync.h +8 −1
drivers/misc/ntsync.c+71−3
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525
2626 enum ntsync_type {
2727 NTSYNC_TYPE_SEM,
28+ NTSYNC_TYPE_MUTEX,
2829 };
2930
3031 /*
@@ -55,6 +56,10 @@ struct ntsync_obj { · 24 unmodified lines
5556 __u32 count;
5657 __u32 max;
5758 } sem;
59+ struct {
60+ __u32 count;
61+ pid_t owner;
62+ } mutex;
5863 } u;
5964
6065 /*
@@ -92,6 +97,7 @@ struct ntsync_q_entry { · 31 unmodified lines
9297
9398 struct ntsync_q {
9499 struct task_struct *task;
100+ __u32 owner;
95101
96102 /*
97103 * Protected via atomic_try_cmpxchg(). Only the thread that wins the
@@ -214,13 +220,17 @@ static void ntsync_unlock_obj(struct ntsync_device *dev, struct ntsync_obj *obj, · 116 unmodified lines
214220 ((lockdep_is_held(&(obj)->dev->wait_all_lock) != LOCK_STATE_NOT_HELD) && \
215221 (obj)->dev_locked))
216222
217−static bool is_signaled(struct ntsync_obj *obj)
223+static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
218224 {
219225 ntsync_assert_held(obj);
220226
221227 switch (obj->type) {
222228 case NTSYNC_TYPE_SEM:
223229 return !!obj->u.sem.count;
230+ case NTSYNC_TYPE_MUTEX:
231+ if (obj->u.mutex.owner && obj->u.mutex.owner != owner)
232+ return false;
233+ return obj->u.mutex.count < UINT_MAX;
224234 }
225235
226236 WARN(1, "bad object type %#x\n", obj->type);
@@ -250,7 +260,7 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, · 23 unmodified lines
250260 }
251261
252262 for (i = 0; i < count; i++) {
253− if (!is_signaled(q->entries[i].obj)) {
263+ if (!is_signaled(q->entries[i].obj, q->owner)) {
254264 can_wake = false;
255265 break;
256266 }
@@ -264,6 +274,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, · 7 unmodified lines
264274 case NTSYNC_TYPE_SEM:
265275 obj->u.sem.count--;
266276 break;
277+ case NTSYNC_TYPE_MUTEX:
278+ obj->u.mutex.count++;
279+ obj->u.mutex.owner = q->owner;
280+ break;
267281 }
268282 }
269283 wake_up_process(q->task);
@@ -307,6 +321,30 @@ static void try_wake_any_sem(struct ntsync_obj *sem) · 37 unmodified lines
307321 }
308322 }
309323
324+static void try_wake_any_mutex(struct ntsync_obj *mutex)
325+{
326+ struct ntsync_q_entry *entry;
327+
328+ ntsync_assert_held(mutex);
329+ lockdep_assert(mutex->type == NTSYNC_TYPE_MUTEX);
330+
331+ list_for_each_entry(entry, &mutex->any_waiters, node) {
332+ struct ntsync_q *q = entry->q;
333+ int signaled = -1;
334+
335+ if (mutex->u.mutex.count == UINT_MAX)
336+ break;
337+ if (mutex->u.mutex.owner && mutex->u.mutex.owner != q->owner)
338+ continue;
339+
340+ if (atomic_try_cmpxchg(&q->signaled, &signaled, entry->index)) {
341+ mutex->u.mutex.count++;
342+ mutex->u.mutex.owner = q->owner;
343+ wake_up_process(q->task);
344+ }
345+ }
346+}
347+
310348 /*
311349 * Actually change the semaphore state, returning -EOVERFLOW if it is made
312350 * invalid.
@@ -451,6 +489,30 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) · 138 unmodified lines
451489 return fd;
452490 }
453491
492+static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp)
493+{
494+ struct ntsync_mutex_args args;
495+ struct ntsync_obj *mutex;
496+ int fd;
497+
498+ if (copy_from_user(&args, argp, sizeof(args)))
499+ return -EFAULT;
500+
501+ if (!args.owner != !args.count)
502+ return -EINVAL;
503+
504+ mutex = ntsync_alloc_obj(dev, NTSYNC_TYPE_MUTEX);
505+ if (!mutex)
506+ return -ENOMEM;
507+ mutex->u.mutex.count = args.count;
508+ mutex->u.mutex.owner = args.owner;
509+ fd = ntsync_obj_get_fd(mutex);
510+ if (fd < 0)
511+ kfree(mutex);
512+
513+ return fd;
514+}
515+
454516 static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
455517 {
456518 struct file *file = fget(fd);
@@ -520,7 +582,7 @@ static int setup_wait(struct ntsync_device *dev, · 63 unmodified lines
520582 struct ntsync_q *q;
521583 __u32 i, j;
522584
523− if (args->pad[0] || args->pad[1] || args->pad[2] || (args->flags & ~NTSYNC_WAIT_REALTIME))
585+ if (args->pad[0] || args->pad[1] || (args->flags & ~NTSYNC_WAIT_REALTIME))
524586 return -EINVAL;
525587
526588 if (args->count > NTSYNC_MAX_WAIT_COUNT)
@@ -534,6 +596,7 @@ static int setup_wait(struct ntsync_device *dev, · 7 unmodified lines
534596 if (!q)
535597 return -ENOMEM;
536598 q->task = current;
599+ q->owner = args->owner;
537600 atomic_set(&q->signaled, -1);
538601 q->all = all;
539602 q->count = count;
@@ -576,6 +639,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) · 36 unmodified lines
576639 case NTSYNC_TYPE_SEM:
577640 try_wake_any_sem(obj);
578641 break;
642+ case NTSYNC_TYPE_MUTEX:
643+ try_wake_any_mutex(obj);
644+ break;
579645 }
580646 }
581647
@@ -765,6 +831,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, · 183 unmodified lines
765831 void __user *argp = (void __user *)parm;
766832
767833 switch (cmd) {
834+ case NTSYNC_IOC_CREATE_MUTEX:
835+ return ntsync_create_mutex(dev, argp);
768836 case NTSYNC_IOC_CREATE_SEM:
769837 return ntsync_create_sem(dev, argp);
770838 case NTSYNC_IOC_WAIT_ALL:
include/uapi/linux/ntsync.h+8−1
@@ -15,6 +15,11 @@ struct ntsync_sem_args { · 14 unmodified lines
1515 __u32 max;
1616 };
1717
18+struct ntsync_mutex_args {
19+ __u32 owner;
20+ __u32 count;
21+};
22+
1823 #define NTSYNC_WAIT_REALTIME 0x1
1924
2025 struct ntsync_wait_args {
@@ -23,7 +28,8 @@ struct ntsync_wait_args { · 2 unmodified lines
2328 __u32 count;
2429 __u32 index;
2530 __u32 flags;
26− __u32 pad[3];
31+ __u32 owner;
32+ __u32 pad[2];
2733 };
2834
2935 #define NTSYNC_MAX_WAIT_COUNT 64
@@ -31,6 +37,7 @@ struct ntsync_wait_args { · 1 unmodified line
3137 #define NTSYNC_IOC_CREATE_SEM _IOW ('N', 0x80, struct ntsync_sem_args)
3238 #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
3339 #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
40+#define NTSYNC_IOC_CREATE_MUTEX _IOW ('N', 0x84, struct ntsync_mutex_args)
3441
3542 #define NTSYNC_IOC_SEM_RELEASE _IOWR('N', 0x81, __u32)
3643

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t