blob: 5e1d7af5e5295a6d45ec0a65c32660d93959bd1e [file] [log] [blame]
Jordan Crousea73ed092012-01-24 15:40:22 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Jordan Crouse29f66af2011-11-17 13:39:20 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/fb.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/list.h>
17#include <linux/file.h>
18#include <linux/sched.h>
19#include <linux/fs.h>
20#include <linux/wait.h>
21#include <linux/uaccess.h>
22#include <linux/anon_inodes.h>
23#include <linux/miscdevice.h>
24#include <linux/genlock.h>
25
26/* Lock states - can either be unlocked, held as an exclusive write lock or a
27 * shared read lock
28 */
29
30#define _UNLOCKED 0
31#define _RDLOCK GENLOCK_RDLOCK
32#define _WRLOCK GENLOCK_WRLOCK
33
Naomi Luisb558aed2011-12-12 12:07:48 -080034#define GENLOCK_LOG_ERR(fmt, args...) \
35pr_err("genlock: %s: " fmt, __func__, ##args)
36
Jordan Crouse29f66af2011-11-17 13:39:20 -070037struct genlock {
38 struct list_head active; /* List of handles holding lock */
39 spinlock_t lock; /* Spinlock to protect the lock internals */
40 wait_queue_head_t queue; /* Holding pen for processes pending lock */
41 struct file *file; /* File structure for exported lock */
42 int state; /* Current state of the lock */
Jordan Crouse4a2879b2011-12-01 11:52:59 -070043 struct kref refcount;
Jordan Crouse29f66af2011-11-17 13:39:20 -070044};
45
46struct genlock_handle {
47 struct genlock *lock; /* Lock currently attached to the handle */
48 struct list_head entry; /* List node for attaching to a lock */
49 struct file *file; /* File structure associated with handle */
50 int active; /* Number of times the active lock has been
51 taken */
52};
53
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070054/*
55 * Create a spinlock to protect against a race condition when a lock gets
56 * released while another process tries to attach it
57 */
58
59static DEFINE_SPINLOCK(genlock_file_lock);
60
Jordan Crouse4a2879b2011-12-01 11:52:59 -070061static void genlock_destroy(struct kref *kref)
62{
63 struct genlock *lock = container_of(kref, struct genlock,
64 refcount);
65
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070066 /*
67 * Clear the private data for the file descriptor in case the fd is
68 * still active after the lock gets released
69 */
70
71 spin_lock(&genlock_file_lock);
72 if (lock->file)
73 lock->file->private_data = NULL;
74 spin_unlock(&genlock_file_lock);
75
Jordan Crouse4a2879b2011-12-01 11:52:59 -070076 kfree(lock);
77}
78
Jordan Crouse29f66af2011-11-17 13:39:20 -070079/*
80 * Release the genlock object. Called when all the references to
81 * the genlock file descriptor are released
82 */
83
84static int genlock_release(struct inode *inodep, struct file *file)
85{
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070086 struct genlock *lock = file->private_data;
87 /*
88 * Clear the refrence back to this file structure to avoid
89 * somehow reusing the lock after the file has been destroyed
90 */
91
92 if (lock)
93 lock->file = NULL;
94
Jordan Crouse29f66af2011-11-17 13:39:20 -070095 return 0;
96}
97
98static const struct file_operations genlock_fops = {
99 .release = genlock_release,
100};
101
102/**
103 * genlock_create_lock - Create a new lock
104 * @handle - genlock handle to attach the lock to
105 *
106 * Returns: a pointer to the genlock
107 */
108
109struct genlock *genlock_create_lock(struct genlock_handle *handle)
110{
111 struct genlock *lock;
112
Jordan Crousea73ed092012-01-24 15:40:22 -0700113 if (IS_ERR_OR_NULL(handle)) {
114 GENLOCK_LOG_ERR("Invalid handle\n");
115 return ERR_PTR(-EINVAL);
116 }
117
Naomi Luisb558aed2011-12-12 12:07:48 -0800118 if (handle->lock != NULL) {
119 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700120 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800121 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700122
123 lock = kzalloc(sizeof(*lock), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800124 if (lock == NULL) {
125 GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700126 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800127 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700128
129 INIT_LIST_HEAD(&lock->active);
130 init_waitqueue_head(&lock->queue);
131 spin_lock_init(&lock->lock);
132
133 lock->state = _UNLOCKED;
134
135 /*
136 * Create an anonyonmous inode for the object that can exported to
137 * other processes
138 */
139
140 lock->file = anon_inode_getfile("genlock", &genlock_fops,
141 lock, O_RDWR);
142
143 /* Attach the new lock to the handle */
144 handle->lock = lock;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700145 kref_init(&lock->refcount);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700146
147 return lock;
148}
149EXPORT_SYMBOL(genlock_create_lock);
150
151/*
152 * Get a file descriptor reference to a lock suitable for sharing with
153 * other processes
154 */
155
156static int genlock_get_fd(struct genlock *lock)
157{
158 int ret;
159
Naomi Luisb558aed2011-12-12 12:07:48 -0800160 if (!lock->file) {
161 GENLOCK_LOG_ERR("No file attached to the lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700162 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800163 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700164
165 ret = get_unused_fd_flags(0);
166 if (ret < 0)
167 return ret;
168 fd_install(ret, lock->file);
169 return ret;
170}
171
172/**
173 * genlock_attach_lock - Attach an existing lock to a handle
174 * @handle - Pointer to a genlock handle to attach the lock to
175 * @fd - file descriptor for the exported lock
176 *
177 * Returns: A pointer to the attached lock structure
178 */
179
180struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
181{
182 struct file *file;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700183 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700184
Jordan Crousea73ed092012-01-24 15:40:22 -0700185 if (IS_ERR_OR_NULL(handle)) {
186 GENLOCK_LOG_ERR("Invalid handle\n");
187 return ERR_PTR(-EINVAL);
188 }
189
Naomi Luisb558aed2011-12-12 12:07:48 -0800190 if (handle->lock != NULL) {
191 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700192 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800193 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700194
195 file = fget(fd);
Naomi Luisb558aed2011-12-12 12:07:48 -0800196 if (file == NULL) {
197 GENLOCK_LOG_ERR("Bad file descriptor\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700198 return ERR_PTR(-EBADF);
Naomi Luisb558aed2011-12-12 12:07:48 -0800199 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700200
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700201 /*
202 * take a spinlock to avoid a race condition if the lock is
203 * released and then attached
204 */
205
206 spin_lock(&genlock_file_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700207 lock = file->private_data;
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700208 spin_unlock(&genlock_file_lock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700209
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700210 fput(file);
211
Naomi Luisb558aed2011-12-12 12:07:48 -0800212 if (lock == NULL) {
213 GENLOCK_LOG_ERR("File descriptor is invalid\n");
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700214 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800215 }
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700216
217 handle->lock = lock;
218 kref_get(&lock->refcount);
219
220 return lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700221}
222EXPORT_SYMBOL(genlock_attach_lock);
223
224/* Helper function that returns 1 if the specified handle holds the lock */
225
226static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
227{
228 struct genlock_handle *h;
229
230 list_for_each_entry(h, &lock->active, entry) {
231 if (h == handle)
232 return 1;
233 }
234
235 return 0;
236}
237
238/* If the lock just became available, signal the next entity waiting for it */
239
240static void _genlock_signal(struct genlock *lock)
241{
242 if (list_empty(&lock->active)) {
243 /* If the list is empty, then the lock is free */
244 lock->state = _UNLOCKED;
245 /* Wake up the first process sitting in the queue */
246 wake_up(&lock->queue);
247 }
248}
249
250/* Attempt to release the handle's ownership of the lock */
251
252static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
253{
254 int ret = -EINVAL;
255 unsigned long irqflags;
256
257 spin_lock_irqsave(&lock->lock, irqflags);
258
Naomi Luisb558aed2011-12-12 12:07:48 -0800259 if (lock->state == _UNLOCKED) {
260 GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700261 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800262 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700263
264 /* Make sure this handle is an owner of the lock */
Naomi Luisb558aed2011-12-12 12:07:48 -0800265 if (!handle_has_lock(lock, handle)) {
266 GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700267 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800268 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700269 /* If the handle holds no more references to the lock then
270 release it (maybe) */
271
272 if (--handle->active == 0) {
273 list_del(&handle->entry);
274 _genlock_signal(lock);
275 }
276
277 ret = 0;
278
279done:
280 spin_unlock_irqrestore(&lock->lock, irqflags);
281 return ret;
282}
283
284/* Attempt to acquire the lock for the handle */
285
286static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
287 int op, int flags, uint32_t timeout)
288{
289 unsigned long irqflags;
290 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600291 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700292
293 spin_lock_irqsave(&lock->lock, irqflags);
294
295 /* Sanity check - no blocking locks in a debug context. Even if it
296 * succeed to not block, the mere idea is too dangerous to continue
297 */
298
299 if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
300 BUG();
301
302 /* Fast path - the lock is unlocked, so go do the needful */
303
304 if (lock->state == _UNLOCKED)
305 goto dolock;
306
307 if (handle_has_lock(lock, handle)) {
308
309 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600310 * If the handle already holds the lock and the lock type is
311 * a read lock then just increment the active pointer. This
312 * allows the handle to do recursive read locks. Recursive
313 * write locks are not allowed in order to support
314 * synchronization within a process using a single gralloc
315 * handle.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700316 */
317
Jeff Boody6d9076f2012-04-26 11:12:44 -0600318 if (lock->state == _RDLOCK && op == _RDLOCK) {
Jordan Crouse29f66af2011-11-17 13:39:20 -0700319 handle->active++;
320 goto done;
321 }
322
323 /*
324 * If the handle holds a write lock then the owner can switch
325 * to a read lock if they want. Do the transition atomically
326 * then wake up any pending waiters in case they want a read
Jeff Boody6d9076f2012-04-26 11:12:44 -0600327 * lock too. In order to support synchronization within a
328 * process the caller must explicity request to convert the
329 * lock type with the GENLOCK_WRITE_TO_READ flag.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700330 */
331
Jeff Boody6d9076f2012-04-26 11:12:44 -0600332 if (flags & GENLOCK_WRITE_TO_READ) {
333 if (lock->state == _WRLOCK && op == _RDLOCK) {
334 lock->state = _RDLOCK;
335 wake_up(&lock->queue);
336 goto done;
337 } else {
338 GENLOCK_LOG_ERR("Invalid state to convert"
339 "write to read\n");
340 ret = -EINVAL;
341 goto done;
342 }
343 }
344 } else {
345
346 /*
347 * Check to ensure the caller has not attempted to convert a
348 * write to a read without holding the lock.
349 */
350
351 if (flags & GENLOCK_WRITE_TO_READ) {
352 GENLOCK_LOG_ERR("Handle must have lock to convert"
353 "write to read\n");
354 ret = -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700355 goto done;
356 }
357
358 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600359 * If we request a read and the lock is held by a read, then go
360 * ahead and share the lock
Jordan Crouse29f66af2011-11-17 13:39:20 -0700361 */
Jeff Boody6d9076f2012-04-26 11:12:44 -0600362
363 if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
364 goto dolock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700365 }
366
Jordan Crouse29f66af2011-11-17 13:39:20 -0700367 /* Treat timeout 0 just like a NOBLOCK flag and return if the
368 lock cannot be aquired without blocking */
369
370 if (flags & GENLOCK_NOBLOCK || timeout == 0) {
371 ret = -EAGAIN;
372 goto done;
373 }
374
Jeff Boody6d9076f2012-04-26 11:12:44 -0600375 /*
376 * Wait while the lock remains in an incompatible state
377 * state op wait
378 * -------------------
379 * unlocked n/a no
380 * read read no
381 * read write yes
382 * write n/a yes
383 */
Jordan Crouse29f66af2011-11-17 13:39:20 -0700384
Jeff Boody6d9076f2012-04-26 11:12:44 -0600385 while ((lock->state == _RDLOCK && op == _WRLOCK) ||
386 lock->state == _WRLOCK) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600387 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700388
389 spin_unlock_irqrestore(&lock->lock, irqflags);
390
391 elapsed = wait_event_interruptible_timeout(lock->queue,
Jeff Boody6d9076f2012-04-26 11:12:44 -0600392 lock->state == _UNLOCKED ||
393 (lock->state == _RDLOCK && op == _RDLOCK),
394 ticks);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700395
396 spin_lock_irqsave(&lock->lock, irqflags);
397
398 if (elapsed <= 0) {
399 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
400 goto done;
401 }
402
Jordan Crousebe669bc2012-03-20 14:09:29 -0600403 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700404 }
405
406dolock:
407 /* We can now get the lock, add ourselves to the list of owners */
408
409 list_add_tail(&handle->entry, &lock->active);
410 lock->state = op;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600411 handle->active++;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700412
413done:
414 spin_unlock_irqrestore(&lock->lock, irqflags);
415 return ret;
416
417}
418
419/**
Jeff Boody6d9076f2012-04-26 11:12:44 -0600420 * genlock_lock - Acquire or release a lock (depreciated)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700421 * @handle - pointer to the genlock handle that is requesting the lock
422 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
423 * @flags - flags to control the operation
424 * @timeout - optional timeout to wait for the lock to come free
425 *
426 * Returns: 0 on success or error code on failure
427 */
428
429int genlock_lock(struct genlock_handle *handle, int op, int flags,
430 uint32_t timeout)
431{
Jordan Crousea73ed092012-01-24 15:40:22 -0700432 struct genlock *lock;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600433 unsigned long irqflags;
434
435 int ret = 0;
436
437 if (IS_ERR_OR_NULL(handle)) {
438 GENLOCK_LOG_ERR("Invalid handle\n");
439 return -EINVAL;
440 }
441
442 lock = handle->lock;
443
444 if (lock == NULL) {
445 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
446 return -EINVAL;
447 }
448
449 switch (op) {
450 case GENLOCK_UNLOCK:
451 ret = _genlock_unlock(lock, handle);
452 break;
453 case GENLOCK_RDLOCK:
454 spin_lock_irqsave(&lock->lock, irqflags);
455 if (handle_has_lock(lock, handle)) {
456 /* request the WRITE_TO_READ flag for compatibility */
457 flags |= GENLOCK_WRITE_TO_READ;
458 }
459 spin_unlock_irqrestore(&lock->lock, irqflags);
460 /* fall through to take lock */
461 case GENLOCK_WRLOCK:
462 ret = _genlock_lock(lock, handle, op, flags, timeout);
463 break;
464 default:
465 GENLOCK_LOG_ERR("Invalid lock operation\n");
466 ret = -EINVAL;
467 break;
468 }
469
470 return ret;
471}
472EXPORT_SYMBOL(genlock_lock);
473
474/**
475 * genlock_dreadlock - Acquire or release a lock
476 * @handle - pointer to the genlock handle that is requesting the lock
477 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
478 * @flags - flags to control the operation
479 * @timeout - optional timeout to wait for the lock to come free
480 *
481 * Returns: 0 on success or error code on failure
482 */
483
484int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
485 uint32_t timeout)
486{
487 struct genlock *lock;
Jordan Crousea73ed092012-01-24 15:40:22 -0700488
Jordan Crouse29f66af2011-11-17 13:39:20 -0700489 int ret = 0;
490
Jordan Crousea73ed092012-01-24 15:40:22 -0700491 if (IS_ERR_OR_NULL(handle)) {
492 GENLOCK_LOG_ERR("Invalid handle\n");
493 return -EINVAL;
494 }
495
496 lock = handle->lock;
497
Naomi Luisb558aed2011-12-12 12:07:48 -0800498 if (lock == NULL) {
499 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700500 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800501 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700502
503 switch (op) {
504 case GENLOCK_UNLOCK:
505 ret = _genlock_unlock(lock, handle);
506 break;
507 case GENLOCK_RDLOCK:
508 case GENLOCK_WRLOCK:
509 ret = _genlock_lock(lock, handle, op, flags, timeout);
510 break;
511 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800512 GENLOCK_LOG_ERR("Invalid lock operation\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700513 ret = -EINVAL;
514 break;
515 }
516
517 return ret;
518}
Jeff Boody6d9076f2012-04-26 11:12:44 -0600519EXPORT_SYMBOL(genlock_dreadlock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700520
521/**
522 * genlock_wait - Wait for the lock to be released
523 * @handle - pointer to the genlock handle that is waiting for the lock
524 * @timeout - optional timeout to wait for the lock to get released
525 */
526
527int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
528{
Jordan Crousea73ed092012-01-24 15:40:22 -0700529 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700530 unsigned long irqflags;
531 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600532 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700533
Jordan Crousea73ed092012-01-24 15:40:22 -0700534 if (IS_ERR_OR_NULL(handle)) {
535 GENLOCK_LOG_ERR("Invalid handle\n");
536 return -EINVAL;
537 }
538
539 lock = handle->lock;
540
Naomi Luisb558aed2011-12-12 12:07:48 -0800541 if (lock == NULL) {
542 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700543 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800544 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700545
546 spin_lock_irqsave(&lock->lock, irqflags);
547
548 /*
549 * if timeout is 0 and the lock is already unlocked, then success
550 * otherwise return -EAGAIN
551 */
552
553 if (timeout == 0) {
554 ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
555 goto done;
556 }
557
558 while (lock->state != _UNLOCKED) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600559 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700560
561 spin_unlock_irqrestore(&lock->lock, irqflags);
562
563 elapsed = wait_event_interruptible_timeout(lock->queue,
564 lock->state == _UNLOCKED, ticks);
565
566 spin_lock_irqsave(&lock->lock, irqflags);
567
568 if (elapsed <= 0) {
569 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
570 break;
571 }
572
Jordan Crousebe669bc2012-03-20 14:09:29 -0600573 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700574 }
575
576done:
577 spin_unlock_irqrestore(&lock->lock, irqflags);
578 return ret;
579}
580
Jordan Crouse4df70a22012-01-25 14:40:51 -0700581static void genlock_release_lock(struct genlock_handle *handle)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700582{
583 unsigned long flags;
584
585 if (handle == NULL || handle->lock == NULL)
586 return;
587
588 spin_lock_irqsave(&handle->lock->lock, flags);
589
590 /* If the handle is holding the lock, then force it closed */
591
592 if (handle_has_lock(handle->lock, handle)) {
593 list_del(&handle->entry);
594 _genlock_signal(handle->lock);
595 }
596 spin_unlock_irqrestore(&handle->lock->lock, flags);
597
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700598 kref_put(&handle->lock->refcount, genlock_destroy);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700599 handle->lock = NULL;
600 handle->active = 0;
601}
Jordan Crouse29f66af2011-11-17 13:39:20 -0700602
603/*
604 * Release function called when all references to a handle are released
605 */
606
607static int genlock_handle_release(struct inode *inodep, struct file *file)
608{
609 struct genlock_handle *handle = file->private_data;
610
611 genlock_release_lock(handle);
612 kfree(handle);
613
614 return 0;
615}
616
617static const struct file_operations genlock_handle_fops = {
618 .release = genlock_handle_release
619};
620
621/*
622 * Allocate a new genlock handle
623 */
624
625static struct genlock_handle *_genlock_get_handle(void)
626{
627 struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800628 if (handle == NULL) {
629 GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700630 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800631 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700632
633 return handle;
634}
635
636/**
637 * genlock_get_handle - Create a new genlock handle
638 *
639 * Returns: A pointer to a new genlock handle
640 */
641
642struct genlock_handle *genlock_get_handle(void)
643{
644 struct genlock_handle *handle = _genlock_get_handle();
645 if (IS_ERR(handle))
646 return handle;
647
648 handle->file = anon_inode_getfile("genlock-handle",
649 &genlock_handle_fops, handle, O_RDWR);
650
651 return handle;
652}
653EXPORT_SYMBOL(genlock_get_handle);
654
655/**
656 * genlock_put_handle - release a reference to a genlock handle
657 * @handle - A pointer to the handle to release
658 */
659
660void genlock_put_handle(struct genlock_handle *handle)
661{
662 if (handle)
663 fput(handle->file);
664}
665EXPORT_SYMBOL(genlock_put_handle);
666
667/**
668 * genlock_get_handle_fd - Get a handle reference from a file descriptor
669 * @fd - The file descriptor for a genlock handle
670 */
671
672struct genlock_handle *genlock_get_handle_fd(int fd)
673{
674 struct file *file = fget(fd);
675
676 if (file == NULL)
677 return ERR_PTR(-EINVAL);
678
679 return file->private_data;
680}
681EXPORT_SYMBOL(genlock_get_handle_fd);
682
683#ifdef CONFIG_GENLOCK_MISCDEVICE
684
685static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
686 unsigned long arg)
687{
688 struct genlock_lock param;
689 struct genlock_handle *handle = filep->private_data;
690 struct genlock *lock;
691 int ret;
692
Jordan Crousea73ed092012-01-24 15:40:22 -0700693 if (IS_ERR_OR_NULL(handle))
694 return -EINVAL;
695
Jordan Crouse29f66af2011-11-17 13:39:20 -0700696 switch (cmd) {
697 case GENLOCK_IOC_NEW: {
698 lock = genlock_create_lock(handle);
699 if (IS_ERR(lock))
700 return PTR_ERR(lock);
701
702 return 0;
703 }
704 case GENLOCK_IOC_EXPORT: {
Naomi Luisb558aed2011-12-12 12:07:48 -0800705 if (handle->lock == NULL) {
706 GENLOCK_LOG_ERR("Handle does not have a lock"
707 "attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700708 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800709 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700710
711 ret = genlock_get_fd(handle->lock);
712 if (ret < 0)
713 return ret;
714
715 param.fd = ret;
716
717 if (copy_to_user((void __user *) arg, &param,
718 sizeof(param)))
719 return -EFAULT;
720
721 return 0;
722 }
723 case GENLOCK_IOC_ATTACH: {
724 if (copy_from_user(&param, (void __user *) arg,
725 sizeof(param)))
726 return -EFAULT;
727
728 lock = genlock_attach_lock(handle, param.fd);
729 if (IS_ERR(lock))
730 return PTR_ERR(lock);
731
732 return 0;
733 }
734 case GENLOCK_IOC_LOCK: {
735 if (copy_from_user(&param, (void __user *) arg,
736 sizeof(param)))
737 return -EFAULT;
738
739 return genlock_lock(handle, param.op, param.flags,
740 param.timeout);
741 }
Jeff Boody6d9076f2012-04-26 11:12:44 -0600742 case GENLOCK_IOC_DREADLOCK: {
743 if (copy_from_user(&param, (void __user *) arg,
744 sizeof(param)))
745 return -EFAULT;
746
747 return genlock_dreadlock(handle, param.op, param.flags,
748 param.timeout);
749 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700750 case GENLOCK_IOC_WAIT: {
751 if (copy_from_user(&param, (void __user *) arg,
752 sizeof(param)))
753 return -EFAULT;
754
755 return genlock_wait(handle, param.timeout);
756 }
757 case GENLOCK_IOC_RELEASE: {
Jordan Crouse4df70a22012-01-25 14:40:51 -0700758 /*
759 * Return error - this ioctl has been deprecated.
760 * Locks should only be released when the handle is
761 * destroyed
762 */
763 GENLOCK_LOG_ERR("Deprecated RELEASE ioctl called\n");
764 return -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700765 }
766 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800767 GENLOCK_LOG_ERR("Invalid ioctl\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700768 return -EINVAL;
769 }
770}
771
772static int genlock_dev_release(struct inode *inodep, struct file *file)
773{
774 struct genlock_handle *handle = file->private_data;
775
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700776 genlock_release_lock(handle);
777 kfree(handle);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700778
779 return 0;
780}
781
782static int genlock_dev_open(struct inode *inodep, struct file *file)
783{
784 struct genlock_handle *handle = _genlock_get_handle();
785 if (IS_ERR(handle))
786 return PTR_ERR(handle);
787
788 handle->file = file;
789 file->private_data = handle;
790 return 0;
791}
792
793static const struct file_operations genlock_dev_fops = {
794 .open = genlock_dev_open,
795 .release = genlock_dev_release,
796 .unlocked_ioctl = genlock_dev_ioctl,
797};
798
799static struct miscdevice genlock_dev;
800
801static int genlock_dev_init(void)
802{
803 genlock_dev.minor = MISC_DYNAMIC_MINOR;
804 genlock_dev.name = "genlock";
805 genlock_dev.fops = &genlock_dev_fops;
806 genlock_dev.parent = NULL;
807
808 return misc_register(&genlock_dev);
809}
810
811static void genlock_dev_close(void)
812{
813 misc_deregister(&genlock_dev);
814}
815
816module_init(genlock_dev_init);
817module_exit(genlock_dev_close);
818
819#endif