blob: aed71c0aaa403d69003a5e4b025a123afde7c772 [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
Jeff Boody507a9d32012-06-11 10:31:10 -060037/* The genlock magic stored in the kernel private data is used to protect
38 * against the possibility of user space passing a valid fd to a
39 * non-genlock file for genlock_attach_lock()
40 */
41#define GENLOCK_MAGIC_OK 0xD2EAD10C
42#define GENLOCK_MAGIC_BAD 0xD2EADBAD
43
Jordan Crouse29f66af2011-11-17 13:39:20 -070044struct genlock {
Jeff Boody507a9d32012-06-11 10:31:10 -060045 unsigned int magic; /* Magic for attach verification */
Jordan Crouse29f66af2011-11-17 13:39:20 -070046 struct list_head active; /* List of handles holding lock */
47 spinlock_t lock; /* Spinlock to protect the lock internals */
48 wait_queue_head_t queue; /* Holding pen for processes pending lock */
49 struct file *file; /* File structure for exported lock */
50 int state; /* Current state of the lock */
Jordan Crouse4a2879b2011-12-01 11:52:59 -070051 struct kref refcount;
Jordan Crouse29f66af2011-11-17 13:39:20 -070052};
53
54struct genlock_handle {
55 struct genlock *lock; /* Lock currently attached to the handle */
56 struct list_head entry; /* List node for attaching to a lock */
57 struct file *file; /* File structure associated with handle */
58 int active; /* Number of times the active lock has been
59 taken */
60};
61
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070062/*
63 * Create a spinlock to protect against a race condition when a lock gets
64 * released while another process tries to attach it
65 */
66
Jeff Boodyd6f534f2012-06-07 11:02:22 -060067static DEFINE_SPINLOCK(genlock_ref_lock);
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070068
Jordan Crouse4a2879b2011-12-01 11:52:59 -070069static void genlock_destroy(struct kref *kref)
70{
71 struct genlock *lock = container_of(kref, struct genlock,
72 refcount);
73
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070074 /*
75 * Clear the private data for the file descriptor in case the fd is
76 * still active after the lock gets released
77 */
78
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070079 if (lock->file)
80 lock->file->private_data = NULL;
Jeff Boody507a9d32012-06-11 10:31:10 -060081 lock->magic = GENLOCK_MAGIC_BAD;
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070082
Jordan Crouse4a2879b2011-12-01 11:52:59 -070083 kfree(lock);
84}
85
Jordan Crouse29f66af2011-11-17 13:39:20 -070086/*
87 * Release the genlock object. Called when all the references to
88 * the genlock file descriptor are released
89 */
90
91static int genlock_release(struct inode *inodep, struct file *file)
92{
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070093 struct genlock *lock = file->private_data;
94 /*
95 * Clear the refrence back to this file structure to avoid
96 * somehow reusing the lock after the file has been destroyed
97 */
98
99 if (lock)
100 lock->file = NULL;
101
Jordan Crouse29f66af2011-11-17 13:39:20 -0700102 return 0;
103}
104
105static const struct file_operations genlock_fops = {
106 .release = genlock_release,
107};
108
109/**
110 * genlock_create_lock - Create a new lock
111 * @handle - genlock handle to attach the lock to
112 *
113 * Returns: a pointer to the genlock
114 */
115
116struct genlock *genlock_create_lock(struct genlock_handle *handle)
117{
118 struct genlock *lock;
119
Jordan Crousea73ed092012-01-24 15:40:22 -0700120 if (IS_ERR_OR_NULL(handle)) {
121 GENLOCK_LOG_ERR("Invalid handle\n");
122 return ERR_PTR(-EINVAL);
123 }
124
Naomi Luisb558aed2011-12-12 12:07:48 -0800125 if (handle->lock != NULL) {
126 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700127 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800128 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700129
130 lock = kzalloc(sizeof(*lock), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800131 if (lock == NULL) {
132 GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700133 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800134 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700135
136 INIT_LIST_HEAD(&lock->active);
137 init_waitqueue_head(&lock->queue);
138 spin_lock_init(&lock->lock);
139
Jeff Boody507a9d32012-06-11 10:31:10 -0600140 lock->magic = GENLOCK_MAGIC_OK;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700141 lock->state = _UNLOCKED;
142
143 /*
144 * Create an anonyonmous inode for the object that can exported to
145 * other processes
146 */
147
148 lock->file = anon_inode_getfile("genlock", &genlock_fops,
149 lock, O_RDWR);
150
151 /* Attach the new lock to the handle */
152 handle->lock = lock;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700153 kref_init(&lock->refcount);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700154
155 return lock;
156}
157EXPORT_SYMBOL(genlock_create_lock);
158
159/*
160 * Get a file descriptor reference to a lock suitable for sharing with
161 * other processes
162 */
163
164static int genlock_get_fd(struct genlock *lock)
165{
166 int ret;
167
Naomi Luisb558aed2011-12-12 12:07:48 -0800168 if (!lock->file) {
169 GENLOCK_LOG_ERR("No file attached to the lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700170 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800171 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700172
173 ret = get_unused_fd_flags(0);
174 if (ret < 0)
175 return ret;
176 fd_install(ret, lock->file);
177 return ret;
178}
179
180/**
181 * genlock_attach_lock - Attach an existing lock to a handle
182 * @handle - Pointer to a genlock handle to attach the lock to
183 * @fd - file descriptor for the exported lock
184 *
185 * Returns: A pointer to the attached lock structure
186 */
187
188struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
189{
190 struct file *file;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700191 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700192
Jordan Crousea73ed092012-01-24 15:40:22 -0700193 if (IS_ERR_OR_NULL(handle)) {
194 GENLOCK_LOG_ERR("Invalid handle\n");
195 return ERR_PTR(-EINVAL);
196 }
197
Naomi Luisb558aed2011-12-12 12:07:48 -0800198 if (handle->lock != NULL) {
199 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700200 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800201 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700202
203 file = fget(fd);
Naomi Luisb558aed2011-12-12 12:07:48 -0800204 if (file == NULL) {
205 GENLOCK_LOG_ERR("Bad file descriptor\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700206 return ERR_PTR(-EBADF);
Naomi Luisb558aed2011-12-12 12:07:48 -0800207 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700208
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700209 /*
210 * take a spinlock to avoid a race condition if the lock is
211 * released and then attached
212 */
213
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600214 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700215 lock = file->private_data;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700216
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700217 fput(file);
218
Naomi Luisb558aed2011-12-12 12:07:48 -0800219 if (lock == NULL) {
220 GENLOCK_LOG_ERR("File descriptor is invalid\n");
Jeff Boody507a9d32012-06-11 10:31:10 -0600221 goto fail_invalid;
222 }
223
224 if (lock->magic != GENLOCK_MAGIC_OK) {
225 GENLOCK_LOG_ERR("Magic is invalid - 0x%X\n", lock->magic);
226 goto fail_invalid;
Naomi Luisb558aed2011-12-12 12:07:48 -0800227 }
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700228
229 handle->lock = lock;
230 kref_get(&lock->refcount);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600231 spin_unlock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700232
233 return lock;
Jeff Boody507a9d32012-06-11 10:31:10 -0600234
235fail_invalid:
236 spin_unlock(&genlock_ref_lock);
237 return ERR_PTR(-EINVAL);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700238}
239EXPORT_SYMBOL(genlock_attach_lock);
240
241/* Helper function that returns 1 if the specified handle holds the lock */
242
243static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
244{
245 struct genlock_handle *h;
246
247 list_for_each_entry(h, &lock->active, entry) {
248 if (h == handle)
249 return 1;
250 }
251
252 return 0;
253}
254
255/* If the lock just became available, signal the next entity waiting for it */
256
257static void _genlock_signal(struct genlock *lock)
258{
259 if (list_empty(&lock->active)) {
260 /* If the list is empty, then the lock is free */
261 lock->state = _UNLOCKED;
262 /* Wake up the first process sitting in the queue */
263 wake_up(&lock->queue);
264 }
265}
266
267/* Attempt to release the handle's ownership of the lock */
268
269static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
270{
271 int ret = -EINVAL;
272 unsigned long irqflags;
273
274 spin_lock_irqsave(&lock->lock, irqflags);
275
Naomi Luisb558aed2011-12-12 12:07:48 -0800276 if (lock->state == _UNLOCKED) {
277 GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700278 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800279 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700280
281 /* Make sure this handle is an owner of the lock */
Naomi Luisb558aed2011-12-12 12:07:48 -0800282 if (!handle_has_lock(lock, handle)) {
283 GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700284 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800285 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700286 /* If the handle holds no more references to the lock then
287 release it (maybe) */
288
289 if (--handle->active == 0) {
290 list_del(&handle->entry);
291 _genlock_signal(lock);
292 }
293
294 ret = 0;
295
296done:
297 spin_unlock_irqrestore(&lock->lock, irqflags);
298 return ret;
299}
300
301/* Attempt to acquire the lock for the handle */
302
303static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
304 int op, int flags, uint32_t timeout)
305{
306 unsigned long irqflags;
307 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600308 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700309
310 spin_lock_irqsave(&lock->lock, irqflags);
311
312 /* Sanity check - no blocking locks in a debug context. Even if it
313 * succeed to not block, the mere idea is too dangerous to continue
314 */
315
316 if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
317 BUG();
318
319 /* Fast path - the lock is unlocked, so go do the needful */
320
321 if (lock->state == _UNLOCKED)
322 goto dolock;
323
324 if (handle_has_lock(lock, handle)) {
325
326 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600327 * If the handle already holds the lock and the lock type is
328 * a read lock then just increment the active pointer. This
329 * allows the handle to do recursive read locks. Recursive
330 * write locks are not allowed in order to support
331 * synchronization within a process using a single gralloc
332 * handle.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700333 */
334
Jeff Boody6d9076f2012-04-26 11:12:44 -0600335 if (lock->state == _RDLOCK && op == _RDLOCK) {
Jordan Crouse29f66af2011-11-17 13:39:20 -0700336 handle->active++;
337 goto done;
338 }
339
340 /*
341 * If the handle holds a write lock then the owner can switch
342 * to a read lock if they want. Do the transition atomically
343 * then wake up any pending waiters in case they want a read
Jeff Boody6d9076f2012-04-26 11:12:44 -0600344 * lock too. In order to support synchronization within a
345 * process the caller must explicity request to convert the
346 * lock type with the GENLOCK_WRITE_TO_READ flag.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700347 */
348
Jeff Boody6d9076f2012-04-26 11:12:44 -0600349 if (flags & GENLOCK_WRITE_TO_READ) {
350 if (lock->state == _WRLOCK && op == _RDLOCK) {
351 lock->state = _RDLOCK;
352 wake_up(&lock->queue);
353 goto done;
354 } else {
355 GENLOCK_LOG_ERR("Invalid state to convert"
356 "write to read\n");
357 ret = -EINVAL;
358 goto done;
359 }
360 }
361 } else {
362
363 /*
364 * Check to ensure the caller has not attempted to convert a
365 * write to a read without holding the lock.
366 */
367
368 if (flags & GENLOCK_WRITE_TO_READ) {
369 GENLOCK_LOG_ERR("Handle must have lock to convert"
370 "write to read\n");
371 ret = -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700372 goto done;
373 }
374
375 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600376 * If we request a read and the lock is held by a read, then go
377 * ahead and share the lock
Jordan Crouse29f66af2011-11-17 13:39:20 -0700378 */
Jeff Boody6d9076f2012-04-26 11:12:44 -0600379
380 if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
381 goto dolock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700382 }
383
Jordan Crouse29f66af2011-11-17 13:39:20 -0700384 /* Treat timeout 0 just like a NOBLOCK flag and return if the
385 lock cannot be aquired without blocking */
386
387 if (flags & GENLOCK_NOBLOCK || timeout == 0) {
388 ret = -EAGAIN;
389 goto done;
390 }
391
Jeff Boody6d9076f2012-04-26 11:12:44 -0600392 /*
393 * Wait while the lock remains in an incompatible state
394 * state op wait
395 * -------------------
396 * unlocked n/a no
397 * read read no
398 * read write yes
399 * write n/a yes
400 */
Jordan Crouse29f66af2011-11-17 13:39:20 -0700401
Jeff Boody6d9076f2012-04-26 11:12:44 -0600402 while ((lock->state == _RDLOCK && op == _WRLOCK) ||
403 lock->state == _WRLOCK) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600404 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700405
406 spin_unlock_irqrestore(&lock->lock, irqflags);
407
408 elapsed = wait_event_interruptible_timeout(lock->queue,
Jeff Boody6d9076f2012-04-26 11:12:44 -0600409 lock->state == _UNLOCKED ||
410 (lock->state == _RDLOCK && op == _RDLOCK),
411 ticks);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700412
413 spin_lock_irqsave(&lock->lock, irqflags);
414
415 if (elapsed <= 0) {
416 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
417 goto done;
418 }
419
Jordan Crousebe669bc2012-03-20 14:09:29 -0600420 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700421 }
422
423dolock:
424 /* We can now get the lock, add ourselves to the list of owners */
425
426 list_add_tail(&handle->entry, &lock->active);
427 lock->state = op;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600428 handle->active++;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700429
430done:
431 spin_unlock_irqrestore(&lock->lock, irqflags);
432 return ret;
433
434}
435
436/**
Jeff Boody6d9076f2012-04-26 11:12:44 -0600437 * genlock_lock - Acquire or release a lock (depreciated)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700438 * @handle - pointer to the genlock handle that is requesting the lock
439 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
440 * @flags - flags to control the operation
441 * @timeout - optional timeout to wait for the lock to come free
442 *
443 * Returns: 0 on success or error code on failure
444 */
445
446int genlock_lock(struct genlock_handle *handle, int op, int flags,
447 uint32_t timeout)
448{
Jordan Crousea73ed092012-01-24 15:40:22 -0700449 struct genlock *lock;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600450 unsigned long irqflags;
451
452 int ret = 0;
453
454 if (IS_ERR_OR_NULL(handle)) {
455 GENLOCK_LOG_ERR("Invalid handle\n");
456 return -EINVAL;
457 }
458
459 lock = handle->lock;
460
461 if (lock == NULL) {
462 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
463 return -EINVAL;
464 }
465
466 switch (op) {
467 case GENLOCK_UNLOCK:
468 ret = _genlock_unlock(lock, handle);
469 break;
470 case GENLOCK_RDLOCK:
471 spin_lock_irqsave(&lock->lock, irqflags);
472 if (handle_has_lock(lock, handle)) {
473 /* request the WRITE_TO_READ flag for compatibility */
474 flags |= GENLOCK_WRITE_TO_READ;
475 }
476 spin_unlock_irqrestore(&lock->lock, irqflags);
477 /* fall through to take lock */
478 case GENLOCK_WRLOCK:
479 ret = _genlock_lock(lock, handle, op, flags, timeout);
480 break;
481 default:
482 GENLOCK_LOG_ERR("Invalid lock operation\n");
483 ret = -EINVAL;
484 break;
485 }
486
487 return ret;
488}
489EXPORT_SYMBOL(genlock_lock);
490
491/**
492 * genlock_dreadlock - Acquire or release a lock
493 * @handle - pointer to the genlock handle that is requesting the lock
494 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
495 * @flags - flags to control the operation
496 * @timeout - optional timeout to wait for the lock to come free
497 *
498 * Returns: 0 on success or error code on failure
499 */
500
501int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
502 uint32_t timeout)
503{
504 struct genlock *lock;
Jordan Crousea73ed092012-01-24 15:40:22 -0700505
Jordan Crouse29f66af2011-11-17 13:39:20 -0700506 int ret = 0;
507
Jordan Crousea73ed092012-01-24 15:40:22 -0700508 if (IS_ERR_OR_NULL(handle)) {
509 GENLOCK_LOG_ERR("Invalid handle\n");
510 return -EINVAL;
511 }
512
513 lock = handle->lock;
514
Naomi Luisb558aed2011-12-12 12:07:48 -0800515 if (lock == NULL) {
516 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700517 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800518 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700519
520 switch (op) {
521 case GENLOCK_UNLOCK:
522 ret = _genlock_unlock(lock, handle);
523 break;
524 case GENLOCK_RDLOCK:
525 case GENLOCK_WRLOCK:
526 ret = _genlock_lock(lock, handle, op, flags, timeout);
527 break;
528 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800529 GENLOCK_LOG_ERR("Invalid lock operation\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700530 ret = -EINVAL;
531 break;
532 }
533
534 return ret;
535}
Jeff Boody6d9076f2012-04-26 11:12:44 -0600536EXPORT_SYMBOL(genlock_dreadlock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700537
538/**
539 * genlock_wait - Wait for the lock to be released
540 * @handle - pointer to the genlock handle that is waiting for the lock
541 * @timeout - optional timeout to wait for the lock to get released
542 */
543
544int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
545{
Jordan Crousea73ed092012-01-24 15:40:22 -0700546 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700547 unsigned long irqflags;
548 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600549 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700550
Jordan Crousea73ed092012-01-24 15:40:22 -0700551 if (IS_ERR_OR_NULL(handle)) {
552 GENLOCK_LOG_ERR("Invalid handle\n");
553 return -EINVAL;
554 }
555
556 lock = handle->lock;
557
Naomi Luisb558aed2011-12-12 12:07:48 -0800558 if (lock == NULL) {
559 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700560 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800561 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700562
563 spin_lock_irqsave(&lock->lock, irqflags);
564
565 /*
566 * if timeout is 0 and the lock is already unlocked, then success
567 * otherwise return -EAGAIN
568 */
569
570 if (timeout == 0) {
571 ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
572 goto done;
573 }
574
575 while (lock->state != _UNLOCKED) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600576 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700577
578 spin_unlock_irqrestore(&lock->lock, irqflags);
579
580 elapsed = wait_event_interruptible_timeout(lock->queue,
581 lock->state == _UNLOCKED, ticks);
582
583 spin_lock_irqsave(&lock->lock, irqflags);
584
585 if (elapsed <= 0) {
586 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
587 break;
588 }
589
Jordan Crousebe669bc2012-03-20 14:09:29 -0600590 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700591 }
592
593done:
594 spin_unlock_irqrestore(&lock->lock, irqflags);
595 return ret;
596}
597
Jordan Crouse4df70a22012-01-25 14:40:51 -0700598static void genlock_release_lock(struct genlock_handle *handle)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700599{
600 unsigned long flags;
601
602 if (handle == NULL || handle->lock == NULL)
603 return;
604
605 spin_lock_irqsave(&handle->lock->lock, flags);
606
607 /* If the handle is holding the lock, then force it closed */
608
609 if (handle_has_lock(handle->lock, handle)) {
610 list_del(&handle->entry);
611 _genlock_signal(handle->lock);
612 }
613 spin_unlock_irqrestore(&handle->lock->lock, flags);
614
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600615 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700616 kref_put(&handle->lock->refcount, genlock_destroy);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600617 spin_unlock(&genlock_ref_lock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700618 handle->lock = NULL;
619 handle->active = 0;
620}
Jordan Crouse29f66af2011-11-17 13:39:20 -0700621
622/*
623 * Release function called when all references to a handle are released
624 */
625
626static int genlock_handle_release(struct inode *inodep, struct file *file)
627{
628 struct genlock_handle *handle = file->private_data;
629
630 genlock_release_lock(handle);
631 kfree(handle);
632
633 return 0;
634}
635
636static const struct file_operations genlock_handle_fops = {
637 .release = genlock_handle_release
638};
639
640/*
641 * Allocate a new genlock handle
642 */
643
644static struct genlock_handle *_genlock_get_handle(void)
645{
646 struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800647 if (handle == NULL) {
648 GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700649 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800650 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700651
652 return handle;
653}
654
655/**
656 * genlock_get_handle - Create a new genlock handle
657 *
658 * Returns: A pointer to a new genlock handle
659 */
660
661struct genlock_handle *genlock_get_handle(void)
662{
663 struct genlock_handle *handle = _genlock_get_handle();
664 if (IS_ERR(handle))
665 return handle;
666
667 handle->file = anon_inode_getfile("genlock-handle",
668 &genlock_handle_fops, handle, O_RDWR);
669
670 return handle;
671}
672EXPORT_SYMBOL(genlock_get_handle);
673
674/**
675 * genlock_put_handle - release a reference to a genlock handle
676 * @handle - A pointer to the handle to release
677 */
678
679void genlock_put_handle(struct genlock_handle *handle)
680{
681 if (handle)
682 fput(handle->file);
683}
684EXPORT_SYMBOL(genlock_put_handle);
685
686/**
687 * genlock_get_handle_fd - Get a handle reference from a file descriptor
688 * @fd - The file descriptor for a genlock handle
689 */
690
691struct genlock_handle *genlock_get_handle_fd(int fd)
692{
693 struct file *file = fget(fd);
694
695 if (file == NULL)
696 return ERR_PTR(-EINVAL);
697
698 return file->private_data;
699}
700EXPORT_SYMBOL(genlock_get_handle_fd);
701
702#ifdef CONFIG_GENLOCK_MISCDEVICE
703
704static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
705 unsigned long arg)
706{
707 struct genlock_lock param;
708 struct genlock_handle *handle = filep->private_data;
709 struct genlock *lock;
710 int ret;
711
Jordan Crousea73ed092012-01-24 15:40:22 -0700712 if (IS_ERR_OR_NULL(handle))
713 return -EINVAL;
714
Jordan Crouse29f66af2011-11-17 13:39:20 -0700715 switch (cmd) {
716 case GENLOCK_IOC_NEW: {
717 lock = genlock_create_lock(handle);
718 if (IS_ERR(lock))
719 return PTR_ERR(lock);
720
721 return 0;
722 }
723 case GENLOCK_IOC_EXPORT: {
Naomi Luisb558aed2011-12-12 12:07:48 -0800724 if (handle->lock == NULL) {
725 GENLOCK_LOG_ERR("Handle does not have a lock"
726 "attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700727 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800728 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700729
730 ret = genlock_get_fd(handle->lock);
731 if (ret < 0)
732 return ret;
733
734 param.fd = ret;
735
736 if (copy_to_user((void __user *) arg, &param,
737 sizeof(param)))
738 return -EFAULT;
739
740 return 0;
741 }
742 case GENLOCK_IOC_ATTACH: {
743 if (copy_from_user(&param, (void __user *) arg,
744 sizeof(param)))
745 return -EFAULT;
746
747 lock = genlock_attach_lock(handle, param.fd);
748 if (IS_ERR(lock))
749 return PTR_ERR(lock);
750
751 return 0;
752 }
753 case GENLOCK_IOC_LOCK: {
754 if (copy_from_user(&param, (void __user *) arg,
755 sizeof(param)))
756 return -EFAULT;
757
758 return genlock_lock(handle, param.op, param.flags,
759 param.timeout);
760 }
Jeff Boody6d9076f2012-04-26 11:12:44 -0600761 case GENLOCK_IOC_DREADLOCK: {
762 if (copy_from_user(&param, (void __user *) arg,
763 sizeof(param)))
764 return -EFAULT;
765
766 return genlock_dreadlock(handle, param.op, param.flags,
767 param.timeout);
768 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700769 case GENLOCK_IOC_WAIT: {
770 if (copy_from_user(&param, (void __user *) arg,
771 sizeof(param)))
772 return -EFAULT;
773
774 return genlock_wait(handle, param.timeout);
775 }
776 case GENLOCK_IOC_RELEASE: {
Jordan Crouse4df70a22012-01-25 14:40:51 -0700777 /*
778 * Return error - this ioctl has been deprecated.
779 * Locks should only be released when the handle is
780 * destroyed
781 */
782 GENLOCK_LOG_ERR("Deprecated RELEASE ioctl called\n");
783 return -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700784 }
785 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800786 GENLOCK_LOG_ERR("Invalid ioctl\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700787 return -EINVAL;
788 }
789}
790
791static int genlock_dev_release(struct inode *inodep, struct file *file)
792{
793 struct genlock_handle *handle = file->private_data;
794
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700795 genlock_release_lock(handle);
796 kfree(handle);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700797
798 return 0;
799}
800
801static int genlock_dev_open(struct inode *inodep, struct file *file)
802{
803 struct genlock_handle *handle = _genlock_get_handle();
804 if (IS_ERR(handle))
805 return PTR_ERR(handle);
806
807 handle->file = file;
808 file->private_data = handle;
809 return 0;
810}
811
812static const struct file_operations genlock_dev_fops = {
813 .open = genlock_dev_open,
814 .release = genlock_dev_release,
815 .unlocked_ioctl = genlock_dev_ioctl,
816};
817
818static struct miscdevice genlock_dev;
819
820static int genlock_dev_init(void)
821{
822 genlock_dev.minor = MISC_DYNAMIC_MINOR;
823 genlock_dev.name = "genlock";
824 genlock_dev.fops = &genlock_dev_fops;
825 genlock_dev.parent = NULL;
826
827 return misc_register(&genlock_dev);
828}
829
830static void genlock_dev_close(void)
831{
832 misc_deregister(&genlock_dev);
833}
834
835module_init(genlock_dev_init);
836module_exit(genlock_dev_close);
837
838#endif