diff options
| -rw-r--r-- | drivers/input/evdev.c | 22 | ||||
| -rw-r--r-- | drivers/input/input.c | 36 | ||||
| -rw-r--r-- | drivers/input/joydev.c | 11 | ||||
| -rw-r--r-- | drivers/input/mousedev.c | 11 |
4 files changed, 32 insertions, 48 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 27026f7d3c03..1d62c8b88e12 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -63,10 +63,7 @@ static void evdev_pass_event(struct evdev_client *client, | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * Pass incoming event to all connected clients. Note that we are | 66 | * Pass incoming event to all connected clients. |
| 67 | * caleld under a spinlock with interrupts off so we don't need | ||
| 68 | * to use rcu_read_lock() here. Writers will be using syncronize_sched() | ||
| 69 | * instead of synchrnoize_rcu(). | ||
| 70 | */ | 67 | */ |
| 71 | static void evdev_event(struct input_handle *handle, | 68 | static void evdev_event(struct input_handle *handle, |
| 72 | unsigned int type, unsigned int code, int value) | 69 | unsigned int type, unsigned int code, int value) |
| @@ -80,6 +77,8 @@ static void evdev_event(struct input_handle *handle, | |||
| 80 | event.code = code; | 77 | event.code = code; |
| 81 | event.value = value; | 78 | event.value = value; |
| 82 | 79 | ||
| 80 | rcu_read_lock(); | ||
| 81 | |||
| 83 | client = rcu_dereference(evdev->grab); | 82 | client = rcu_dereference(evdev->grab); |
| 84 | if (client) | 83 | if (client) |
| 85 | evdev_pass_event(client, &event); | 84 | evdev_pass_event(client, &event); |
| @@ -87,6 +86,8 @@ static void evdev_event(struct input_handle *handle, | |||
| 87 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 86 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
| 88 | evdev_pass_event(client, &event); | 87 | evdev_pass_event(client, &event); |
| 89 | 88 | ||
| 89 | rcu_read_unlock(); | ||
| 90 | |||
| 90 | wake_up_interruptible(&evdev->wait); | 91 | wake_up_interruptible(&evdev->wait); |
| 91 | } | 92 | } |
| 92 | 93 | ||
| @@ -142,12 +143,7 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client) | |||
| 142 | return error; | 143 | return error; |
| 143 | 144 | ||
| 144 | rcu_assign_pointer(evdev->grab, client); | 145 | rcu_assign_pointer(evdev->grab, client); |
| 145 | /* | 146 | synchronize_rcu(); |
| 146 | * We don't use synchronize_rcu() here because read-side | ||
| 147 | * critical section is protected by a spinlock instead | ||
| 148 | * of rcu_read_lock(). | ||
| 149 | */ | ||
| 150 | synchronize_sched(); | ||
| 151 | 147 | ||
| 152 | return 0; | 148 | return 0; |
| 153 | } | 149 | } |
| @@ -158,7 +154,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) | |||
| 158 | return -EINVAL; | 154 | return -EINVAL; |
| 159 | 155 | ||
| 160 | rcu_assign_pointer(evdev->grab, NULL); | 156 | rcu_assign_pointer(evdev->grab, NULL); |
| 161 | synchronize_sched(); | 157 | synchronize_rcu(); |
| 162 | input_release_device(&evdev->handle); | 158 | input_release_device(&evdev->handle); |
| 163 | 159 | ||
| 164 | return 0; | 160 | return 0; |
| @@ -170,7 +166,7 @@ static void evdev_attach_client(struct evdev *evdev, | |||
| 170 | spin_lock(&evdev->client_lock); | 166 | spin_lock(&evdev->client_lock); |
| 171 | list_add_tail_rcu(&client->node, &evdev->client_list); | 167 | list_add_tail_rcu(&client->node, &evdev->client_list); |
| 172 | spin_unlock(&evdev->client_lock); | 168 | spin_unlock(&evdev->client_lock); |
| 173 | synchronize_sched(); | 169 | synchronize_rcu(); |
| 174 | } | 170 | } |
| 175 | 171 | ||
| 176 | static void evdev_detach_client(struct evdev *evdev, | 172 | static void evdev_detach_client(struct evdev *evdev, |
| @@ -179,7 +175,7 @@ static void evdev_detach_client(struct evdev *evdev, | |||
| 179 | spin_lock(&evdev->client_lock); | 175 | spin_lock(&evdev->client_lock); |
| 180 | list_del_rcu(&client->node); | 176 | list_del_rcu(&client->node); |
| 181 | spin_unlock(&evdev->client_lock); | 177 | spin_unlock(&evdev->client_lock); |
| 182 | synchronize_sched(); | 178 | synchronize_rcu(); |
| 183 | } | 179 | } |
| 184 | 180 | ||
| 185 | static int evdev_open_device(struct evdev *evdev) | 181 | static int evdev_open_device(struct evdev *evdev) |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 3070c7aa1237..2f2b020cd629 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -65,16 +65,16 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) | |||
| 65 | 65 | ||
| 66 | /* | 66 | /* |
| 67 | * Pass event through all open handles. This function is called with | 67 | * Pass event through all open handles. This function is called with |
| 68 | * dev->event_lock held and interrupts disabled. Because of that we | 68 | * dev->event_lock held and interrupts disabled. |
| 69 | * do not need to use rcu_read_lock() here although we are using RCU | ||
| 70 | * to access handle list. Note that because of that write-side uses | ||
| 71 | * synchronize_sched() instead of synchronize_ru(). | ||
| 72 | */ | 69 | */ |
| 73 | static void input_pass_event(struct input_dev *dev, | 70 | static void input_pass_event(struct input_dev *dev, |
| 74 | unsigned int type, unsigned int code, int value) | 71 | unsigned int type, unsigned int code, int value) |
| 75 | { | 72 | { |
| 76 | struct input_handle *handle = rcu_dereference(dev->grab); | 73 | struct input_handle *handle; |
| 74 | |||
| 75 | rcu_read_lock(); | ||
| 77 | 76 | ||
| 77 | handle = rcu_dereference(dev->grab); | ||
| 78 | if (handle) | 78 | if (handle) |
| 79 | handle->handler->event(handle, type, code, value); | 79 | handle->handler->event(handle, type, code, value); |
| 80 | else | 80 | else |
| @@ -82,6 +82,7 @@ static void input_pass_event(struct input_dev *dev, | |||
| 82 | if (handle->open) | 82 | if (handle->open) |
| 83 | handle->handler->event(handle, | 83 | handle->handler->event(handle, |
| 84 | type, code, value); | 84 | type, code, value); |
| 85 | rcu_read_unlock(); | ||
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | /* | 88 | /* |
| @@ -293,9 +294,11 @@ void input_inject_event(struct input_handle *handle, | |||
| 293 | if (is_event_supported(type, dev->evbit, EV_MAX)) { | 294 | if (is_event_supported(type, dev->evbit, EV_MAX)) { |
| 294 | spin_lock_irqsave(&dev->event_lock, flags); | 295 | spin_lock_irqsave(&dev->event_lock, flags); |
| 295 | 296 | ||
| 297 | rcu_read_lock(); | ||
| 296 | grab = rcu_dereference(dev->grab); | 298 | grab = rcu_dereference(dev->grab); |
| 297 | if (!grab || grab == handle) | 299 | if (!grab || grab == handle) |
| 298 | input_handle_event(dev, type, code, value); | 300 | input_handle_event(dev, type, code, value); |
| 301 | rcu_read_unlock(); | ||
| 299 | 302 | ||
| 300 | spin_unlock_irqrestore(&dev->event_lock, flags); | 303 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 301 | } | 304 | } |
| @@ -325,11 +328,7 @@ int input_grab_device(struct input_handle *handle) | |||
| 325 | } | 328 | } |
| 326 | 329 | ||
| 327 | rcu_assign_pointer(dev->grab, handle); | 330 | rcu_assign_pointer(dev->grab, handle); |
| 328 | /* | 331 | synchronize_rcu(); |
| 329 | * Not using synchronize_rcu() because read-side is protected | ||
| 330 | * by a spinlock with interrupts off instead of rcu_read_lock(). | ||
| 331 | */ | ||
| 332 | synchronize_sched(); | ||
| 333 | 332 | ||
| 334 | out: | 333 | out: |
| 335 | mutex_unlock(&dev->mutex); | 334 | mutex_unlock(&dev->mutex); |
| @@ -344,7 +343,7 @@ static void __input_release_device(struct input_handle *handle) | |||
| 344 | if (dev->grab == handle) { | 343 | if (dev->grab == handle) { |
| 345 | rcu_assign_pointer(dev->grab, NULL); | 344 | rcu_assign_pointer(dev->grab, NULL); |
| 346 | /* Make sure input_pass_event() notices that grab is gone */ | 345 | /* Make sure input_pass_event() notices that grab is gone */ |
| 347 | synchronize_sched(); | 346 | synchronize_rcu(); |
| 348 | 347 | ||
| 349 | list_for_each_entry(handle, &dev->h_list, d_node) | 348 | list_for_each_entry(handle, &dev->h_list, d_node) |
| 350 | if (handle->open && handle->handler->start) | 349 | if (handle->open && handle->handler->start) |
| @@ -404,7 +403,7 @@ int input_open_device(struct input_handle *handle) | |||
| 404 | * Make sure we are not delivering any more events | 403 | * Make sure we are not delivering any more events |
| 405 | * through this handle | 404 | * through this handle |
| 406 | */ | 405 | */ |
| 407 | synchronize_sched(); | 406 | synchronize_rcu(); |
| 408 | } | 407 | } |
| 409 | } | 408 | } |
| 410 | 409 | ||
| @@ -451,11 +450,11 @@ void input_close_device(struct input_handle *handle) | |||
| 451 | 450 | ||
| 452 | if (!--handle->open) { | 451 | if (!--handle->open) { |
| 453 | /* | 452 | /* |
| 454 | * synchronize_sched() makes sure that input_pass_event() | 453 | * synchronize_rcu() makes sure that input_pass_event() |
| 455 | * completed and that no more input events are delivered | 454 | * completed and that no more input events are delivered |
| 456 | * through this handle | 455 | * through this handle |
| 457 | */ | 456 | */ |
| 458 | synchronize_sched(); | 457 | synchronize_rcu(); |
| 459 | } | 458 | } |
| 460 | 459 | ||
| 461 | mutex_unlock(&dev->mutex); | 460 | mutex_unlock(&dev->mutex); |
| @@ -1477,12 +1476,7 @@ int input_register_handle(struct input_handle *handle) | |||
| 1477 | return error; | 1476 | return error; |
| 1478 | list_add_tail_rcu(&handle->d_node, &dev->h_list); | 1477 | list_add_tail_rcu(&handle->d_node, &dev->h_list); |
| 1479 | mutex_unlock(&dev->mutex); | 1478 | mutex_unlock(&dev->mutex); |
| 1480 | /* | 1479 | synchronize_rcu(); |
| 1481 | * We don't use synchronize_rcu() here because we rely | ||
| 1482 | * on dev->event_lock to protect read-side critical | ||
| 1483 | * section in input_pass_event(). | ||
| 1484 | */ | ||
| 1485 | synchronize_sched(); | ||
| 1486 | 1480 | ||
| 1487 | /* | 1481 | /* |
| 1488 | * Since we are supposed to be called from ->connect() | 1482 | * Since we are supposed to be called from ->connect() |
| @@ -1521,7 +1515,7 @@ void input_unregister_handle(struct input_handle *handle) | |||
| 1521 | mutex_lock(&dev->mutex); | 1515 | mutex_lock(&dev->mutex); |
| 1522 | list_del_rcu(&handle->d_node); | 1516 | list_del_rcu(&handle->d_node); |
| 1523 | mutex_unlock(&dev->mutex); | 1517 | mutex_unlock(&dev->mutex); |
| 1524 | synchronize_sched(); | 1518 | synchronize_rcu(); |
| 1525 | } | 1519 | } |
| 1526 | EXPORT_SYMBOL(input_unregister_handle); | 1520 | EXPORT_SYMBOL(input_unregister_handle); |
| 1527 | 1521 | ||
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f306c97f556d..2b201f9aa024 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -149,8 +149,10 @@ static void joydev_event(struct input_handle *handle, | |||
| 149 | 149 | ||
| 150 | event.time = jiffies_to_msecs(jiffies); | 150 | event.time = jiffies_to_msecs(jiffies); |
| 151 | 151 | ||
| 152 | rcu_read_lock(); | ||
| 152 | list_for_each_entry_rcu(client, &joydev->client_list, node) | 153 | list_for_each_entry_rcu(client, &joydev->client_list, node) |
| 153 | joydev_pass_event(client, &event); | 154 | joydev_pass_event(client, &event); |
| 155 | rcu_read_unlock(); | ||
| 154 | 156 | ||
| 155 | wake_up_interruptible(&joydev->wait); | 157 | wake_up_interruptible(&joydev->wait); |
| 156 | } | 158 | } |
| @@ -178,12 +180,7 @@ static void joydev_attach_client(struct joydev *joydev, | |||
| 178 | spin_lock(&joydev->client_lock); | 180 | spin_lock(&joydev->client_lock); |
| 179 | list_add_tail_rcu(&client->node, &joydev->client_list); | 181 | list_add_tail_rcu(&client->node, &joydev->client_list); |
| 180 | spin_unlock(&joydev->client_lock); | 182 | spin_unlock(&joydev->client_lock); |
| 181 | /* | 183 | synchronize_rcu(); |
| 182 | * We don't use synchronize_rcu() here because read-side | ||
| 183 | * critical section is protected by a spinlock (dev->event_lock) | ||
| 184 | * instead of rcu_read_lock(). | ||
| 185 | */ | ||
| 186 | synchronize_sched(); | ||
| 187 | } | 184 | } |
| 188 | 185 | ||
| 189 | static void joydev_detach_client(struct joydev *joydev, | 186 | static void joydev_detach_client(struct joydev *joydev, |
| @@ -192,7 +189,7 @@ static void joydev_detach_client(struct joydev *joydev, | |||
| 192 | spin_lock(&joydev->client_lock); | 189 | spin_lock(&joydev->client_lock); |
| 193 | list_del_rcu(&client->node); | 190 | list_del_rcu(&client->node); |
| 194 | spin_unlock(&joydev->client_lock); | 191 | spin_unlock(&joydev->client_lock); |
| 195 | synchronize_sched(); | 192 | synchronize_rcu(); |
| 196 | } | 193 | } |
| 197 | 194 | ||
| 198 | static int joydev_open_device(struct joydev *joydev) | 195 | static int joydev_open_device(struct joydev *joydev) |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index cc36edbb912f..79146d6ed2ab 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -265,6 +265,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, | |||
| 265 | unsigned int new_head; | 265 | unsigned int new_head; |
| 266 | int wake_readers = 0; | 266 | int wake_readers = 0; |
| 267 | 267 | ||
| 268 | rcu_read_lock(); | ||
| 268 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { | 269 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { |
| 269 | 270 | ||
| 270 | /* Just acquire the lock, interrupts already disabled */ | 271 | /* Just acquire the lock, interrupts already disabled */ |
| @@ -309,6 +310,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, | |||
| 309 | wake_readers = 1; | 310 | wake_readers = 1; |
| 310 | } | 311 | } |
| 311 | } | 312 | } |
| 313 | rcu_read_unlock(); | ||
| 312 | 314 | ||
| 313 | if (wake_readers) | 315 | if (wake_readers) |
| 314 | wake_up_interruptible(&mousedev->wait); | 316 | wake_up_interruptible(&mousedev->wait); |
| @@ -499,12 +501,7 @@ static void mousedev_attach_client(struct mousedev *mousedev, | |||
| 499 | spin_lock(&mousedev->client_lock); | 501 | spin_lock(&mousedev->client_lock); |
| 500 | list_add_tail_rcu(&client->node, &mousedev->client_list); | 502 | list_add_tail_rcu(&client->node, &mousedev->client_list); |
| 501 | spin_unlock(&mousedev->client_lock); | 503 | spin_unlock(&mousedev->client_lock); |
| 502 | /* | 504 | synchronize_rcu(); |
| 503 | * We don't use synchronize_rcu() here because read-side | ||
| 504 | * critical section is protected by a spinlock (dev->event_lock) | ||
| 505 | * instead of rcu_read_lock(). | ||
| 506 | */ | ||
| 507 | synchronize_sched(); | ||
| 508 | } | 505 | } |
| 509 | 506 | ||
| 510 | static void mousedev_detach_client(struct mousedev *mousedev, | 507 | static void mousedev_detach_client(struct mousedev *mousedev, |
| @@ -513,7 +510,7 @@ static void mousedev_detach_client(struct mousedev *mousedev, | |||
| 513 | spin_lock(&mousedev->client_lock); | 510 | spin_lock(&mousedev->client_lock); |
| 514 | list_del_rcu(&client->node); | 511 | list_del_rcu(&client->node); |
| 515 | spin_unlock(&mousedev->client_lock); | 512 | spin_unlock(&mousedev->client_lock); |
| 516 | synchronize_sched(); | 513 | synchronize_rcu(); |
| 517 | } | 514 | } |
| 518 | 515 | ||
| 519 | static int mousedev_release(struct inode *inode, struct file *file) | 516 | static int mousedev_release(struct inode *inode, struct file *file) |
