base: genlock: Remove genlock_release_lock and associated ioctl
base: genlock: allow synchronization with a single gralloc handle base: genlock: remove BIT macro usage
This commit is contained in:
parent
8bdae42d95
commit
e20f7d7077
302
drivers/base/genlock.c
Normal file → Executable file
302
drivers/base/genlock.c
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -22,7 +22,7 @@
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/genlock.h>
|
||||
#include <linux/interrupt.h> /* for in_interrupt() */
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/* Lock states - can either be unlocked, held as an exclusive write lock or a
|
||||
* shared read lock
|
||||
@ -32,6 +32,9 @@
|
||||
#define _RDLOCK GENLOCK_RDLOCK
|
||||
#define _WRLOCK GENLOCK_WRLOCK
|
||||
|
||||
#define GENLOCK_LOG_ERR(fmt, args...) \
|
||||
pr_err("genlock: %s: " fmt, __func__, ##args)
|
||||
|
||||
struct genlock {
|
||||
struct list_head active; /* List of handles holding lock */
|
||||
spinlock_t lock; /* Spinlock to protect the lock internals */
|
||||
@ -49,12 +52,29 @@ struct genlock_handle {
|
||||
taken */
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a spinlock to protect against a race condition when a lock gets
|
||||
* released while another process tries to attach it
|
||||
*/
|
||||
|
||||
static DEFINE_SPINLOCK(genlock_file_lock);
|
||||
|
||||
static void genlock_destroy(struct kref *kref)
|
||||
{
|
||||
struct genlock *lock = container_of(kref, struct genlock,
|
||||
refcount);
|
||||
struct genlock *lock = container_of(kref, struct genlock,
|
||||
refcount);
|
||||
|
||||
kfree(lock);
|
||||
/*
|
||||
* Clear the private data for the file descriptor in case the fd is
|
||||
* still active after the lock gets released
|
||||
*/
|
||||
|
||||
spin_lock(&genlock_file_lock);
|
||||
if (lock->file)
|
||||
lock->file->private_data = NULL;
|
||||
spin_unlock(&genlock_file_lock);
|
||||
|
||||
kfree(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -64,6 +84,15 @@ static void genlock_destroy(struct kref *kref)
|
||||
|
||||
static int genlock_release(struct inode *inodep, struct file *file)
|
||||
{
|
||||
struct genlock *lock = file->private_data;
|
||||
/*
|
||||
* Clear the refrence back to this file structure to avoid
|
||||
* somehow reusing the lock after the file has been destroyed
|
||||
*/
|
||||
|
||||
if (lock)
|
||||
lock->file = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -82,12 +111,21 @@ struct genlock *genlock_create_lock(struct genlock_handle *handle)
|
||||
{
|
||||
struct genlock *lock;
|
||||
|
||||
if (handle->lock != NULL)
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
GENLOCK_LOG_ERR("Invalid handle\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (handle->lock != NULL) {
|
||||
GENLOCK_LOG_ERR("Handle already has a lock attached\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
lock = kzalloc(sizeof(*lock), GFP_KERNEL);
|
||||
if (lock == NULL)
|
||||
if (lock == NULL) {
|
||||
GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&lock->active);
|
||||
init_waitqueue_head(&lock->queue);
|
||||
@ -120,8 +158,10 @@ static int genlock_get_fd(struct genlock *lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!lock->file)
|
||||
if (!lock->file) {
|
||||
GENLOCK_LOG_ERR("No file attached to the lock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = get_unused_fd_flags(0);
|
||||
if (ret < 0)
|
||||
@ -143,19 +183,37 @@ struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
|
||||
struct file *file;
|
||||
struct genlock *lock;
|
||||
|
||||
if (handle->lock != NULL)
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
GENLOCK_LOG_ERR("Invalid handle\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (handle->lock != NULL) {
|
||||
GENLOCK_LOG_ERR("Handle already has a lock attached\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
file = fget(fd);
|
||||
if (file == NULL)
|
||||
if (file == NULL) {
|
||||
GENLOCK_LOG_ERR("Bad file descriptor\n");
|
||||
return ERR_PTR(-EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* take a spinlock to avoid a race condition if the lock is
|
||||
* released and then attached
|
||||
*/
|
||||
|
||||
spin_lock(&genlock_file_lock);
|
||||
lock = file->private_data;
|
||||
spin_unlock(&genlock_file_lock);
|
||||
|
||||
fput(file);
|
||||
|
||||
if (lock == NULL)
|
||||
if (lock == NULL) {
|
||||
GENLOCK_LOG_ERR("File descriptor is invalid\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
handle->lock = lock;
|
||||
kref_get(&lock->refcount);
|
||||
@ -199,13 +257,16 @@ static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
|
||||
|
||||
spin_lock_irqsave(&lock->lock, irqflags);
|
||||
|
||||
if (lock->state == _UNLOCKED)
|
||||
if (lock->state == _UNLOCKED) {
|
||||
GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Make sure this handle is an owner of the lock */
|
||||
if (!handle_has_lock(lock, handle))
|
||||
if (!handle_has_lock(lock, handle)) {
|
||||
GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
|
||||
goto done;
|
||||
|
||||
}
|
||||
/* If the handle holds no more references to the lock then
|
||||
release it (maybe) */
|
||||
|
||||
@ -228,7 +289,7 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
|
||||
{
|
||||
unsigned long irqflags;
|
||||
int ret = 0;
|
||||
unsigned int ticks = msecs_to_jiffies(timeout);
|
||||
unsigned long ticks = msecs_to_jiffies(timeout);
|
||||
|
||||
spin_lock_irqsave(&lock->lock, irqflags);
|
||||
|
||||
@ -247,12 +308,15 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
|
||||
if (handle_has_lock(lock, handle)) {
|
||||
|
||||
/*
|
||||
* If the handle already holds the lock and the type matches,
|
||||
* then just increment the active pointer. This allows the
|
||||
* handle to do recursive locks
|
||||
* If the handle already holds the lock and the lock type is
|
||||
* a read lock then just increment the active pointer. This
|
||||
* allows the handle to do recursive read locks. Recursive
|
||||
* write locks are not allowed in order to support
|
||||
* synchronization within a process using a single gralloc
|
||||
* handle.
|
||||
*/
|
||||
|
||||
if (lock->state == op) {
|
||||
if (lock->state == _RDLOCK && op == _RDLOCK) {
|
||||
handle->active++;
|
||||
goto done;
|
||||
}
|
||||
@ -261,32 +325,46 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
|
||||
* If the handle holds a write lock then the owner can switch
|
||||
* to a read lock if they want. Do the transition atomically
|
||||
* then wake up any pending waiters in case they want a read
|
||||
* lock too.
|
||||
* lock too. In order to support synchronization within a
|
||||
* process the caller must explicity request to convert the
|
||||
* lock type with the GENLOCK_WRITE_TO_READ flag.
|
||||
*/
|
||||
|
||||
if (op == _RDLOCK && handle->active == 1) {
|
||||
lock->state = _RDLOCK;
|
||||
wake_up(&lock->queue);
|
||||
if (flags & GENLOCK_WRITE_TO_READ) {
|
||||
if (lock->state == _WRLOCK && op == _RDLOCK) {
|
||||
lock->state = _RDLOCK;
|
||||
wake_up(&lock->queue);
|
||||
goto done;
|
||||
} else {
|
||||
GENLOCK_LOG_ERR("Invalid state to convert"
|
||||
"write to read\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Check to ensure the caller has not attempted to convert a
|
||||
* write to a read without holding the lock.
|
||||
*/
|
||||
|
||||
if (flags & GENLOCK_WRITE_TO_READ) {
|
||||
GENLOCK_LOG_ERR("Handle must have lock to convert"
|
||||
"write to read\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise the user tried to turn a read into a write, and we
|
||||
* don't allow that.
|
||||
* If we request a read and the lock is held by a read, then go
|
||||
* ahead and share the lock
|
||||
*/
|
||||
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
|
||||
goto dolock;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we request a read and the lock is held by a read, then go
|
||||
* ahead and share the lock
|
||||
*/
|
||||
|
||||
if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
|
||||
goto dolock;
|
||||
|
||||
/* Treat timeout 0 just like a NOBLOCK flag and return if the
|
||||
lock cannot be aquired without blocking */
|
||||
|
||||
@ -295,15 +373,26 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Wait while the lock remains in an incompatible state */
|
||||
/*
|
||||
* Wait while the lock remains in an incompatible state
|
||||
* state op wait
|
||||
* -------------------
|
||||
* unlocked n/a no
|
||||
* read read no
|
||||
* read write yes
|
||||
* write n/a yes
|
||||
*/
|
||||
|
||||
while (lock->state != _UNLOCKED) {
|
||||
unsigned int elapsed;
|
||||
while ((lock->state == _RDLOCK && op == _WRLOCK) ||
|
||||
lock->state == _WRLOCK) {
|
||||
signed long elapsed;
|
||||
|
||||
spin_unlock_irqrestore(&lock->lock, irqflags);
|
||||
|
||||
elapsed = wait_event_interruptible_timeout(lock->queue,
|
||||
lock->state == _UNLOCKED, ticks);
|
||||
lock->state == _UNLOCKED ||
|
||||
(lock->state == _RDLOCK && op == _RDLOCK),
|
||||
ticks);
|
||||
|
||||
spin_lock_irqsave(&lock->lock, irqflags);
|
||||
|
||||
@ -312,7 +401,7 @@ static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
|
||||
goto done;
|
||||
}
|
||||
|
||||
ticks = elapsed;
|
||||
ticks = (unsigned long) elapsed;
|
||||
}
|
||||
|
||||
dolock:
|
||||
@ -320,7 +409,7 @@ dolock:
|
||||
|
||||
list_add_tail(&handle->entry, &lock->active);
|
||||
lock->state = op;
|
||||
handle->active = 1;
|
||||
handle->active++;
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&lock->lock, irqflags);
|
||||
@ -329,7 +418,7 @@ done:
|
||||
}
|
||||
|
||||
/**
|
||||
* genlock_lock - Acquire or release a lock
|
||||
* genlock_lock - Acquire or release a lock (depreciated)
|
||||
* @handle - pointer to the genlock handle that is requesting the lock
|
||||
* @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
|
||||
* @flags - flags to control the operation
|
||||
@ -341,11 +430,76 @@ done:
|
||||
int genlock_lock(struct genlock_handle *handle, int op, int flags,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct genlock *lock = handle->lock;
|
||||
struct genlock *lock;
|
||||
unsigned long irqflags;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (lock == NULL)
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
GENLOCK_LOG_ERR("Invalid handle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lock = handle->lock;
|
||||
|
||||
if (lock == NULL) {
|
||||
GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case GENLOCK_UNLOCK:
|
||||
ret = _genlock_unlock(lock, handle);
|
||||
break;
|
||||
case GENLOCK_RDLOCK:
|
||||
spin_lock_irqsave(&lock->lock, irqflags);
|
||||
if (handle_has_lock(lock, handle)) {
|
||||
/* request the WRITE_TO_READ flag for compatibility */
|
||||
flags |= GENLOCK_WRITE_TO_READ;
|
||||
}
|
||||
spin_unlock_irqrestore(&lock->lock, irqflags);
|
||||
/* fall through to take lock */
|
||||
case GENLOCK_WRLOCK:
|
||||
ret = _genlock_lock(lock, handle, op, flags, timeout);
|
||||
break;
|
||||
default:
|
||||
GENLOCK_LOG_ERR("Invalid lock operation\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(genlock_lock);
|
||||
|
||||
/**
|
||||
* genlock_dreadlock - Acquire or release a lock
|
||||
* @handle - pointer to the genlock handle that is requesting the lock
|
||||
* @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
|
||||
* @flags - flags to control the operation
|
||||
* @timeout - optional timeout to wait for the lock to come free
|
||||
*
|
||||
* Returns: 0 on success or error code on failure
|
||||
*/
|
||||
|
||||
int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct genlock *lock;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
GENLOCK_LOG_ERR("Invalid handle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lock = handle->lock;
|
||||
|
||||
if (lock == NULL) {
|
||||
GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case GENLOCK_UNLOCK:
|
||||
@ -356,13 +510,14 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags,
|
||||
ret = _genlock_lock(lock, handle, op, flags, timeout);
|
||||
break;
|
||||
default:
|
||||
GENLOCK_LOG_ERR("Invalid lock operation\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(genlock_lock);
|
||||
EXPORT_SYMBOL(genlock_dreadlock);
|
||||
|
||||
/**
|
||||
* genlock_wait - Wait for the lock to be released
|
||||
@ -372,13 +527,22 @@ EXPORT_SYMBOL(genlock_lock);
|
||||
|
||||
int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
|
||||
{
|
||||
struct genlock *lock = handle->lock;
|
||||
struct genlock *lock;
|
||||
unsigned long irqflags;
|
||||
int ret = 0;
|
||||
unsigned int ticks = msecs_to_jiffies(timeout);
|
||||
unsigned long ticks = msecs_to_jiffies(timeout);
|
||||
|
||||
if (lock == NULL)
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
GENLOCK_LOG_ERR("Invalid handle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lock = handle->lock;
|
||||
|
||||
if (lock == NULL) {
|
||||
GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&lock->lock, irqflags);
|
||||
|
||||
@ -393,7 +557,7 @@ int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
|
||||
}
|
||||
|
||||
while (lock->state != _UNLOCKED) {
|
||||
unsigned int elapsed;
|
||||
signed long elapsed;
|
||||
|
||||
spin_unlock_irqrestore(&lock->lock, irqflags);
|
||||
|
||||
@ -407,7 +571,7 @@ int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
|
||||
break;
|
||||
}
|
||||
|
||||
ticks = elapsed;
|
||||
ticks = (unsigned long) elapsed;
|
||||
}
|
||||
|
||||
done:
|
||||
@ -415,12 +579,7 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* genlock_release_lock - Release a lock attached to a handle
|
||||
* @handle - Pointer to the handle holding the lock
|
||||
*/
|
||||
|
||||
void genlock_release_lock(struct genlock_handle *handle)
|
||||
static void genlock_release_lock(struct genlock_handle *handle)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -441,7 +600,6 @@ void genlock_release_lock(struct genlock_handle *handle)
|
||||
handle->lock = NULL;
|
||||
handle->active = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(genlock_release_lock);
|
||||
|
||||
/*
|
||||
* Release function called when all references to a handle are released
|
||||
@ -468,8 +626,10 @@ static const struct file_operations genlock_handle_fops = {
|
||||
static struct genlock_handle *_genlock_get_handle(void)
|
||||
{
|
||||
struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (handle == NULL)
|
||||
if (handle == NULL) {
|
||||
GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
@ -531,6 +691,9 @@ static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
|
||||
struct genlock *lock;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(handle))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case GENLOCK_IOC_NEW: {
|
||||
lock = genlock_create_lock(handle);
|
||||
@ -540,8 +703,11 @@ static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
|
||||
return 0;
|
||||
}
|
||||
case GENLOCK_IOC_EXPORT: {
|
||||
if (handle->lock == NULL)
|
||||
if (handle->lock == NULL) {
|
||||
GENLOCK_LOG_ERR("Handle does not have a lock"
|
||||
"attached\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = genlock_get_fd(handle->lock);
|
||||
if (ret < 0)
|
||||
@ -574,6 +740,14 @@ static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
|
||||
return genlock_lock(handle, param.op, param.flags,
|
||||
param.timeout);
|
||||
}
|
||||
case GENLOCK_IOC_DREADLOCK: {
|
||||
if (copy_from_user(¶m, (void __user *) arg,
|
||||
sizeof(param)))
|
||||
return -EFAULT;
|
||||
|
||||
return genlock_dreadlock(handle, param.op, param.flags,
|
||||
param.timeout);
|
||||
}
|
||||
case GENLOCK_IOC_WAIT: {
|
||||
if (copy_from_user(¶m, (void __user *) arg,
|
||||
sizeof(param)))
|
||||
@ -582,10 +756,16 @@ static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
|
||||
return genlock_wait(handle, param.timeout);
|
||||
}
|
||||
case GENLOCK_IOC_RELEASE: {
|
||||
genlock_release_lock(handle);
|
||||
return 0;
|
||||
/*
|
||||
* Return error - this ioctl has been deprecated.
|
||||
* Locks should only be released when the handle is
|
||||
* destroyed
|
||||
*/
|
||||
GENLOCK_LOG_ERR("Deprecated RELEASE ioctl called\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
GENLOCK_LOG_ERR("Invalid ioctl\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
11
include/linux/genlock.h
Normal file → Executable file
11
include/linux/genlock.h
Normal file → Executable file
@ -12,7 +12,7 @@ void genlock_put_handle(struct genlock_handle *handle);
|
||||
struct genlock *genlock_create_lock(struct genlock_handle *);
|
||||
struct genlock *genlock_attach_lock(struct genlock_handle *, int fd);
|
||||
int genlock_wait(struct genlock_handle *handle, u32 timeout);
|
||||
void genlock_release_lock(struct genlock_handle *);
|
||||
/* genlock_release_lock was deprecated */
|
||||
int genlock_lock(struct genlock_handle *handle, int op, int flags,
|
||||
u32 timeout);
|
||||
#endif
|
||||
@ -21,7 +21,8 @@ int genlock_lock(struct genlock_handle *handle, int op, int flags,
|
||||
#define GENLOCK_WRLOCK 1
|
||||
#define GENLOCK_RDLOCK 2
|
||||
|
||||
#define GENLOCK_NOBLOCK (1 << 0)
|
||||
#define GENLOCK_NOBLOCK (1 << 0)
|
||||
#define GENLOCK_WRITE_TO_READ (1 << 1)
|
||||
|
||||
struct genlock_lock {
|
||||
int fd;
|
||||
@ -37,9 +38,15 @@ struct genlock_lock {
|
||||
struct genlock_lock)
|
||||
#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
|
||||
struct genlock_lock)
|
||||
|
||||
/* Deprecated */
|
||||
#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
|
||||
struct genlock_lock)
|
||||
|
||||
/* Deprecated */
|
||||
#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
|
||||
#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
|
||||
struct genlock_lock)
|
||||
#define GENLOCK_IOC_DREADLOCK _IOW(GENLOCK_IOC_MAGIC, 6, \
|
||||
struct genlock_lock)
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user