Guest User

Untitled

a guest
Sep 21st, 2018
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 25.44 KB | None | 0 0
  1. diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
  2. new file mode 100644
  3. index 0000000..d3a44e2
  4. --- /dev/null
  5. +++ b/Documentation/genlock.txt
  6. @@ -0,0 +1,161 @@
  7. +Introduction
  8. +
  9. +'genlock' is an in-kernel API and optional userspace interface for a generic
  10. +cross-process locking mechanism. The API is designed for situations where
  11. +multiple user space processes and/or kernel drivers need to coordinate access
  12. +to a shared resource, such as a graphics buffer. The API was designed with
  13. +graphics buffers in mind, but is sufficiently generic to allow it to be
  14. +independently used with different types of resources. The chief advantage
  15. +of genlock over other cross-process locking mechanisms is that the resources
  16. +can be accessed by both userspace and kernel drivers which allows resources
  17. +to be locked or unlocked by asynchronous events in the kernel without the
  18. +intervention of user space.
  19. +
  20. +As an example, consider a graphics buffer that is shared between a rendering
  21. +application and a compositing window manager. The application renders into a
  22. +buffer. That buffer is reused by the compositing window manager as a texture.
  23. +To avoid corruption, access to the buffer needs to be restricted so that one
  24. +is not drawing on the surface while the other is reading. Locks can be
  25. +explicitly added between the rendering stages in the processes, but explicit
  26. +locks require that the application wait for rendering and purposely release the
  27. +lock. An implicit release triggered by an asynchronous event from the GPU
  28. +kernel driver, however, will let execution continue without requiring the
  29. +intercession of user space.
  30. +
  31. +SW Goals
  32. +
  33. +The genlock API implements exclusive write locks and shared read locks meaning
  34. +that there can only be one writer at a time, but multiple readers. Processes
  35. +that are unable to acquire a lock can be optionally blocked until the resource
  36. +becomes available.
  37. +
  38. +Locks are shared between processes. Each process will have its own private
  39. +instance for a lock known as a handle. Handles can be shared between user
  40. +space and kernel space to allow a kernel driver to unlock or lock a buffer
  41. +on behalf of a user process.
  42. +
  43. +Kernel API
  44. +
  45. +Access to the genlock API can either be via the in-kernel API or via an
  46. +optional character device (/dev/genlock). The character device is primarily
  47. +to be used for legacy resource sharing APIs that cannot be easily changed.
  48. +New resource sharing APIs from this point should implement a scheme specific
  49. +wrapper for locking.
  50. +
  51. +To create or attach to an existing lock, a process or kernel driver must first
  52. +create a handle. Each handle is linked to a single lock at any time. An entityi
  53. +may have multiple handles, each associated with a different lock. Once a handle
  54. +has been created, the owner may create a new lock or attach an existing lock
  55. +that has been exported from a different handle.
  56. +
  57. +Once the handle has a lock attached, the owning process may attempt to lock the
  58. +buffer for read or write. Write locks are exclusive, meaning that only one
  59. +process may acquire it at any given time. Read locks are shared, meaning that
  60. +multiple readers can hold the lock at the same time. Attempts to acquire a read
  61. +lock with a writer active or a write lock with one or more readers or writers
  62. +active will typically cause the process to block until the lock is acquired.
  63. +When the lock is released, all waiting processes will be woken up. Ownership
  64. +of the lock is reference counted, meaning that any one owner can "lock"
  65. +multiple times. The lock will only be released from the owner when all the
  66. +references to the lock are released via unlock.
  67. +
  68. +The owner of a write lock may atomically convert the lock into a read lock
  69. +(which will wake up other processes waiting for a read lock) without first
  70. +releasing the lock. The owner would simply issue a new request for a read lock.
  71. +However, the owner of a read lock cannot convert it into a write lock in the
  72. +same manner. To switch from a read lock to a write lock, the owner must
  73. +release the lock and then try to reacquire it.
  74. +
  75. +These are the in-kernel API calls that drivers can use to create and
  76. +manipulate handles and locks. Handles can either be created and managed
  77. +completely inside of kernel space, or shared from user space via a file
  78. +descriptor.
  79. +
  80. +* struct genlock_handle *genlock_get_handle(void)
  81. +Create a new handle.
  82. +
  83. +* struct genlock_handle * genlock_get_handle_fd(int fd)
  84. +Given a valid file descriptor, return the handle associated with that
  85. +descriptor.
  86. +
  87. +* void genlock_put_handle(struct genlock_handle *)
  88. +Release a handle.
  89. +
  90. +* struct genlock * genlock_create_lock(struct genlock_handle *)
  91. +Create a new lock and attach it to the handle.
  92. +
  93. +* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
  94. +Given a valid file descriptor, get the lock associated with it and attach it to
  95. +the handle.
  96. +
  97. +* void genlock_release_lock(struct genlock_handle *)
  98. +Release a lock attached to a handle.
  99. +
  100. +* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
  101. +Lock or unlock the lock attached to the handle. A zero timeout value will
  102. +be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
  103. +can be acquired without blocking then do so otherwise return -EAGAIN.
  104. +Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
  105. +acquired.
  106. +
  107. +* int genlock_wait(struct genloc_handle *, u32 timeout)
  108. +Wait for a lock held by the handle to go to the unlocked state. A non-zero
  109. +timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
  110. +0 if the lock is in an unlocked state.
  111. +
  112. +Character Device
  113. +
  114. +Opening an instance to the /dev/genlock character device will automatically
  115. +create a new handle. All ioctl functions with the exception of NEW and
  116. +RELEASE use the following parameter structure:
  117. +
  118. +struct genlock_lock {
  119. +   int fd; /* Returned by EXPORT, used by ATTACH */
  120. +   int op; /* Used by LOCK */
  121. +   int flags;  /* used by LOCK */
  122. +   u32 timeout;    /* Used by LOCK and WAIT */
  123. +}
  124. +
  125. +*GENLOCK_IOC_NEW
  126. +Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
  127. +already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
  128. +-ENOMEM if the memory for the lock can not be allocated. No data is passed
  129. +from the user for this ioctl.
  130. +
  131. +*GENLOCK_IOC_EXPORT
  132. +Export the currently attached lock to a file descriptor. The file descriptor
  133. +is returned in genlock_lock.fd.
  134. +
  135. +*GENLOCK_IOC_ATTACH
  136. +Attach an exported lock file descriptor to the current handle. Return -EINVAL
  137. +if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
  138. +it). Pass the file descriptor in genlock_lock.fd.
  139. +
  140. +*GENLOCK_IOC_LOCK
  141. +Lock or unlock the attached lock. Pass the desired operation in
  142. +genlock_lock.op:
  143. + * GENLOCK_WRLOCK - write lock
  144. + * GENLOCK_RDLOCK - read lock
  145. + * GENLOCK_UNLOCK - unlock an existing lock
  146. +
  147. +Pass flags in genlock_lock.flags:
  148. + * GENLOCK_NOBLOCK - Do not block if the lock is already taken
  149. +
  150. +Pass a timeout value in milliseconds in genlock_lock.timeout.
  151. +genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
  152. +Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
  153. +NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
  154. +expires or 0 if the lock was successful.
  155. +
  156. +* GENLOCK_IOC_WAIT
  157. +Wait for the lock attached to the handle to be released (i.e. goes to unlock).
  158. +This is mainly used for a thread that needs to wait for a peer to release a
  159. +lock on the same shared handle. A non-zero timeout value in milliseconds is
  160. +passed in genlock_lock.timeout. Returns 0 when the lock has been released,
  161. +-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
  162. +
  163. +* GENLOCK_IOC_RELEASE
  164. +Use this to release an existing lock. This is useful if you wish to attach a
  165. +different lock to the same handle. You do not need to call this under normal
  166. +circumstances; when the handle is closed the reference to the lock is released.
  167. +No data is passed from the user for this ioctl.
  168. diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
  169. index ef38aff..5afaaa7 100644
  170. --- a/drivers/base/Kconfig
  171. +++ b/drivers/base/Kconfig
  172. @@ -169,4 +169,18 @@ config SYS_HYPERVISOR
  173.     bool
  174.     default n
  175.  
  176. +config GENLOCK
  177. +   bool "Enable a generic cross-process locking mechanism"
  178. +   depends on ANON_INODES
  179. +   help
  180. +     Enable a generic cross-process locking API to provide protection
  181. +     for shared memory objects such as graphics buffers.
  182. +
  183. +config GENLOCK_MISCDEVICE
  184. +   bool "Enable a misc-device for userspace to access the genlock engine"
  185. +   depends on GENLOCK
  186. +   help
  187. +     Create a miscdevice for the purposes of allowing userspace to create
  188. +     and interact with locks created using genlock.
  189. +
  190.  endmenu
  191. diff --git a/drivers/base/Makefile b/drivers/base/Makefile
  192. index 1e5f7a1..3149f3e 100644
  193. --- a/drivers/base/Makefile
  194. +++ b/drivers/base/Makefile
  195. @@ -8,6 +8,7 @@ obj-$(CONFIG_DEVTMPFS)  += devtmpfs.o
  196.  obj-y          += power/
  197.  obj-$(CONFIG_HAS_DMA)  += dma-mapping.o
  198.  obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
  199. +obj-$(CONFIG_GENLOCK) += genlock.o
  200.  obj-$(CONFIG_ISA)  += isa.o
  201.  obj-$(CONFIG_FW_LOADER)    += firmware_class.o
  202.  obj-$(CONFIG_NUMA) += node.o
  203. diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
  204. new file mode 100644
  205. index 0000000..ee4bec9
  206. --- /dev/null
  207. +++ b/drivers/base/genlock.c
  208. @@ -0,0 +1,621 @@
  209. +/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
  210. + *
  211. + * This program is free software; you can redistribute it and/or modify
  212. + * it under the terms of the GNU General Public License version 2 and
  213. + * only version 2 as published by the Free Software Foundation.
  214. + *
  215. + * This program is distributed in the hope that it will be useful,
  216. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  217. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  218. + * GNU General Public License for more details.
  219. + */
  220. +
  221. +#include <linux/fb.h>
  222. +#include <linux/slab.h>
  223. +#include <linux/module.h>
  224. +#include <linux/list.h>
  225. +#include <linux/file.h>
  226. +#include <linux/sched.h>
  227. +#include <linux/fs.h>
  228. +#include <linux/wait.h>
  229. +#include <linux/uaccess.h>
  230. +#include <linux/anon_inodes.h>
  231. +#include <linux/miscdevice.h>
  232. +#include <linux/genlock.h>
  233. +#include <linux/hardirq.h>
  234. +
  235. +/* Lock states - can either be unlocked, held as an exclusive write lock or a
  236. + * shared read lock
  237. + */
  238. +
  239. +#define _UNLOCKED 0
  240. +#define _RDLOCK  GENLOCK_RDLOCK
  241. +#define _WRLOCK GENLOCK_WRLOCK
  242. +
  243. +struct genlock {
  244. +   struct list_head active;  /* List of handles holding lock */
  245. +   spinlock_t lock;          /* Spinlock to protect the lock internals */
  246. +   wait_queue_head_t queue;  /* Holding pen for processes pending lock */
  247. +   struct file *file;        /* File structure for exported lock */
  248. +   int state;                /* Current state of the lock */
  249. +};
  250. +
  251. +struct genlock_handle {
  252. +   struct genlock *lock;     /* Lock currently attached to the handle */
  253. +   struct list_head entry;   /* List node for attaching to a lock */
  254. +   struct file *file;        /* File structure associated with handle */
  255. +   int active;       /* Number of times the active lock has been
  256. +                    taken */
  257. +};
  258. +
  259. +/*
  260. + * Release the genlock object. Called when all the references to
  261. + * the genlock file descriptor are released
  262. + */
  263. +
  264. +static int genlock_release(struct inode *inodep, struct file *file)
  265. +{
  266. +   kfree(file->private_data);
  267. +   return 0;
  268. +}
  269. +
  270. +static const struct file_operations genlock_fops = {
  271. +   .release = genlock_release,
  272. +};
  273. +
  274. +/**
  275. + * genlock_create_lock - Create a new lock
  276. + * @handle - genlock handle to attach the lock to
  277. + *
  278. + * Returns: a pointer to the genlock
  279. + */
  280. +
  281. +struct genlock *genlock_create_lock(struct genlock_handle *handle)
  282. +{
  283. +   struct genlock *lock;
  284. +
  285. +   if (handle->lock != NULL)
  286. +       return ERR_PTR(-EINVAL);
  287. +
  288. +   lock = kzalloc(sizeof(*lock), GFP_KERNEL);
  289. +   if (lock == NULL)
  290. +       return ERR_PTR(-ENOMEM);
  291. +
  292. +   INIT_LIST_HEAD(&lock->active);
  293. +   init_waitqueue_head(&lock->queue);
  294. +   spin_lock_init(&lock->lock);
  295. +
  296. +   lock->state = _UNLOCKED;
  297. +
  298. +   /*
  299. +    * Create an anonyonmous inode for the object that can exported to
  300. +    * other processes
  301. +    */
  302. +
  303. +   lock->file = anon_inode_getfile("genlock", &genlock_fops,
  304. +       lock, O_RDWR);
  305. +
  306. +   /* Attach the new lock to the handle */
  307. +   handle->lock = lock;
  308. +
  309. +   return lock;
  310. +}
  311. +EXPORT_SYMBOL(genlock_create_lock);
  312. +
  313. +/*
  314. + * Get a file descriptor reference to a lock suitable for sharing with
  315. + * other processes
  316. + */
  317. +
  318. +static int genlock_get_fd(struct genlock *lock)
  319. +{
  320. +   int ret;
  321. +
  322. +   if (!lock->file)
  323. +       return -EINVAL;
  324. +
  325. +   ret = get_unused_fd_flags(0);
  326. +   if (ret < 0)
  327. +       return ret;
  328. +   fd_install(ret, lock->file);
  329. +   return ret;
  330. +}
  331. +
  332. +/**
  333. + * genlock_attach_lock - Attach an existing lock to a handle
  334. + * @handle - Pointer to a genlock handle to attach the lock to
  335. + * @fd - file descriptor for the exported lock
  336. + *
  337. + * Returns: A pointer to the attached lock structure
  338. + */
  339. +
  340. +struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
  341. +{
  342. +   struct file *file;
  343. +
  344. +   if (handle->lock != NULL)
  345. +       return ERR_PTR(-EINVAL);
  346. +
  347. +   file = fget(fd);
  348. +   if (file == NULL)
  349. +       return ERR_PTR(-EBADF);
  350. +
  351. +   handle->lock = file->private_data;
  352. +
  353. +   return handle->lock;
  354. +}
  355. +EXPORT_SYMBOL(genlock_attach_lock);
  356. +
  357. +/* Helper function that returns 1 if the specified handle holds the lock */
  358. +
  359. +static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
  360. +{
  361. +   struct genlock_handle *h;
  362. +
  363. +   list_for_each_entry(h, &lock->active, entry) {
  364. +       if (h == handle)
  365. +           return 1;
  366. +   }
  367. +
  368. +   return 0;
  369. +}
  370. +
  371. +/* If the lock just became available, signal the next entity waiting for it */
  372. +
  373. +static void _genlock_signal(struct genlock *lock)
  374. +{
  375. +   if (list_empty(&lock->active)) {
  376. +       /* If the list is empty, then the lock is free */
  377. +       lock->state = _UNLOCKED;
  378. +       /* Wake up the first process sitting in the queue */
  379. +       wake_up(&lock->queue);
  380. +   }
  381. +}
  382. +
  383. +/* Attempt to release the handle's ownership of the lock */
  384. +
  385. +static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
  386. +{
  387. +   int ret = -EINVAL;
  388. +   unsigned long irqflags;
  389. +
  390. +   spin_lock_irqsave(&lock->lock, irqflags);
  391. +
  392. +   if (lock->state == _UNLOCKED)
  393. +       goto done;
  394. +
  395. +   /* Make sure this handle is an owner of the lock */
  396. +   if (!handle_has_lock(lock, handle))
  397. +       goto done;
  398. +
  399. +   /* If the handle holds no more references to the lock then
  400. +      release it (maybe) */
  401. +
  402. +   if (--handle->active == 0) {
  403. +       list_del(&handle->entry);
  404. +       _genlock_signal(lock);
  405. +   }
  406. +
  407. +   ret = 0;
  408. +
  409. +done:
  410. +   spin_unlock_irqrestore(&lock->lock, irqflags);
  411. +   return ret;
  412. +}
  413. +
  414. +/* Attempt to acquire the lock for the handle */
  415. +
  416. +static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
  417. +   int op, int flags, uint32_t timeout)
  418. +{
  419. +   unsigned long irqflags;
  420. +   int ret = 0;
  421. +   unsigned int ticks = msecs_to_jiffies(timeout);
  422. +
  423. +   spin_lock_irqsave(&lock->lock, irqflags);
  424. +
  425. +   /* Sanity check - no blocking locks in a debug context. Even if it
  426. +    * succeed to not block, the mere idea is too dangerous to continue
  427. +    */
  428. +
  429. +   if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
  430. +       BUG();
  431. +
  432. +   /* Fast path - the lock is unlocked, so go do the needful */
  433. +
  434. +   if (lock->state == _UNLOCKED)
  435. +       goto dolock;
  436. +
  437. +   if (handle_has_lock(lock, handle)) {
  438. +
  439. +       /*
  440. +        * If the handle already holds the lock and the type matches,
  441. +        * then just increment the active pointer. This allows the
  442. +        * handle to do recursive locks
  443. +        */
  444. +
  445. +       if (lock->state == op) {
  446. +           handle->active++;
  447. +           goto done;
  448. +       }
  449. +
  450. +       /*
  451. +        * If the handle holds a write lock then the owner can switch
  452. +        * to a read lock if they want. Do the transition atomically
  453. +        * then wake up any pending waiters in case they want a read
  454. +        * lock too.
  455. +        */
  456. +
  457. +       if (op == _RDLOCK && handle->active == 1) {
  458. +           lock->state = _RDLOCK;
  459. +           wake_up(&lock->queue);
  460. +           goto done;
  461. +       }
  462. +
  463. +       /*
  464. +        * Otherwise the user tried to turn a read into a write, and we
  465. +        * don't allow that.
  466. +        */
  467. +
  468. +       ret = -EINVAL;
  469. +       goto done;
  470. +   }
  471. +
  472. +   /*
  473. +    * If we request a read and the lock is held by a read, then go
  474. +    * ahead and share the lock
  475. +    */
  476. +
  477. +   if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
  478. +       goto dolock;
  479. +
  480. +   /* Treat timeout 0 just like a NOBLOCK flag and return if the
  481. +      lock cannot be aquired without blocking */
  482. +
  483. +   if (flags & GENLOCK_NOBLOCK || timeout == 0) {
  484. +       ret = -EAGAIN;
  485. +       goto done;
  486. +   }
  487. +
  488. +   /* Wait while the lock remains in an incompatible state */
  489. +
  490. +   while (lock->state != _UNLOCKED) {
  491. +       unsigned int elapsed;
  492. +
  493. +       spin_unlock_irqrestore(&lock->lock, irqflags);
  494. +
  495. +       elapsed = wait_event_interruptible_timeout(lock->queue,
  496. +           lock->state == _UNLOCKED, ticks);
  497. +
  498. +       spin_lock_irqsave(&lock->lock, irqflags);
  499. +
  500. +       if (elapsed <= 0) {
  501. +           ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
  502. +           goto done;
  503. +       }
  504. +
  505. +       ticks = elapsed;
  506. +   }
  507. +
  508. +dolock:
  509. +   /* We can now get the lock, add ourselves to the list of owners */
  510. +
  511. +   list_add_tail(&handle->entry, &lock->active);
  512. +   lock->state = op;
  513. +   handle->active = 1;
  514. +
  515. +done:
  516. +   spin_unlock_irqrestore(&lock->lock, irqflags);
  517. +   return ret;
  518. +
  519. +}
  520. +
  521. +/**
  522. + * genlock_lock - Acquire or release a lock
  523. + * @handle - pointer to the genlock handle that is requesting the lock
  524. + * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
  525. + * @flags - flags to control the operation
  526. + * @timeout - optional timeout to wait for the lock to come free
  527. + *
  528. + * Returns: 0 on success or error code on failure
  529. + */
  530. +
  531. +int genlock_lock(struct genlock_handle *handle, int op, int flags,
  532. +   uint32_t timeout)
  533. +{
  534. +   struct genlock *lock = handle->lock;
  535. +   int ret = 0;
  536. +
  537. +   if (lock == NULL)
  538. +       return -EINVAL;
  539. +
  540. +   switch (op) {
  541. +   case GENLOCK_UNLOCK:
  542. +       ret = _genlock_unlock(lock, handle);
  543. +       break;
  544. +   case GENLOCK_RDLOCK:
  545. +   case GENLOCK_WRLOCK:
  546. +       ret = _genlock_lock(lock, handle, op, flags, timeout);
  547. +       break;
  548. +   default:
  549. +       ret = -EINVAL;
  550. +       break;
  551. +   }
  552. +
  553. +   return ret;
  554. +}
  555. +EXPORT_SYMBOL(genlock_lock);
  556. +
  557. +/**
  558. + * genlock_wait - Wait for the lock to be released
  559. + * @handle - pointer to the genlock handle that is waiting for the lock
  560. + * @timeout - optional timeout to wait for the lock to get released
  561. + */
  562. +
  563. +int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
  564. +{
  565. +   struct genlock *lock = handle->lock;
  566. +   unsigned long irqflags;
  567. +   int ret = 0;
  568. +   unsigned int ticks = msecs_to_jiffies(timeout);
  569. +
  570. +   if (lock == NULL)
  571. +       return -EINVAL;
  572. +
  573. +   spin_lock_irqsave(&lock->lock, irqflags);
  574. +
  575. +   /*
  576. +    * if timeout is 0 and the lock is already unlocked, then success
  577. +    * otherwise return -EAGAIN
  578. +    */
  579. +
  580. +   if (timeout == 0) {
  581. +       ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
  582. +       goto done;
  583. +   }
  584. +
  585. +   while (lock->state != _UNLOCKED) {
  586. +       unsigned int elapsed;
  587. +
  588. +       spin_unlock_irqrestore(&lock->lock, irqflags);
  589. +
  590. +       elapsed = wait_event_interruptible_timeout(lock->queue,
  591. +           lock->state == _UNLOCKED, ticks);
  592. +
  593. +       spin_lock_irqsave(&lock->lock, irqflags);
  594. +
  595. +       if (elapsed <= 0) {
  596. +           ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
  597. +           break;
  598. +       }
  599. +
  600. +       ticks = elapsed;
  601. +   }
  602. +
  603. +done:
  604. +   spin_unlock_irqrestore(&lock->lock, irqflags);
  605. +   return ret;
  606. +}
  607. +
  608. +/**
  609. + * genlock_release_lock - Release a lock attached to a handle
  610. + * @handle - Pointer to the handle holding the lock
  611. + */
  612. +
  613. +void genlock_release_lock(struct genlock_handle *handle)
  614. +{
  615. +   unsigned long flags;
  616. +
  617. +   if (handle == NULL || handle->lock == NULL)
  618. +       return;
  619. +
  620. +   spin_lock_irqsave(&handle->lock->lock, flags);
  621. +
  622. +   /* If the handle is holding the lock, then force it closed */
  623. +
  624. +   if (handle_has_lock(handle->lock, handle)) {
  625. +       list_del(&handle->entry);
  626. +       _genlock_signal(handle->lock);
  627. +   }
  628. +   spin_unlock_irqrestore(&handle->lock->lock, flags);
  629. +
  630. +   fput(handle->lock->file);
  631. +   handle->lock = NULL;
  632. +   handle->active = 0;
  633. +}
  634. +EXPORT_SYMBOL(genlock_release_lock);
  635. +
  636. +/*
  637. + * Release function called when all references to a handle are released
  638. + */
  639. +
  640. +static int genlock_handle_release(struct inode *inodep, struct file *file)
  641. +{
  642. +   struct genlock_handle *handle = file->private_data;
  643. +
  644. +   genlock_release_lock(handle);
  645. +   kfree(handle);
  646. +
  647. +   return 0;
  648. +}
  649. +
  650. +static const struct file_operations genlock_handle_fops = {
  651. +   .release = genlock_handle_release
  652. +};
  653. +
  654. +/*
  655. + * Allocate a new genlock handle
  656. + */
  657. +
  658. +static struct genlock_handle *_genlock_get_handle(void)
  659. +{
  660. +   struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
  661. +   if (handle == NULL)
  662. +       return ERR_PTR(-ENOMEM);
  663. +
  664. +   return handle;
  665. +}
  666. +
  667. +/**
  668. + * genlock_get_handle - Create a new genlock handle
  669. + *
  670. + * Returns: A pointer to a new genlock handle
  671. + */
  672. +
  673. +struct genlock_handle *genlock_get_handle(void)
  674. +{
  675. +   struct genlock_handle *handle = _genlock_get_handle();
  676. +   if (IS_ERR(handle))
  677. +       return handle;
  678. +
  679. +   handle->file = anon_inode_getfile("genlock-handle",
  680. +       &genlock_handle_fops, handle, O_RDWR);
  681. +
  682. +   return handle;
  683. +}
  684. +EXPORT_SYMBOL(genlock_get_handle);
  685. +
  686. +/**
  687. + * genlock_put_handle - release a reference to a genlock handle
  688. + * @handle - A pointer to the handle to release
  689. + */
  690. +
  691. +void genlock_put_handle(struct genlock_handle *handle)
  692. +{
  693. +   if (handle)
  694. +       fput(handle->file);
  695. +}
  696. +EXPORT_SYMBOL(genlock_put_handle);
  697. +
  698. +/**
  699. + * genlock_get_handle_fd - Get a handle reference from a file descriptor
  700. + * @fd - The file descriptor for a genlock handle
  701. + */
  702. +
  703. +struct genlock_handle *genlock_get_handle_fd(int fd)
  704. +{
  705. +   struct file *file = fget(fd);
  706. +
  707. +   if (file == NULL)
  708. +       return ERR_PTR(-EINVAL);
  709. +
  710. +   return file->private_data;
  711. +}
  712. +EXPORT_SYMBOL(genlock_get_handle_fd);
  713. +
  714. +#ifdef CONFIG_GENLOCK_MISCDEVICE
  715. +
  716. +static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
  717. +   unsigned long arg)
  718. +{
  719. +   struct genlock_lock param;
  720. +   struct genlock_handle *handle = filep->private_data;
  721. +   struct genlock *lock;
  722. +   int ret;
  723. +
  724. +   switch (cmd) {
  725. +   case GENLOCK_IOC_NEW: {
  726. +       lock = genlock_create_lock(handle);
  727. +       if (IS_ERR(lock))
  728. +           return PTR_ERR(lock);
  729. +
  730. +       return 0;
  731. +   }
  732. +   case GENLOCK_IOC_EXPORT: {
  733. +       if (handle->lock == NULL)
  734. +           return -EINVAL;
  735. +
  736. +       ret = genlock_get_fd(handle->lock);
  737. +       if (ret < 0)
  738. +           return ret;
  739. +
  740. +       param.fd = ret;
  741. +
  742. +       if (copy_to_user((void __user *) arg, &param,
  743. +           sizeof(param)))
  744. +           return -EFAULT;
  745. +
  746. +       return 0;
  747. +       }
  748. +   case GENLOCK_IOC_ATTACH: {
  749. +       if (copy_from_user(&param, (void __user *) arg,
  750. +           sizeof(param)))
  751. +           return -EFAULT;
  752. +
  753. +       lock = genlock_attach_lock(handle, param.fd);
  754. +       if (IS_ERR(lock))
  755. +           return PTR_ERR(lock);
  756. +
  757. +       return 0;
  758. +   }
  759. +   case GENLOCK_IOC_LOCK: {
  760. +       if (copy_from_user(&param, (void __user *) arg,
  761. +       sizeof(param)))
  762. +           return -EFAULT;
  763. +
  764. +       return genlock_lock(handle, param.op, param.flags,
  765. +           param.timeout);
  766. +   }
  767. +   case GENLOCK_IOC_WAIT: {
  768. +       if (copy_from_user(&param, (void __user *) arg,
  769. +       sizeof(param)))
  770. +           return -EFAULT;
  771. +
  772. +       return genlock_wait(handle, param.timeout);
  773. +   }
  774. +   case GENLOCK_IOC_RELEASE: {
  775. +       genlock_release_lock(handle);
  776. +       return 0;
  777. +   }
  778. +   default:
  779. +       return -EINVAL;
  780. +   }
  781. +}
  782. +
  783. +static int genlock_dev_release(struct inode *inodep, struct file *file)
  784. +{
  785. +   struct genlock_handle *handle = file->private_data;
  786. +
  787. +   genlock_put_handle(handle);
  788. +
  789. +   return 0;
  790. +}
  791. +
  792. +static int genlock_dev_open(struct inode *inodep, struct file *file)
  793. +{
  794. +   struct genlock_handle *handle = _genlock_get_handle();
  795. +   if (IS_ERR(handle))
  796. +       return PTR_ERR(handle);
  797. +
  798. +   handle->file = file;
  799. +   file->private_data = handle;
  800. +   return 0;
  801. +}
  802. +
  803. +static const struct file_operations genlock_dev_fops = {
  804. +   .open = genlock_dev_open,
  805. +   .release = genlock_dev_release,
  806. +   .unlocked_ioctl = genlock_dev_ioctl,
  807. +};
  808. +
  809. +static struct miscdevice genlock_dev;
  810. +
  811. +static int genlock_dev_init(void)
  812. +{
  813. +   genlock_dev.minor = MISC_DYNAMIC_MINOR;
  814. +   genlock_dev.name = "genlock";
  815. +   genlock_dev.fops = &genlock_dev_fops;
  816. +   genlock_dev.parent = NULL;
  817. +
  818. +   return misc_register(&genlock_dev);
  819. +}
  820. +
  821. +static void genlock_dev_close(void)
  822. +{
  823. +   misc_deregister(&genlock_dev);
  824. +}
  825. +
  826. +module_init(genlock_dev_init);
  827. +module_exit(genlock_dev_close);
  828. +
  829. +#endif
  830. diff --git a/include/linux/genlock.h b/include/linux/genlock.h
  831. new file mode 100644
  832. index 0000000..2e9f9d6
  833. --- /dev/null
  834. +++ b/include/linux/genlock.h
  835. @@ -0,0 +1,45 @@
  836. +#ifndef _GENLOCK_H_
  837. +#define _GENLOCK_H_
  838. +
  839. +#ifdef __KERNEL__
  840. +
  841. +struct genlock;
  842. +struct genlock_handle;
  843. +
  844. +struct genlock_handle *genlock_get_handle(void);
  845. +struct genlock_handle *genlock_get_handle_fd(int fd);
  846. +void genlock_put_handle(struct genlock_handle *handle);
  847. +struct genlock *genlock_create_lock(struct genlock_handle *);
  848. +struct genlock *genlock_attach_lock(struct genlock_handle *, int fd);
  849. +int genlock_wait(struct genlock_handle *handle, u32 timeout);
  850. +void genlock_release_lock(struct genlock_handle *);
  851. +int genlock_lock(struct genlock_handle *handle, int op, int flags,
  852. +   u32 timeout);
  853. +#endif
  854. +
  855. +#define GENLOCK_UNLOCK 0
  856. +#define GENLOCK_WRLOCK 1
  857. +#define GENLOCK_RDLOCK 2
  858. +
  859. +#define GENLOCK_NOBLOCK (1 << 0)
  860. +
  861. +struct genlock_lock {
  862. +   int fd;
  863. +   int op;
  864. +   int flags;
  865. +   int timeout;
  866. +};
  867. +
  868. +#define GENLOCK_IOC_MAGIC     'G'
  869. +
  870. +#define GENLOCK_IOC_NEW _IO(GENLOCK_IOC_MAGIC, 0)
  871. +#define GENLOCK_IOC_EXPORT _IOR(GENLOCK_IOC_MAGIC, 1, \
  872. +   struct genlock_lock)
  873. +#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
  874. +   struct genlock_lock)
  875. +#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
  876. +   struct genlock_lock)
  877. +#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
  878. +#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
  879. +   struct genlock_lock)
  880. +#endif
Add Comment
Please, Sign In to add comment