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
25 25
26enum ntsync_type {26enum ntsync_type {
27 NTSYNC_TYPE_SEM,27 NTSYNC_TYPE_SEM,
28 NTSYNC_TYPE_MUTEX,
28};29};
29 30
30/*31/*
@@ -55,6 +56,10 @@ struct ntsync_obj { · 24 unmodified lines
55 __u32 count;56 __u32 count;
56 __u32 max;57 __u32 max;
57 } sem;58 } sem;
59 struct {
60 __u32 count;
61 pid_t owner;
62 } mutex;
58 } u;63 } u;
59 64
60 /*65 /*
@@ -92,6 +97,7 @@ struct ntsync_q_entry { · 31 unmodified lines
92 97
93struct ntsync_q {98struct ntsync_q {
94 struct task_struct *task;99 struct task_struct *task;
100 __u32 owner;
95 101
96 /*102 /*
97 * Protected via atomic_try_cmpxchg(). Only the thread that wins the103 * 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
214 ((lockdep_is_held(&(obj)->dev->wait_all_lock) != LOCK_STATE_NOT_HELD) && \220 ((lockdep_is_held(&(obj)->dev->wait_all_lock) != LOCK_STATE_NOT_HELD) && \
215 (obj)->dev_locked))221 (obj)->dev_locked))
216 222
217static bool is_signaled(struct ntsync_obj *obj)223static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
218{224{
219 ntsync_assert_held(obj);225 ntsync_assert_held(obj);
220 226
221 switch (obj->type) {227 switch (obj->type) {
222 case NTSYNC_TYPE_SEM:228 case NTSYNC_TYPE_SEM:
223 return !!obj->u.sem.count;229 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;
224 }234 }
225 235
226 WARN(1, "bad object type %#x\n", obj->type);236 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
250 }260 }
251 261
252 for (i = 0; i < count; i++) {262 for (i = 0; i < count; i++) {
253 if (!is_signaled(q->entries[i].obj)) {263 if (!is_signaled(q->entries[i].obj, q->owner)) {
254 can_wake = false;264 can_wake = false;
255 break;265 break;
256 }266 }
@@ -264,6 +274,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, · 7 unmodified lines
264 case NTSYNC_TYPE_SEM:274 case NTSYNC_TYPE_SEM:
265 obj->u.sem.count--;275 obj->u.sem.count--;
266 break;276 break;
277 case NTSYNC_TYPE_MUTEX:
278 obj->u.mutex.count++;
279 obj->u.mutex.owner = q->owner;
280 break;
267 }281 }
268 }282 }
269 wake_up_process(q->task);283 wake_up_process(q->task);
@@ -307,6 +321,30 @@ static void try_wake_any_sem(struct ntsync_obj *sem) · 37 unmodified lines
307 }321 }
308}322}
309 323
324static 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
310/*348/*
311 * Actually change the semaphore state, returning -EOVERFLOW if it is made349 * Actually change the semaphore state, returning -EOVERFLOW if it is made
312 * invalid.350 * invalid.
@@ -451,6 +489,30 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) · 138 unmodified lines
451 return fd;489 return fd;
452}490}
453 491
492static 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
454static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)516static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
455{517{
456 struct file *file = fget(fd);518 struct file *file = fget(fd);
@@ -520,7 +582,7 @@ static int setup_wait(struct ntsync_device *dev, · 63 unmodified lines
520 struct ntsync_q *q;582 struct ntsync_q *q;
521 __u32 i, j;583 __u32 i, j;
522 584
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))
524 return -EINVAL;586 return -EINVAL;
525 587
526 if (args->count > NTSYNC_MAX_WAIT_COUNT)588 if (args->count > NTSYNC_MAX_WAIT_COUNT)
@@ -534,6 +596,7 @@ static int setup_wait(struct ntsync_device *dev, · 7 unmodified lines
534 if (!q)596 if (!q)
535 return -ENOMEM;597 return -ENOMEM;
536 q->task = current;598 q->task = current;
599 q->owner = args->owner;
537 atomic_set(&q->signaled, -1);600 atomic_set(&q->signaled, -1);
538 q->all = all;601 q->all = all;
539 q->count = count;602 q->count = count;
@@ -576,6 +639,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) · 36 unmodified lines
576 case NTSYNC_TYPE_SEM:639 case NTSYNC_TYPE_SEM:
577 try_wake_any_sem(obj);640 try_wake_any_sem(obj);
578 break;641 break;
642 case NTSYNC_TYPE_MUTEX:
643 try_wake_any_mutex(obj);
644 break;
579 }645 }
580}646}
581 647
@@ -765,6 +831,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, · 183 unmodified lines
765 void __user *argp = (void __user *)parm;831 void __user *argp = (void __user *)parm;
766 832
767 switch (cmd) {833 switch (cmd) {
834 case NTSYNC_IOC_CREATE_MUTEX:
835 return ntsync_create_mutex(dev, argp);
768 case NTSYNC_IOC_CREATE_SEM:836 case NTSYNC_IOC_CREATE_SEM:
769 return ntsync_create_sem(dev, argp);837 return ntsync_create_sem(dev, argp);
770 case NTSYNC_IOC_WAIT_ALL:838 case NTSYNC_IOC_WAIT_ALL:
include/uapi/linux/ntsync.h+8−1
@@ -15,6 +15,11 @@ struct ntsync_sem_args { · 14 unmodified lines
15 __u32 max;15 __u32 max;
16};16};
17 17
18struct ntsync_mutex_args {
19 __u32 owner;
20 __u32 count;
21};
22
18#define NTSYNC_WAIT_REALTIME 0x123#define NTSYNC_WAIT_REALTIME 0x1
19 24
20struct ntsync_wait_args {25struct ntsync_wait_args {
@@ -23,7 +28,8 @@ struct ntsync_wait_args { · 2 unmodified lines
23 __u32 count;28 __u32 count;
24 __u32 index;29 __u32 index;
25 __u32 flags;30 __u32 flags;
26 __u32 pad[3];31 __u32 owner;
32 __u32 pad[2];
27};33};
28 34
29#define NTSYNC_MAX_WAIT_COUNT 6435#define NTSYNC_MAX_WAIT_COUNT 64
@@ -31,6 +37,7 @@ struct ntsync_wait_args { · 1 unmodified line
31#define NTSYNC_IOC_CREATE_SEM _IOW ('N', 0x80, struct ntsync_sem_args)37#define NTSYNC_IOC_CREATE_SEM _IOW ('N', 0x80, struct ntsync_sem_args)
32#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)38#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
33#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)39#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)
34 41
35#define NTSYNC_IOC_SEM_RELEASE _IOWR('N', 0x81, __u32)42#define NTSYNC_IOC_SEM_RELEASE _IOWR('N', 0x81, __u32)
36 43

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