blob: 0686d20f31fa337ac3d8ffcf2a4216dd4ede78e6 [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
Jeff Boodyd6f534f2012-06-07 11:02:22 -060059static DEFINE_SPINLOCK(genlock_ref_lock);
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070060
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
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070071 if (lock->file)
72 lock->file->private_data = NULL;
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070073
Jordan Crouse4a2879b2011-12-01 11:52:59 -070074 kfree(lock);
75}
76
Jordan Crouse29f66af2011-11-17 13:39:20 -070077/*
78 * Release the genlock object. Called when all the references to
79 * the genlock file descriptor are released
80 */
81
82static int genlock_release(struct inode *inodep, struct file *file)
83{
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070084 struct genlock *lock = file->private_data;
85 /*
86 * Clear the refrence back to this file structure to avoid
87 * somehow reusing the lock after the file has been destroyed
88 */
89
90 if (lock)
91 lock->file = NULL;
92
Jordan Crouse29f66af2011-11-17 13:39:20 -070093 return 0;
94}
95
96static const struct file_operations genlock_fops = {
97 .release = genlock_release,
98};
99
100/**
101 * genlock_create_lock - Create a new lock
102 * @handle - genlock handle to attach the lock to
103 *
104 * Returns: a pointer to the genlock
105 */
106
107struct genlock *genlock_create_lock(struct genlock_handle *handle)
108{
109 struct genlock *lock;
110
Jordan Crousea73ed092012-01-24 15:40:22 -0700111 if (IS_ERR_OR_NULL(handle)) {
112 GENLOCK_LOG_ERR("Invalid handle\n");
113 return ERR_PTR(-EINVAL);
114 }
115
Naomi Luisb558aed2011-12-12 12:07:48 -0800116 if (handle->lock != NULL) {
117 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700118 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800119 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700120
121 lock = kzalloc(sizeof(*lock), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800122 if (lock == NULL) {
123 GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700124 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800125 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700126
127 INIT_LIST_HEAD(&lock->active);
128 init_waitqueue_head(&lock->queue);
129 spin_lock_init(&lock->lock);
130
131 lock->state = _UNLOCKED;
132
133 /*
134 * Create an anonyonmous inode for the object that can exported to
135 * other processes
136 */
137
138 lock->file = anon_inode_getfile("genlock", &genlock_fops,
139 lock, O_RDWR);
140
141 /* Attach the new lock to the handle */
142 handle->lock = lock;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700143 kref_init(&lock->refcount);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700144
145 return lock;
146}
147EXPORT_SYMBOL(genlock_create_lock);
148
149/*
150 * Get a file descriptor reference to a lock suitable for sharing with
151 * other processes
152 */
153
154static int genlock_get_fd(struct genlock *lock)
155{
156 int ret;
157
Naomi Luisb558aed2011-12-12 12:07:48 -0800158 if (!lock->file) {
159 GENLOCK_LOG_ERR("No file attached to the lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700160 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800161 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700162
163 ret = get_unused_fd_flags(0);
164 if (ret < 0)
165 return ret;
166 fd_install(ret, lock->file);
167 return ret;
168}
169
170/**
171 * genlock_attach_lock - Attach an existing lock to a handle
172 * @handle - Pointer to a genlock handle to attach the lock to
173 * @fd - file descriptor for the exported lock
174 *
175 * Returns: A pointer to the attached lock structure
176 */
177
178struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
179{
180 struct file *file;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700181 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700182
Jordan Crousea73ed092012-01-24 15:40:22 -0700183 if (IS_ERR_OR_NULL(handle)) {
184 GENLOCK_LOG_ERR("Invalid handle\n");
185 return ERR_PTR(-EINVAL);
186 }
187
Naomi Luisb558aed2011-12-12 12:07:48 -0800188 if (handle->lock != NULL) {
189 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700190 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800191 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700192
193 file = fget(fd);
Naomi Luisb558aed2011-12-12 12:07:48 -0800194 if (file == NULL) {
195 GENLOCK_LOG_ERR("Bad file descriptor\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700196 return ERR_PTR(-EBADF);
Naomi Luisb558aed2011-12-12 12:07:48 -0800197 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700198
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700199 /*
200 * take a spinlock to avoid a race condition if the lock is
201 * released and then attached
202 */
203
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600204 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700205 lock = file->private_data;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700206
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700207 fput(file);
208
Naomi Luisb558aed2011-12-12 12:07:48 -0800209 if (lock == NULL) {
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600210 spin_unlock(&genlock_ref_lock);
Naomi Luisb558aed2011-12-12 12:07:48 -0800211 GENLOCK_LOG_ERR("File descriptor is invalid\n");
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700212 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800213 }
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700214
215 handle->lock = lock;
216 kref_get(&lock->refcount);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600217 spin_unlock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700218
219 return lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700220}
221EXPORT_SYMBOL(genlock_attach_lock);
222
223/* Helper function that returns 1 if the specified handle holds the lock */
224
225static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
226{
227 struct genlock_handle *h;
228
229 list_for_each_entry(h, &lock->active, entry) {
230 if (h == handle)
231 return 1;
232 }
233
234 return 0;
235}
236
237/* If the lock just became available, signal the next entity waiting for it */
238
239static void _genlock_signal(struct genlock *lock)
240{
241 if (list_empty(&lock->active)) {
242 /* If the list is empty, then the lock is free */
243 lock->state = _UNLOCKED;
244 /* Wake up the first process sitting in the queue */
245 wake_up(&lock->queue);
246 }
247}
248
249/* Attempt to release the handle's ownership of the lock */
250
251static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
252{
253 int ret = -EINVAL;
254 unsigned long irqflags;
255
256 spin_lock_irqsave(&lock->lock, irqflags);
257
Naomi Luisb558aed2011-12-12 12:07:48 -0800258 if (lock->state == _UNLOCKED) {
259 GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700260 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800261 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700262
263 /* Make sure this handle is an owner of the lock */
Naomi Luisb558aed2011-12-12 12:07:48 -0800264 if (!handle_has_lock(lock, handle)) {
265 GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700266 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800267 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700268 /* If the handle holds no more references to the lock then
269 release it (maybe) */
270
271 if (--handle->active == 0) {
272 list_del(&handle->entry);
273 _genlock_signal(lock);
274 }
275
276 ret = 0;
277
278done:
279 spin_unlock_irqrestore(&lock->lock, irqflags);
280 return ret;
281}
282
283/* Attempt to acquire the lock for the handle */
284
285static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
286 int op, int flags, uint32_t timeout)
287{
288 unsigned long irqflags;
289 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600290 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700291
292 spin_lock_irqsave(&lock->lock, irqflags);
293
294 /* Sanity check - no blocking locks in a debug context. Even if it
295 * succeed to not block, the mere idea is too dangerous to continue
296 */
297
298 if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
299 BUG();
300
301 /* Fast path - the lock is unlocked, so go do the needful */
302
303 if (lock->state == _UNLOCKED)
304 goto dolock;
305
306 if (handle_has_lock(lock, handle)) {
307
308 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600309 * If the handle already holds the lock and the lock type is
310 * a read lock then just increment the active pointer. This
311 * allows the handle to do recursive read locks. Recursive
312 * write locks are not allowed in order to support
313 * synchronization within a process using a single gralloc
314 * handle.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700315 */
316
Jeff Boody6d9076f2012-04-26 11:12:44 -0600317 if (lock->state == _RDLOCK && op == _RDLOCK) {
Jordan Crouse29f66af2011-11-17 13:39:20 -0700318 handle->active++;
319 goto done;
320 }
321
322 /*
323 * If the handle holds a write lock then the owner can switch
324 * to a read lock if they want. Do the transition atomically
325 * then wake up any pending waiters in case they want a read
Jeff Boody6d9076f2012-04-26 11:12:44 -0600326 * lock too. In order to support synchronization within a
327 * process the caller must explicity request to convert the
328 * lock type with the GENLOCK_WRITE_TO_READ flag.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700329 */
330
Jeff Boody6d9076f2012-04-26 11:12:44 -0600331 if (flags & GENLOCK_WRITE_TO_READ) {
332 if (lock->state == _WRLOCK && op == _RDLOCK) {
333 lock->state = _RDLOCK;
334 wake_up(&lock->queue);
335 goto done;
336 } else {
337 GENLOCK_LOG_ERR("Invalid state to convert"
338 "write to read\n");
339 ret = -EINVAL;
340 goto done;
341 }
342 }
343 } else {
344
345 /*
346 * Check to ensure the caller has not attempted to convert a
347 * write to a read without holding the lock.
348 */
349
350 if (flags & GENLOCK_WRITE_TO_READ) {
351 GENLOCK_LOG_ERR("Handle must have lock to convert"
352 "write to read\n");
353 ret = -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700354 goto done;
355 }
356
357 /*
Jeff Boody6d9076f2012-04-26 11:12:44 -0600358 * If we request a read and the lock is held by a read, then go
359 * ahead and share the lock
Jordan Crouse29f66af2011-11-17 13:39:20 -0700360 */
Jeff Boody6d9076f2012-04-26 11:12:44 -0600361
362 if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
363 goto dolock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700364 }
365
Jordan Crouse29f66af2011-11-17 13:39:20 -0700366 /* Treat timeout 0 just like a NOBLOCK flag and return if the
367 lock cannot be aquired without blocking */
368
369 if (flags & GENLOCK_NOBLOCK || timeout == 0) {
370 ret = -EAGAIN;
371 goto done;
372 }
373
Jeff Boody6d9076f2012-04-26 11:12:44 -0600374 /*
375 * Wait while the lock remains in an incompatible state
376 * state op wait
377 * -------------------
378 * unlocked n/a no
379 * read read no
380 * read write yes
381 * write n/a yes
382 */
Jordan Crouse29f66af2011-11-17 13:39:20 -0700383
Jeff Boody6d9076f2012-04-26 11:12:44 -0600384 while ((lock->state == _RDLOCK && op == _WRLOCK) ||
385 lock->state == _WRLOCK) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600386 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700387
388 spin_unlock_irqrestore(&lock->lock, irqflags);
389
390 elapsed = wait_event_interruptible_timeout(lock->queue,
Jeff Boody6d9076f2012-04-26 11:12:44 -0600391 lock->state == _UNLOCKED ||
392 (lock->state == _RDLOCK && op == _RDLOCK),
393 ticks);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700394
395 spin_lock_irqsave(&lock->lock, irqflags);
396
397 if (elapsed <= 0) {
398 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
399 goto done;
400 }
401
Jordan Crousebe669bc2012-03-20 14:09:29 -0600402 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700403 }
404
405dolock:
406 /* We can now get the lock, add ourselves to the list of owners */
407
408 list_add_tail(&handle->entry, &lock->active);
409 lock->state = op;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600410 handle->active++;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700411
412done:
413 spin_unlock_irqrestore(&lock->lock, irqflags);
414 return ret;
415
416}
417
418/**
Jeff Boody6d9076f2012-04-26 11:12:44 -0600419 * genlock_lock - Acquire or release a lock (depreciated)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700420 * @handle - pointer to the genlock handle that is requesting the lock
421 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
422 * @flags - flags to control the operation
423 * @timeout - optional timeout to wait for the lock to come free
424 *
425 * Returns: 0 on success or error code on failure
426 */
427
428int genlock_lock(struct genlock_handle *handle, int op, int flags,
429 uint32_t timeout)
430{
Jordan Crousea73ed092012-01-24 15:40:22 -0700431 struct genlock *lock;
Jeff Boody6d9076f2012-04-26 11:12:44 -0600432 unsigned long irqflags;
433
434 int ret = 0;
435
436 if (IS_ERR_OR_NULL(handle)) {
437 GENLOCK_LOG_ERR("Invalid handle\n");
438 return -EINVAL;
439 }
440
441 lock = handle->lock;
442
443 if (lock == NULL) {
444 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
445 return -EINVAL;
446 }
447
448 switch (op) {
449 case GENLOCK_UNLOCK:
450 ret = _genlock_unlock(lock, handle);
451 break;
452 case GENLOCK_RDLOCK:
453 spin_lock_irqsave(&lock->lock, irqflags);
454 if (handle_has_lock(lock, handle)) {
455 /* request the WRITE_TO_READ flag for compatibility */
456 flags |= GENLOCK_WRITE_TO_READ;
457 }
458 spin_unlock_irqrestore(&lock->lock, irqflags);
459 /* fall through to take lock */
460 case GENLOCK_WRLOCK:
461 ret = _genlock_lock(lock, handle, op, flags, timeout);
462 break;
463 default:
464 GENLOCK_LOG_ERR("Invalid lock operation\n");
465 ret = -EINVAL;
466 break;
467 }
468
469 return ret;
470}
471EXPORT_SYMBOL(genlock_lock);
472
473/**
474 * genlock_dreadlock - Acquire or release a lock
475 * @handle - pointer to the genlock handle that is requesting the lock
476 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
477 * @flags - flags to control the operation
478 * @timeout - optional timeout to wait for the lock to come free
479 *
480 * Returns: 0 on success or error code on failure
481 */
482
483int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
484 uint32_t timeout)
485{
486 struct genlock *lock;
Jordan Crousea73ed092012-01-24 15:40:22 -0700487
Jordan Crouse29f66af2011-11-17 13:39:20 -0700488 int ret = 0;
489
Jordan Crousea73ed092012-01-24 15:40:22 -0700490 if (IS_ERR_OR_NULL(handle)) {
491 GENLOCK_LOG_ERR("Invalid handle\n");
492 return -EINVAL;
493 }
494
495 lock = handle->lock;
496
Naomi Luisb558aed2011-12-12 12:07:48 -0800497 if (lock == NULL) {
498 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700499 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800500 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700501
502 switch (op) {
503 case GENLOCK_UNLOCK:
504 ret = _genlock_unlock(lock, handle);
505 break;
506 case GENLOCK_RDLOCK:
507 case GENLOCK_WRLOCK:
508 ret = _genlock_lock(lock, handle, op, flags, timeout);
509 break;
510 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800511 GENLOCK_LOG_ERR("Invalid lock operation\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700512 ret = -EINVAL;
513 break;
514 }
515
516 return ret;
517}
Jeff Boody6d9076f2012-04-26 11:12:44 -0600518EXPORT_SYMBOL(genlock_dreadlock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700519
520/**
521 * genlock_wait - Wait for the lock to be released
522 * @handle - pointer to the genlock handle that is waiting for the lock
523 * @timeout - optional timeout to wait for the lock to get released
524 */
525
526int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
527{
Jordan Crousea73ed092012-01-24 15:40:22 -0700528 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700529 unsigned long irqflags;
530 int ret = 0;
Jordan Crousebe669bc2012-03-20 14:09:29 -0600531 unsigned long ticks = msecs_to_jiffies(timeout);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700532
Jordan Crousea73ed092012-01-24 15:40:22 -0700533 if (IS_ERR_OR_NULL(handle)) {
534 GENLOCK_LOG_ERR("Invalid handle\n");
535 return -EINVAL;
536 }
537
538 lock = handle->lock;
539
Naomi Luisb558aed2011-12-12 12:07:48 -0800540 if (lock == NULL) {
541 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700542 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800543 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700544
545 spin_lock_irqsave(&lock->lock, irqflags);
546
547 /*
548 * if timeout is 0 and the lock is already unlocked, then success
549 * otherwise return -EAGAIN
550 */
551
552 if (timeout == 0) {
553 ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
554 goto done;
555 }
556
557 while (lock->state != _UNLOCKED) {
Jordan Crousebe669bc2012-03-20 14:09:29 -0600558 signed long elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700559
560 spin_unlock_irqrestore(&lock->lock, irqflags);
561
562 elapsed = wait_event_interruptible_timeout(lock->queue,
563 lock->state == _UNLOCKED, ticks);
564
565 spin_lock_irqsave(&lock->lock, irqflags);
566
567 if (elapsed <= 0) {
568 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
569 break;
570 }
571
Jordan Crousebe669bc2012-03-20 14:09:29 -0600572 ticks = (unsigned long) elapsed;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700573 }
574
575done:
576 spin_unlock_irqrestore(&lock->lock, irqflags);
577 return ret;
578}
579
Jordan Crouse4df70a22012-01-25 14:40:51 -0700580static void genlock_release_lock(struct genlock_handle *handle)
Jordan Crouse29f66af2011-11-17 13:39:20 -0700581{
582 unsigned long flags;
583
584 if (handle == NULL || handle->lock == NULL)
585 return;
586
587 spin_lock_irqsave(&handle->lock->lock, flags);
588
589 /* If the handle is holding the lock, then force it closed */
590
591 if (handle_has_lock(handle->lock, handle)) {
592 list_del(&handle->entry);
593 _genlock_signal(handle->lock);
594 }
595 spin_unlock_irqrestore(&handle->lock->lock, flags);
596
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600597 spin_lock(&genlock_ref_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700598 kref_put(&handle->lock->refcount, genlock_destroy);
Jeff Boodyd6f534f2012-06-07 11:02:22 -0600599 spin_unlock(&genlock_ref_lock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700600 handle->lock = NULL;
601 handle->active = 0;
602}
Jordan Crouse29f66af2011-11-17 13:39:20 -0700603
604/*
605 * Release function called when all references to a handle are released
606 */
607
608static int genlock_handle_release(struct inode *inodep, struct file *file)
609{
610 struct genlock_handle *handle = file->private_data;
611
612 genlock_release_lock(handle);
613 kfree(handle);
614
615 return 0;
616}
617
618static const struct file_operations genlock_handle_fops = {
619 .release = genlock_handle_release
620};
621
622/*
623 * Allocate a new genlock handle
624 */
625
626static struct genlock_handle *_genlock_get_handle(void)
627{
628 struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800629 if (handle == NULL) {
630 GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700631 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800632 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700633
634 return handle;
635}
636
637/**
638 * genlock_get_handle - Create a new genlock handle
639 *
640 * Returns: A pointer to a new genlock handle
641 */
642
643struct genlock_handle *genlock_get_handle(void)
644{
645 struct genlock_handle *handle = _genlock_get_handle();
646 if (IS_ERR(handle))
647 return handle;
648
649 handle->file = anon_inode_getfile("genlock-handle",
650 &genlock_handle_fops, handle, O_RDWR);
651
652 return handle;
653}
654EXPORT_SYMBOL(genlock_get_handle);
655
656/**
657 * genlock_put_handle - release a reference to a genlock handle
658 * @handle - A pointer to the handle to release
659 */
660
661void genlock_put_handle(struct genlock_handle *handle)
662{
663 if (handle)
664 fput(handle->file);
665}
666EXPORT_SYMBOL(genlock_put_handle);
667
668/**
669 * genlock_get_handle_fd - Get a handle reference from a file descriptor
670 * @fd - The file descriptor for a genlock handle
671 */
672
673struct genlock_handle *genlock_get_handle_fd(int fd)
674{
675 struct file *file = fget(fd);
676
677 if (file == NULL)
678 return ERR_PTR(-EINVAL);
679
680 return file->private_data;
681}
682EXPORT_SYMBOL(genlock_get_handle_fd);
683
684#ifdef CONFIG_GENLOCK_MISCDEVICE
685
686static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
687 unsigned long arg)
688{
689 struct genlock_lock param;
690 struct genlock_handle *handle = filep->private_data;
691 struct genlock *lock;
692 int ret;
693
Jordan Crousea73ed092012-01-24 15:40:22 -0700694 if (IS_ERR_OR_NULL(handle))
695 return -EINVAL;
696
Jordan Crouse29f66af2011-11-17 13:39:20 -0700697 switch (cmd) {
698 case GENLOCK_IOC_NEW: {
699 lock = genlock_create_lock(handle);
700 if (IS_ERR(lock))
701 return PTR_ERR(lock);
702
703 return 0;
704 }
705 case GENLOCK_IOC_EXPORT: {
Naomi Luisb558aed2011-12-12 12:07:48 -0800706 if (handle->lock == NULL) {
707 GENLOCK_LOG_ERR("Handle does not have a lock"
708 "attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700709 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800710 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700711
712 ret = genlock_get_fd(handle->lock);
713 if (ret < 0)
714 return ret;
715
716 param.fd = ret;
717
718 if (copy_to_user((void __user *) arg, &param,
719 sizeof(param)))
720 return -EFAULT;
721
722 return 0;
723 }
724 case GENLOCK_IOC_ATTACH: {
725 if (copy_from_user(&param, (void __user *) arg,
726 sizeof(param)))
727 return -EFAULT;
728
729 lock = genlock_attach_lock(handle, param.fd);
730 if (IS_ERR(lock))
731 return PTR_ERR(lock);
732
733 return 0;
734 }
735 case GENLOCK_IOC_LOCK: {
736 if (copy_from_user(&param, (void __user *) arg,
737 sizeof(param)))
738 return -EFAULT;
739
740 return genlock_lock(handle, param.op, param.flags,
741 param.timeout);
742 }
Jeff Boody6d9076f2012-04-26 11:12:44 -0600743 case GENLOCK_IOC_DREADLOCK: {
744 if (copy_from_user(&param, (void __user *) arg,
745 sizeof(param)))
746 return -EFAULT;
747
748 return genlock_dreadlock(handle, param.op, param.flags,
749 param.timeout);
750 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700751 case GENLOCK_IOC_WAIT: {
752 if (copy_from_user(&param, (void __user *) arg,
753 sizeof(param)))
754 return -EFAULT;
755
756 return genlock_wait(handle, param.timeout);
757 }
758 case GENLOCK_IOC_RELEASE: {
Jordan Crouse4df70a22012-01-25 14:40:51 -0700759 /*
760 * Return error - this ioctl has been deprecated.
761 * Locks should only be released when the handle is
762 * destroyed
763 */
764 GENLOCK_LOG_ERR("Deprecated RELEASE ioctl called\n");
765 return -EINVAL;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700766 }
767 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800768 GENLOCK_LOG_ERR("Invalid ioctl\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700769 return -EINVAL;
770 }
771}
772
773static int genlock_dev_release(struct inode *inodep, struct file *file)
774{
775 struct genlock_handle *handle = file->private_data;
776
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700777 genlock_release_lock(handle);
778 kfree(handle);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700779
780 return 0;
781}
782
783static int genlock_dev_open(struct inode *inodep, struct file *file)
784{
785 struct genlock_handle *handle = _genlock_get_handle();
786 if (IS_ERR(handle))
787 return PTR_ERR(handle);
788
789 handle->file = file;
790 file->private_data = handle;
791 return 0;
792}
793
794static const struct file_operations genlock_dev_fops = {
795 .open = genlock_dev_open,
796 .release = genlock_dev_release,
797 .unlocked_ioctl = genlock_dev_ioctl,
798};
799
800static struct miscdevice genlock_dev;
801
802static int genlock_dev_init(void)
803{
804 genlock_dev.minor = MISC_DYNAMIC_MINOR;
805 genlock_dev.name = "genlock";
806 genlock_dev.fops = &genlock_dev_fops;
807 genlock_dev.parent = NULL;
808
809 return misc_register(&genlock_dev);
810}
811
812static void genlock_dev_close(void)
813{
814 misc_deregister(&genlock_dev);
815}
816
817module_init(genlock_dev_init);
818module_exit(genlock_dev_close);
819
820#endif