Commit 1791f881435fab951939ad700e947b66c062e083
Committed by
Thomas Gleixner
1 parent
a1b49cb7e2
Exists in
master
and in
20 other branches
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: Richard Cochran <richard.cochran@omicron.at> Cc: John Stultz <john.stultz@linaro.org> Link: http://lkml.kernel.org/r/%3C20110330132421.GA31771%40riccoc20.at.omicron.at%3E Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Showing 2 changed files with 12 additions and 17 deletions Side-by-side Diff
include/linux/posix-clock.h
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 | #include <linux/fs.h> |
25 | 25 | #include <linux/poll.h> |
26 | 26 | #include <linux/posix-timers.h> |
27 | +#include <linux/rwsem.h> | |
27 | 28 | |
28 | 29 | struct posix_clock; |
29 | 30 | |
... | ... | @@ -104,7 +105,7 @@ |
104 | 105 | * @ops: Functional interface to the clock |
105 | 106 | * @cdev: Character device instance for this clock |
106 | 107 | * @kref: Reference count. |
107 | - * @mutex: Protects the 'zombie' field from concurrent access. | |
108 | + * @rwsem: Protects the 'zombie' field from concurrent access. | |
108 | 109 | * @zombie: If 'zombie' is true, then the hardware has disappeared. |
109 | 110 | * @release: A function to free the structure when the reference count reaches |
110 | 111 | * zero. May be NULL if structure is statically allocated. |
... | ... | @@ -117,7 +118,7 @@ |
117 | 118 | struct posix_clock_operations ops; |
118 | 119 | struct cdev cdev; |
119 | 120 | struct kref kref; |
120 | - struct mutex mutex; | |
121 | + struct rw_semaphore rwsem; | |
121 | 122 | bool zombie; |
122 | 123 | void (*release)(struct posix_clock *clk); |
123 | 124 | }; |
kernel/time/posix-clock.c
... | ... | @@ -19,7 +19,6 @@ |
19 | 19 | */ |
20 | 20 | #include <linux/device.h> |
21 | 21 | #include <linux/file.h> |
22 | -#include <linux/mutex.h> | |
23 | 22 | #include <linux/posix-clock.h> |
24 | 23 | #include <linux/slab.h> |
25 | 24 | #include <linux/syscalls.h> |
26 | 25 | |
27 | 26 | |
... | ... | @@ -34,19 +33,19 @@ |
34 | 33 | { |
35 | 34 | struct posix_clock *clk = fp->private_data; |
36 | 35 | |
37 | - mutex_lock(&clk->mutex); | |
36 | + down_read(&clk->rwsem); | |
38 | 37 | |
39 | 38 | if (!clk->zombie) |
40 | 39 | return clk; |
41 | 40 | |
42 | - mutex_unlock(&clk->mutex); | |
41 | + up_read(&clk->rwsem); | |
43 | 42 | |
44 | 43 | return NULL; |
45 | 44 | } |
46 | 45 | |
47 | 46 | static void put_posix_clock(struct posix_clock *clk) |
48 | 47 | { |
49 | - mutex_unlock(&clk->mutex); | |
48 | + up_read(&clk->rwsem); | |
50 | 49 | } |
51 | 50 | |
52 | 51 | static ssize_t posix_clock_read(struct file *fp, char __user *buf, |
... | ... | @@ -156,7 +155,7 @@ |
156 | 155 | struct posix_clock *clk = |
157 | 156 | container_of(inode->i_cdev, struct posix_clock, cdev); |
158 | 157 | |
159 | - mutex_lock(&clk->mutex); | |
158 | + down_read(&clk->rwsem); | |
160 | 159 | |
161 | 160 | if (clk->zombie) { |
162 | 161 | err = -ENODEV; |
... | ... | @@ -172,7 +171,7 @@ |
172 | 171 | fp->private_data = clk; |
173 | 172 | } |
174 | 173 | out: |
175 | - mutex_unlock(&clk->mutex); | |
174 | + up_read(&clk->rwsem); | |
176 | 175 | return err; |
177 | 176 | } |
178 | 177 | |
179 | 178 | |
180 | 179 | |
181 | 180 | |
... | ... | @@ -211,25 +210,20 @@ |
211 | 210 | int err; |
212 | 211 | |
213 | 212 | kref_init(&clk->kref); |
214 | - mutex_init(&clk->mutex); | |
213 | + init_rwsem(&clk->rwsem); | |
215 | 214 | |
216 | 215 | cdev_init(&clk->cdev, &posix_clock_file_operations); |
217 | 216 | clk->cdev.owner = clk->ops.owner; |
218 | 217 | err = cdev_add(&clk->cdev, devid, 1); |
219 | - if (err) | |
220 | - goto no_cdev; | |
221 | 218 | |
222 | 219 | return err; |
223 | -no_cdev: | |
224 | - mutex_destroy(&clk->mutex); | |
225 | - return err; | |
226 | 220 | } |
227 | 221 | EXPORT_SYMBOL_GPL(posix_clock_register); |
228 | 222 | |
229 | 223 | static void delete_clock(struct kref *kref) |
230 | 224 | { |
231 | 225 | struct posix_clock *clk = container_of(kref, struct posix_clock, kref); |
232 | - mutex_destroy(&clk->mutex); | |
226 | + | |
233 | 227 | if (clk->release) |
234 | 228 | clk->release(clk); |
235 | 229 | } |
236 | 230 | |
... | ... | @@ -238,9 +232,9 @@ |
238 | 232 | { |
239 | 233 | cdev_del(&clk->cdev); |
240 | 234 | |
241 | - mutex_lock(&clk->mutex); | |
235 | + down_write(&clk->rwsem); | |
242 | 236 | clk->zombie = true; |
243 | - mutex_unlock(&clk->mutex); | |
237 | + up_write(&clk->rwsem); | |
244 | 238 | |
245 | 239 | kref_put(&clk->kref, delete_clock); |
246 | 240 | } |