Skip to content

Commit

Permalink
winesync: Introduce WINESYNC_IOC_KILL_OWNER
Browse files Browse the repository at this point in the history
  • Loading branch information
Zebediah Figura authored and xanmod committed May 30, 2022
1 parent 1d25d18 commit 224d0c0
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 2 deletions.
80 changes: 78 additions & 2 deletions drivers/misc/winesync.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct winesync_obj {
struct {
__u32 count;
__u32 owner;
bool ownerdead;
} mutex;
} u;
};
Expand All @@ -87,6 +88,7 @@ struct winesync_q {
atomic_t signaled;

bool all;
bool ownerdead;
__u32 count;
struct winesync_q_entry entries[];
};
Expand Down Expand Up @@ -240,6 +242,9 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q,
obj->u.sem.count--;
break;
case WINESYNC_TYPE_MUTEX:
if (obj->u.mutex.ownerdead)
q->ownerdead = true;
obj->u.mutex.ownerdead = false;
obj->u.mutex.count++;
obj->u.mutex.owner = q->owner;
break;
Expand Down Expand Up @@ -300,6 +305,9 @@ static void try_wake_any_mutex(struct winesync_obj *mutex)
continue;

if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) {
if (mutex->u.mutex.ownerdead)
q->ownerdead = true;
mutex->u.mutex.ownerdead = false;
mutex->u.mutex.count++;
mutex->u.mutex.owner = q->owner;
wake_up_process(q->task);
Expand Down Expand Up @@ -515,6 +523,71 @@ static int winesync_put_mutex(struct winesync_device *dev, void __user *argp)
return ret;
}

/*
* Actually change the mutex state to mark its owner as dead.
*/
static void put_mutex_ownerdead_state(struct winesync_obj *mutex)
{
lockdep_assert_held(&mutex->lock);

mutex->u.mutex.ownerdead = true;
mutex->u.mutex.owner = 0;
mutex->u.mutex.count = 0;
}

static int winesync_kill_owner(struct winesync_device *dev, void __user *argp)
{
struct winesync_obj *obj;
unsigned long id;
__u32 owner;

if (get_user(owner, (__u32 __user *)argp))
return -EFAULT;
if (!owner)
return -EINVAL;

rcu_read_lock();

xa_for_each(&dev->objects, id, obj) {
if (!kref_get_unless_zero(&obj->refcount))
continue;

if (obj->type != WINESYNC_TYPE_MUTEX) {
put_obj(obj);
continue;
}

if (atomic_read(&obj->all_hint) > 0) {
spin_lock(&dev->wait_all_lock);
spin_lock(&obj->lock);

if (obj->u.mutex.owner == owner) {
put_mutex_ownerdead_state(obj);
try_wake_all_obj(dev, obj);
try_wake_any_mutex(obj);
}

spin_unlock(&obj->lock);
spin_unlock(&dev->wait_all_lock);
} else {
spin_lock(&obj->lock);

if (obj->u.mutex.owner == owner) {
put_mutex_ownerdead_state(obj);
try_wake_any_mutex(obj);
}

spin_unlock(&obj->lock);
}

put_obj(obj);
}

rcu_read_unlock();

return 0;
}

static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout)
{
int ret = 0;
Expand Down Expand Up @@ -583,6 +656,7 @@ static int setup_wait(struct winesync_device *dev,
q->owner = args->owner;
atomic_set(&q->signaled, -1);
q->all = all;
q->ownerdead = false;
q->count = count;

for (i = 0; i < count; i++) {
Expand Down Expand Up @@ -695,7 +769,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp)
struct winesync_wait_args __user *user_args = argp;

/* even if we caught a signal, we need to communicate success */
ret = 0;
ret = q->ownerdead ? -EOWNERDEAD : 0;

if (put_user(signaled, &user_args->index))
ret = -EFAULT;
Expand Down Expand Up @@ -776,7 +850,7 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp)
struct winesync_wait_args __user *user_args = argp;

/* even if we caught a signal, we need to communicate success */
ret = 0;
ret = q->ownerdead ? -EOWNERDEAD : 0;

if (put_user(signaled, &user_args->index))
ret = -EFAULT;
Expand All @@ -801,6 +875,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd,
return winesync_create_sem(dev, argp);
case WINESYNC_IOC_DELETE:
return winesync_delete(dev, argp);
case WINESYNC_IOC_KILL_OWNER:
return winesync_kill_owner(dev, argp);
case WINESYNC_IOC_PUT_MUTEX:
return winesync_put_mutex(dev, argp);
case WINESYNC_IOC_PUT_SEM:
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/winesync.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ struct winesync_wait_args {
struct winesync_mutex_args)
#define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \
struct winesync_mutex_args)
#define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32)

#endif

0 comments on commit 224d0c0

Please sign in to comment.