blob: 58b05139ca701a4e6dec7093d104bb1bac8b1746 [file] [log] [blame]
Alex Wong7cf76c92013-04-02 23:04:25 -07001/* Copyright (c) 2011-2013, The Linux Foundation. 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;
Jeff Boodydc6023b2012-07-19 14:19:12 -0600119 void *ret;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700120
Jordan Crousea73ed092012-01-24 15:40:22 -0700121 if (IS_ERR_OR_NULL(handle)) {
122 GENLOCK_LOG_ERR("Invalid handle\n");
123 return ERR_PTR(-EINVAL);
124 }
125
Naomi Luisb558aed2011-12-12 12:07:48 -0800126 if (handle->lock != NULL) {
127 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700128 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800129 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700130
131 lock = kzalloc(sizeof(*lock), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800132 if (lock == NULL) {
133 GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700134 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800135 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700136
137 INIT_LIST_HEAD(&lock->active);
138 init_waitqueue_head(&lock->queue);
139 spin_lock_init(&lock->lock);
140
Jeff Boody507a9d32012-06-11 10:31:10 -0600141 lock->magic = GENLOCK_MAGIC_OK;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700142 lock->state = _UNLOCKED;
143
144 /*
145 * Create an anonyonmous inode for the object that can exported to
146 * other processes
147 */
148
Jeff Boodydc6023b2012-07-19 14:19:12 -0600149 ret = anon_inode_getfile("genlock", &genlock_fops, lock, O_RDWR);
150 if (IS_ERR_OR_NULL(ret)) {
151 GENLOCK_LOG_ERR("Unable to create lock inode\n");
152 kfree(lock);
153 return ret;
154 }
155 lock->file = ret;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700156
157 /* Attach the new lock to the handle */
158 handle->lock = lock;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700159 kref_init(&lock->refcount);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700160
161 return lock;
162}
163EXPORT_SYMBOL(genlock_create_lock);
164
165/*
166 * Get a file descriptor reference to a lock suitable for sharing with
167 * other processes
168 */
169
170static int genlock_get_fd(struct genlock *lock)
171{
172 int ret;
173
Naomi Luisb558aed2011-12-12 12:07:48 -0800174 if (!lock->file) {
175 GENLOCK_LOG_ERR("No file attached to the lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700176 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800177 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700178
179 ret = get_unused_fd_flags(0);
180 if (ret < 0)
181 return ret;
182 fd_install(ret, lock->file);
183 return ret;
184}
185
186/**
187 * genlock_attach_lock - Attach an existing lock to a handle
188 * @handle - Pointer to a genlock handle to attach the lock to
189 * @fd - file descriptor for the exported lock
190 *
191 * Returns: A pointer to the attached lock structure
192 */
193
194struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
195{
196 struct file *file;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700197 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700198
Jordan Crousea73ed092012-01-24 15:40:22 -0700199 if (IS_ERR_OR_NULL(handle)) {
200 GENLOCK_LOG_ERR("Invalid handle\n");
201 return ERR_PTR(-EINVAL);
202 }
203
Naomi Luisb558aed2011-12-12 12:07:48 -0800204 if (handle->lock != NULL) {
205 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700206 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800207 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700208
209 file = fget(fd);
Naomi Luisb558aed2011-12-12 12:07:48 -0800210 if (file == NULL) {
211 GENLOCK_LOG_ERR("Bad file descriptor\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700212 return ERR_PTR(-EBADF);
Naomi Luisb558aed2011-12-12 12:07:48 -0800213 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700214
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700215 /*
216 * take a spinlock to avoid a race condition if the lock is
217 * released and then attached
218 */
219
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600220 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700221 lock = file->private_data;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700222
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700223 fput(file);
224
Naomi Luisb558aed2011-12-12 12:07:48 -0800225 if (lock == NULL) {
226 GENLOCK_LOG_ERR("File descriptor is invalid\n");
Jeff Boody507a9d32012-06-11 10:31:10 -0600227 goto fail_invalid;
228 }
229
230 if (lock->magic != GENLOCK_MAGIC_OK) {
231 GENLOCK_LOG_ERR("Magic is invalid - 0x%X\n", lock->magic);
232 goto fail_invalid;
Naomi Luisb558aed2011-12-12 12:07:48 -0800233 }
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700234
235 handle->lock = lock;
236 kref_get(&lock->refcount);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600237 spin_unlock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700238
239 return lock;
Jeff Boody507a9d32012-06-11 10:31:10 -0600240
241fail_invalid:
242 spin_unlock(&genlock_ref_lock);
243 return ERR_PTR(-EINVAL);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700244}
245EXPORT_SYMBOL(genlock_attach_lock);
246
247/* Helper function that returns 1 if the specified handle holds the lock */
248
249static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
250{
251 struct genlock_handle *h;
252
253 list_for_each_entry(h, &lock->active, entry) {
254 if (h == handle)
255 return 1;
256 }
257
258 return 0;
259}
260
261/* If the lock just became available, signal the next entity waiting for it */
262
263static void _genlock_signal(struct genlock *lock)
264{
265 if (list_empty(&lock->active)) {
266 /* If the list is empty, then the lock is free */
267 lock->state = _UNLOCKED;
268 /* Wake up the first process sitting in the queue */
269 wake_up(&lock->queue);
270 }
271}
272
273/* Attempt to release the handle's ownership of the lock */
274
275static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
276{
277 int ret = -EINVAL;
278 unsigned long irqflags;
279
280 spin_lock_irqsave(&lock->lock, irqflags);
281
Naomi Luisb558aed2011-12-12 12:07:48 -0800282 if (lock->state == _UNLOCKED) {
283 GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\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
287 /* Make sure this handle is an owner of the lock */
Naomi Luisb558aed2011-12-12 12:07:48 -0800288 if (!handle_has_lock(lock, handle)) {
289 GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700290 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800291 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700292 /* If the handle holds no more references to the lock then
293 release it (maybe) */
294
295 if (--handle->active == 0) {
296 list_del(&handle->entry);
297 _genlock_signal(lock);
298 }
299
300 ret = 0;
301
302done:
303 spin_unlock_irqrestore(&lock->lock, irqflags);
304 return ret;
305}
306
307/* Attempt to acquire the lock for the handle */
308
309static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
310 int op, int flags, uint32_t timeout)
311{
312 unsigned long irqflags;
313 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600314 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700315
316 spin_lock_irqsave(&lock->lock, irqflags);
317
318 /* Sanity check - no blocking locks in a debug context. Even if it
319 * succeed to not block, the mere idea is too dangerous to continue
320 */
321
322 if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
323 BUG();
324
325 /* Fast path - the lock is unlocked, so go do the needful */
326
327 if (lock->state == _UNLOCKED)
328 goto dolock;
329
330 if (handle_has_lock(lock, handle)) {
331
332 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600333 * If the handle already holds the lock and the lock type is
334 * a read lock then just increment the active pointer. This
335 * allows the handle to do recursive read locks. Recursive
336 * write locks are not allowed in order to support
337 * synchronization within a process using a single gralloc
338 * handle.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700339 */
340
Jeff Boody6d9076f2012-04-26 11:12:44 -0600341 if (lock->state == _RDLOCK && op == _RDLOCK) {
Jordan Crouse29f66af2011-11-17 13:39:20 -0700342 handle->active++;
343 goto done;
344 }
345
346 /*
347 * If the handle holds a write lock then the owner can switch
348 * to a read lock if they want. Do the transition atomically
349 * then wake up any pending waiters in case they want a read
Jeff Boody6d9076f2012-04-26 11:12:44 -0600350 * lock too. In order to support synchronization within a
351 * process the caller must explicity request to convert the
352 * lock type with the GENLOCK_WRITE_TO_READ flag.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700353 */
354
Jeff Boody6d9076f2012-04-26 11:12:44 -0600355 if (flags & GENLOCK_WRITE_TO_READ) {
356 if (lock->state == _WRLOCK && op == _RDLOCK) {
357 lock->state = _RDLOCK;
358 wake_up(&lock->queue);
359 goto done;
360 } else {
361 GENLOCK_LOG_ERR("Invalid state to convert"
362 "write to read\n");
363 ret = -EINVAL;
364 goto done;
365 }
366 }
367 } else {
368
369 /*
370 * Check to ensure the caller has not attempted to convert a
371 * write to a read without holding the lock.
372 */
373
374 if (flags & GENLOCK_WRITE_TO_READ) {
375 GENLOCK_LOG_ERR("Handle must have lock to convert"
376 "write to read\n");
377 ret = -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700378 goto done;
379 }
380
381 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600382 * If we request a read and the lock is held by a read, then go
383 * ahead and share the lock
Jordan Crouse29f66af2011-11-17 13:39:20 -0700384 */
Jeff Boody6d9076f2012-04-26 11:12:44 -0600385
386 if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
387 goto dolock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700388 }
389
Jordan Crouse29f66af2011-11-17 13:39:20 -0700390 /* Treat timeout 0 just like a NOBLOCK flag and return if the
391 lock cannot be aquired without blocking */
392
393 if (flags & GENLOCK_NOBLOCK || timeout == 0) {
394 ret = -EAGAIN;
395 goto done;
396 }
397
Jeff Boody6d9076f2012-04-26 11:12:44 -0600398 /*
399 * Wait while the lock remains in an incompatible state
400 * state op wait
401 * -------------------
402 * unlocked n/a no
403 * read read no
404 * read write yes
405 * write n/a yes
406 */
Jordan Crouse29f66af2011-11-17 13:39:20 -0700407
Jeff Boody6d9076f2012-04-26 11:12:44 -0600408 while ((lock->state == _RDLOCK && op == _WRLOCK) ||
409 lock->state == _WRLOCK) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600410 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700411
412 spin_unlock_irqrestore(&lock->lock, irqflags);
413
414 elapsed = wait_event_interruptible_timeout(lock->queue,
Jeff Boody6d9076f2012-04-26 11:12:44 -0600415 lock->state == _UNLOCKED ||
416 (lock->state == _RDLOCK && op == _RDLOCK),
417 ticks);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700418
419 spin_lock_irqsave(&lock->lock, irqflags);
420
421 if (elapsed <= 0) {
422 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
423 goto done;
424 }
425
Jordan Crousebe669bc2012-03-20 14:09:29 -0600426 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700427 }
428
429dolock:
430 /* We can now get the lock, add ourselves to the list of owners */
431
432 list_add_tail(&handle->entry, &lock->active);
433 lock->state = op;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600434 handle->active++;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700435
436done:
437 spin_unlock_irqrestore(&lock->lock, irqflags);
438 return ret;
439
440}
441
442/**
Jeff Boody6d9076f2012-04-26 11:12:44 -0600443 * genlock_lock - Acquire or release a lock (depreciated)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700444 * @handle - pointer to the genlock handle that is requesting the lock
445 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
446 * @flags - flags to control the operation
447 * @timeout - optional timeout to wait for the lock to come free
448 *
449 * Returns: 0 on success or error code on failure
450 */
451
452int genlock_lock(struct genlock_handle *handle, int op, int flags,
453 uint32_t timeout)
454{
Jordan Crousea73ed092012-01-24 15:40:22 -0700455 struct genlock *lock;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600456 unsigned long irqflags;
457
458 int ret = 0;
459
460 if (IS_ERR_OR_NULL(handle)) {
461 GENLOCK_LOG_ERR("Invalid handle\n");
462 return -EINVAL;
463 }
464
465 lock = handle->lock;
466
467 if (lock == NULL) {
468 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
469 return -EINVAL;
470 }
471
472 switch (op) {
473 case GENLOCK_UNLOCK:
474 ret = _genlock_unlock(lock, handle);
475 break;
476 case GENLOCK_RDLOCK:
477 spin_lock_irqsave(&lock->lock, irqflags);
478 if (handle_has_lock(lock, handle)) {
479 /* request the WRITE_TO_READ flag for compatibility */
480 flags |= GENLOCK_WRITE_TO_READ;
481 }
482 spin_unlock_irqrestore(&lock->lock, irqflags);
483 /* fall through to take lock */
484 case GENLOCK_WRLOCK:
485 ret = _genlock_lock(lock, handle, op, flags, timeout);
486 break;
487 default:
488 GENLOCK_LOG_ERR("Invalid lock operation\n");
489 ret = -EINVAL;
490 break;
491 }
492
493 return ret;
494}
495EXPORT_SYMBOL(genlock_lock);
496
497/**
498 * genlock_dreadlock - Acquire or release a lock
499 * @handle - pointer to the genlock handle that is requesting the lock
500 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
501 * @flags - flags to control the operation
502 * @timeout - optional timeout to wait for the lock to come free
503 *
504 * Returns: 0 on success or error code on failure
505 */
506
507int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
508 uint32_t timeout)
509{
510 struct genlock *lock;
Jordan Crousea73ed092012-01-24 15:40:22 -0700511
Jordan Crouse29f66af2011-11-17 13:39:20 -0700512 int ret = 0;
513
Jordan Crousea73ed092012-01-24 15:40:22 -0700514 if (IS_ERR_OR_NULL(handle)) {
515 GENLOCK_LOG_ERR("Invalid handle\n");
516 return -EINVAL;
517 }
518
519 lock = handle->lock;
520
Naomi Luisb558aed2011-12-12 12:07:48 -0800521 if (lock == NULL) {
522 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700523 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800524 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700525
526 switch (op) {
527 case GENLOCK_UNLOCK:
528 ret = _genlock_unlock(lock, handle);
529 break;
530 case GENLOCK_RDLOCK:
531 case GENLOCK_WRLOCK:
532 ret = _genlock_lock(lock, handle, op, flags, timeout);
533 break;
534 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800535 GENLOCK_LOG_ERR("Invalid lock operation\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700536 ret = -EINVAL;
537 break;
538 }
539
540 return ret;
541}
Jeff Boody6d9076f2012-04-26 11:12:44 -0600542EXPORT_SYMBOL(genlock_dreadlock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700543
544/**
545 * genlock_wait - Wait for the lock to be released
546 * @handle - pointer to the genlock handle that is waiting for the lock
547 * @timeout - optional timeout to wait for the lock to get released
548 */
549
550int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
551{
Jordan Crousea73ed092012-01-24 15:40:22 -0700552 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700553 unsigned long irqflags;
554 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600555 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700556
Jordan Crousea73ed092012-01-24 15:40:22 -0700557 if (IS_ERR_OR_NULL(handle)) {
558 GENLOCK_LOG_ERR("Invalid handle\n");
559 return -EINVAL;
560 }
561
562 lock = handle->lock;
563
Naomi Luisb558aed2011-12-12 12:07:48 -0800564 if (lock == NULL) {
565 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700566 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800567 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700568
569 spin_lock_irqsave(&lock->lock, irqflags);
570
571 /*
572 * if timeout is 0 and the lock is already unlocked, then success
573 * otherwise return -EAGAIN
574 */
575
576 if (timeout == 0) {
577 ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
578 goto done;
579 }
580
581 while (lock->state != _UNLOCKED) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600582 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700583
584 spin_unlock_irqrestore(&lock->lock, irqflags);
585
586 elapsed = wait_event_interruptible_timeout(lock->queue,
587 lock->state == _UNLOCKED, ticks);
588
589 spin_lock_irqsave(&lock->lock, irqflags);
590
591 if (elapsed <= 0) {
592 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
593 break;
594 }
595
Jordan Crousebe669bc2012-03-20 14:09:29 -0600596 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700597 }
598
599done:
600 spin_unlock_irqrestore(&lock->lock, irqflags);
601 return ret;
602}
603
Jordan Crouse4df70a22012-01-25 14:40:51 -0700604static void genlock_release_lock(struct genlock_handle *handle)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700605{
606 unsigned long flags;
607
608 if (handle == NULL || handle->lock == NULL)
609 return;
610
611 spin_lock_irqsave(&handle->lock->lock, flags);
612
613 /* If the handle is holding the lock, then force it closed */
614
615 if (handle_has_lock(handle->lock, handle)) {
616 list_del(&handle->entry);
617 _genlock_signal(handle->lock);
618 }
619 spin_unlock_irqrestore(&handle->lock->lock, flags);
620
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600621 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700622 kref_put(&handle->lock->refcount, genlock_destroy);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600623 spin_unlock(&genlock_ref_lock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700624 handle->lock = NULL;
625 handle->active = 0;
626}
Jordan Crouse29f66af2011-11-17 13:39:20 -0700627
628/*
629 * Release function called when all references to a handle are released
630 */
631
632static int genlock_handle_release(struct inode *inodep, struct file *file)
633{
634 struct genlock_handle *handle = file->private_data;
635
636 genlock_release_lock(handle);
637 kfree(handle);
638
639 return 0;
640}
641
642static const struct file_operations genlock_handle_fops = {
643 .release = genlock_handle_release
644};
645
646/*
647 * Allocate a new genlock handle
648 */
649
650static struct genlock_handle *_genlock_get_handle(void)
651{
652 struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800653 if (handle == NULL) {
654 GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700655 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800656 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700657
658 return handle;
659}
660
661/**
662 * genlock_get_handle - Create a new genlock handle
663 *
664 * Returns: A pointer to a new genlock handle
665 */
666
667struct genlock_handle *genlock_get_handle(void)
668{
Jeff Boodydc6023b2012-07-19 14:19:12 -0600669 void *ret;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700670 struct genlock_handle *handle = _genlock_get_handle();
671 if (IS_ERR(handle))
672 return handle;
673
Jeff Boodydc6023b2012-07-19 14:19:12 -0600674 ret = anon_inode_getfile("genlock-handle",
Jordan Crouse29f66af2011-11-17 13:39:20 -0700675 &genlock_handle_fops, handle, O_RDWR);
Jeff Boodydc6023b2012-07-19 14:19:12 -0600676 if (IS_ERR_OR_NULL(ret)) {
677 GENLOCK_LOG_ERR("Unable to create handle inode\n");
678 kfree(handle);
679 return ret;
680 }
681 handle->file = ret;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700682
683 return handle;
684}
685EXPORT_SYMBOL(genlock_get_handle);
686
687/**
688 * genlock_put_handle - release a reference to a genlock handle
689 * @handle - A pointer to the handle to release
690 */
691
692void genlock_put_handle(struct genlock_handle *handle)
693{
694 if (handle)
695 fput(handle->file);
696}
697EXPORT_SYMBOL(genlock_put_handle);
698
699/**
700 * genlock_get_handle_fd - Get a handle reference from a file descriptor
701 * @fd - The file descriptor for a genlock handle
702 */
703
704struct genlock_handle *genlock_get_handle_fd(int fd)
705{
706 struct file *file = fget(fd);
707
708 if (file == NULL)
709 return ERR_PTR(-EINVAL);
710
711 return file->private_data;
712}
713EXPORT_SYMBOL(genlock_get_handle_fd);
714
Alex Wong7cf76c92013-04-02 23:04:25 -0700715/*
716 * Get a file descriptor reference to a lock suitable for sharing with
717 * other processes
718 */
719
720int genlock_get_fd_handle(struct genlock_handle *handle)
721{
722 int ret;
723 struct genlock *lock;
724
725 if (IS_ERR_OR_NULL(handle))
726 return -EINVAL;
727
728 lock = handle->lock;
729
730 if (IS_ERR(lock))
731 return PTR_ERR(lock);
732
733 if (!lock->file) {
734 GENLOCK_LOG_ERR("No file attached to the lock\n");
735 return -EINVAL;
736 }
737
738 ret = get_unused_fd_flags(0);
739
740 if (ret < 0)
741 return ret;
742
743 fd_install(ret, lock->file);
744
Deepak Kumare1c80732013-07-05 05:44:03 +0530745 /*
746 * Taking a reference for lock file.
747 * This is required as now we have two file descriptor
748 * pointing to same file. If one FD is closed, lock file
749 * will be closed. Taking this reference will make sure
750 * that file doesn't get close. This refrence will go
751 * when client will call close on this FD.
752 */
753 fget(ret);
754
Alex Wong7cf76c92013-04-02 23:04:25 -0700755 return ret;
756}
757EXPORT_SYMBOL(genlock_get_fd_handle);
758
Jordan Crouse29f66af2011-11-17 13:39:20 -0700759#ifdef CONFIG_GENLOCK_MISCDEVICE
760
761static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
762 unsigned long arg)
763{
764 struct genlock_lock param;
765 struct genlock_handle *handle = filep->private_data;
766 struct genlock *lock;
767 int ret;
768
Jordan Crousea73ed092012-01-24 15:40:22 -0700769 if (IS_ERR_OR_NULL(handle))
770 return -EINVAL;
771
Jordan Crouse29f66af2011-11-17 13:39:20 -0700772 switch (cmd) {
773 case GENLOCK_IOC_NEW: {
774 lock = genlock_create_lock(handle);
775 if (IS_ERR(lock))
776 return PTR_ERR(lock);
777
778 return 0;
779 }
780 case GENLOCK_IOC_EXPORT: {
Naomi Luisb558aed2011-12-12 12:07:48 -0800781 if (handle->lock == NULL) {
782 GENLOCK_LOG_ERR("Handle does not have a lock"
783 "attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700784 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800785 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700786
787 ret = genlock_get_fd(handle->lock);
788 if (ret < 0)
789 return ret;
790
791 param.fd = ret;
792
793 if (copy_to_user((void __user *) arg, &param,
794 sizeof(param)))
795 return -EFAULT;
796
797 return 0;
798 }
799 case GENLOCK_IOC_ATTACH: {
800 if (copy_from_user(&param, (void __user *) arg,
801 sizeof(param)))
802 return -EFAULT;
803
804 lock = genlock_attach_lock(handle, param.fd);
805 if (IS_ERR(lock))
806 return PTR_ERR(lock);
807
808 return 0;
809 }
810 case GENLOCK_IOC_LOCK: {
811 if (copy_from_user(&param, (void __user *) arg,
812 sizeof(param)))
813 return -EFAULT;
814
815 return genlock_lock(handle, param.op, param.flags,
816 param.timeout);
817 }
Jeff Boody6d9076f2012-04-26 11:12:44 -0600818 case GENLOCK_IOC_DREADLOCK: {
819 if (copy_from_user(&param, (void __user *) arg,
820 sizeof(param)))
821 return -EFAULT;
822
823 return genlock_dreadlock(handle, param.op, param.flags,
824 param.timeout);
825 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700826 case GENLOCK_IOC_WAIT: {
827 if (copy_from_user(&param, (void __user *) arg,
828 sizeof(param)))
829 return -EFAULT;
830
831 return genlock_wait(handle, param.timeout);
832 }
833 case GENLOCK_IOC_RELEASE: {
Jordan Crouse4df70a22012-01-25 14:40:51 -0700834 /*
835 * Return error - this ioctl has been deprecated.
836 * Locks should only be released when the handle is
837 * destroyed
838 */
839 GENLOCK_LOG_ERR("Deprecated RELEASE ioctl called\n");
840 return -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700841 }
842 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800843 GENLOCK_LOG_ERR("Invalid ioctl\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700844 return -EINVAL;
845 }
846}
847
848static int genlock_dev_release(struct inode *inodep, struct file *file)
849{
850 struct genlock_handle *handle = file->private_data;
851
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700852 genlock_release_lock(handle);
853 kfree(handle);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700854
855 return 0;
856}
857
858static int genlock_dev_open(struct inode *inodep, struct file *file)
859{
860 struct genlock_handle *handle = _genlock_get_handle();
861 if (IS_ERR(handle))
862 return PTR_ERR(handle);
863
864 handle->file = file;
865 file->private_data = handle;
866 return 0;
867}
868
869static const struct file_operations genlock_dev_fops = {
870 .open = genlock_dev_open,
871 .release = genlock_dev_release,
872 .unlocked_ioctl = genlock_dev_ioctl,
873};
874
875static struct miscdevice genlock_dev;
876
877static int genlock_dev_init(void)
878{
879 genlock_dev.minor = MISC_DYNAMIC_MINOR;
880 genlock_dev.name = "genlock";
881 genlock_dev.fops = &genlock_dev_fops;
882 genlock_dev.parent = NULL;
883
884 return misc_register(&genlock_dev);
885}
886
887static void genlock_dev_close(void)
888{
889 misc_deregister(&genlock_dev);
890}
891
892module_init(genlock_dev_init);
893module_exit(genlock_dev_close);
894
895#endif