Commit 1791f881 authored by Richard Cochran's avatar Richard Cochran Committed by Thomas Gleixner

posix clocks: Replace mutex with reader/writer semaphore

A dynamic posix clock is protected from asynchronous removal by a mutex.
However, using a mutex has the unwanted effect that a long running clock
operation in one process will unnecessarily block other processes.

For example, one process might call read() to get an external time stamp
coming in at one pulse per second. A second process calling clock_gettime
would have to wait for almost a whole second.

This patch fixes the issue by using a reader/writer semaphore instead of
a mutex.
Signed-off-by: default avatarRichard Cochran <richard.cochran@omicron.at>
Cc: John Stultz <john.stultz@linaro.org>
Link: http://lkml.kernel.org/r/%3C20110330132421.GA31771%40riccoc20.at.omicron.at%3ESigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent a1b49cb7
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/rwsem.h>
struct posix_clock; struct posix_clock;
...@@ -104,7 +105,7 @@ struct posix_clock_operations { ...@@ -104,7 +105,7 @@ struct posix_clock_operations {
* @ops: Functional interface to the clock * @ops: Functional interface to the clock
* @cdev: Character device instance for this clock * @cdev: Character device instance for this clock
* @kref: Reference count. * @kref: Reference count.
* @mutex: Protects the 'zombie' field from concurrent access. * @rwsem: Protects the 'zombie' field from concurrent access.
* @zombie: If 'zombie' is true, then the hardware has disappeared. * @zombie: If 'zombie' is true, then the hardware has disappeared.
* @release: A function to free the structure when the reference count reaches * @release: A function to free the structure when the reference count reaches
* zero. May be NULL if structure is statically allocated. * zero. May be NULL if structure is statically allocated.
...@@ -117,7 +118,7 @@ struct posix_clock { ...@@ -117,7 +118,7 @@ struct posix_clock {
struct posix_clock_operations ops; struct posix_clock_operations ops;
struct cdev cdev; struct cdev cdev;
struct kref kref; struct kref kref;
struct mutex mutex; struct rw_semaphore rwsem;
bool zombie; bool zombie;
void (*release)(struct posix_clock *clk); void (*release)(struct posix_clock *clk);
}; };
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/mutex.h>
#include <linux/posix-clock.h> #include <linux/posix-clock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
...@@ -34,19 +33,19 @@ static struct posix_clock *get_posix_clock(struct file *fp) ...@@ -34,19 +33,19 @@ static struct posix_clock *get_posix_clock(struct file *fp)
{ {
struct posix_clock *clk = fp->private_data; struct posix_clock *clk = fp->private_data;
mutex_lock(&clk->mutex); down_read(&clk->rwsem);
if (!clk->zombie) if (!clk->zombie)
return clk; return clk;
mutex_unlock(&clk->mutex); up_read(&clk->rwsem);
return NULL; return NULL;
} }
static void put_posix_clock(struct posix_clock *clk) static void put_posix_clock(struct posix_clock *clk)
{ {
mutex_unlock(&clk->mutex); up_read(&clk->rwsem);
} }
static ssize_t posix_clock_read(struct file *fp, char __user *buf, static ssize_t posix_clock_read(struct file *fp, char __user *buf,
...@@ -156,7 +155,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp) ...@@ -156,7 +155,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
struct posix_clock *clk = struct posix_clock *clk =
container_of(inode->i_cdev, struct posix_clock, cdev); container_of(inode->i_cdev, struct posix_clock, cdev);
mutex_lock(&clk->mutex); down_read(&clk->rwsem);
if (clk->zombie) { if (clk->zombie) {
err = -ENODEV; err = -ENODEV;
...@@ -172,7 +171,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp) ...@@ -172,7 +171,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
fp->private_data = clk; fp->private_data = clk;
} }
out: out:
mutex_unlock(&clk->mutex); up_read(&clk->rwsem);
return err; return err;
} }
...@@ -211,25 +210,20 @@ int posix_clock_register(struct posix_clock *clk, dev_t devid) ...@@ -211,25 +210,20 @@ int posix_clock_register(struct posix_clock *clk, dev_t devid)
int err; int err;
kref_init(&clk->kref); kref_init(&clk->kref);
mutex_init(&clk->mutex); init_rwsem(&clk->rwsem);
cdev_init(&clk->cdev, &posix_clock_file_operations); cdev_init(&clk->cdev, &posix_clock_file_operations);
clk->cdev.owner = clk->ops.owner; clk->cdev.owner = clk->ops.owner;
err = cdev_add(&clk->cdev, devid, 1); err = cdev_add(&clk->cdev, devid, 1);
if (err)
goto no_cdev;
return err; return err;
no_cdev:
mutex_destroy(&clk->mutex);
return err;
} }
EXPORT_SYMBOL_GPL(posix_clock_register); EXPORT_SYMBOL_GPL(posix_clock_register);
static void delete_clock(struct kref *kref) static void delete_clock(struct kref *kref)
{ {
struct posix_clock *clk = container_of(kref, struct posix_clock, kref); struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
mutex_destroy(&clk->mutex);
if (clk->release) if (clk->release)
clk->release(clk); clk->release(clk);
} }
...@@ -238,9 +232,9 @@ void posix_clock_unregister(struct posix_clock *clk) ...@@ -238,9 +232,9 @@ void posix_clock_unregister(struct posix_clock *clk)
{ {
cdev_del(&clk->cdev); cdev_del(&clk->cdev);
mutex_lock(&clk->mutex); down_write(&clk->rwsem);
clk->zombie = true; clk->zombie = true;
mutex_unlock(&clk->mutex); up_write(&clk->rwsem);
kref_put(&clk->kref, delete_clock); kref_put(&clk->kref, delete_clock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment