Skip to content

Commit

Permalink
winesync: Introduce WINESYNC_IOC_CREATE_SEM and WINESYNC_IOC_DELETE.
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Frade <kernel@xanmod.org>
  • Loading branch information
Zebediah Figura authored and xanmod committed Aug 2, 2022
1 parent 6ed53d3 commit 7aca173
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
117 changes: 117 additions & 0 deletions drivers/misc/winesync.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,140 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/xarray.h>
#include <uapi/linux/winesync.h>

#define WINESYNC_NAME "winesync"

enum winesync_type {
WINESYNC_TYPE_SEM,
};

struct winesync_obj {
struct rcu_head rhead;
struct kref refcount;

enum winesync_type type;

union {
struct {
__u32 count;
__u32 max;
} sem;
} u;
};

struct winesync_device {
struct xarray objects;
};

static void destroy_obj(struct kref *ref)
{
struct winesync_obj *obj = container_of(ref, struct winesync_obj, refcount);

kfree_rcu(obj, rhead);
}

static void put_obj(struct winesync_obj *obj)
{
kref_put(&obj->refcount, destroy_obj);
}

static int winesync_char_open(struct inode *inode, struct file *file)
{
struct winesync_device *dev;

dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;

xa_init_flags(&dev->objects, XA_FLAGS_ALLOC);

file->private_data = dev;
return nonseekable_open(inode, file);
}

static int winesync_char_release(struct inode *inode, struct file *file)
{
struct winesync_device *dev = file->private_data;
struct winesync_obj *obj;
unsigned long id;

xa_for_each(&dev->objects, id, obj)
put_obj(obj);

xa_destroy(&dev->objects);

kfree(dev);

return 0;
}

static void init_obj(struct winesync_obj *obj)
{
kref_init(&obj->refcount);
}

static int winesync_create_sem(struct winesync_device *dev, void __user *argp)
{
struct winesync_sem_args __user *user_args = argp;
struct winesync_sem_args args;
struct winesync_obj *sem;
__u32 id;
int ret;

if (copy_from_user(&args, argp, sizeof(args)))
return -EFAULT;

if (args.count > args.max)
return -EINVAL;

sem = kzalloc(sizeof(*sem), GFP_KERNEL);
if (!sem)
return -ENOMEM;

init_obj(sem);
sem->type = WINESYNC_TYPE_SEM;
sem->u.sem.count = args.count;
sem->u.sem.max = args.max;

ret = xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL);
if (ret < 0) {
kfree(sem);
return ret;
}

return put_user(id, &user_args->sem);
}

static int winesync_delete(struct winesync_device *dev, void __user *argp)
{
struct winesync_obj *obj;
__u32 id;

if (get_user(id, (__u32 __user *)argp))
return -EFAULT;

obj = xa_erase(&dev->objects, id);
if (!obj)
return -EINVAL;

put_obj(obj);
return 0;
}

static long winesync_char_ioctl(struct file *file, unsigned int cmd,
unsigned long parm)
{
struct winesync_device *dev = file->private_data;
void __user *argp = (void __user *)parm;

switch (cmd) {
case WINESYNC_IOC_CREATE_SEM:
return winesync_create_sem(dev, argp);
case WINESYNC_IOC_DELETE:
return winesync_delete(dev, argp);
default:
return -ENOSYS;
}
Expand Down
25 changes: 25 additions & 0 deletions include/uapi/linux/winesync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Kernel support for Wine synchronization primitives
*
* Copyright (C) 2021 Zebediah Figura
*/

#ifndef __LINUX_WINESYNC_H
#define __LINUX_WINESYNC_H

#include <linux/types.h>

struct winesync_sem_args {
__u32 sem;
__u32 count;
__u32 max;
};

#define WINESYNC_IOC_BASE 0xf7

#define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \
struct winesync_sem_args)
#define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32)

#endif

0 comments on commit 7aca173

Please sign in to comment.