Commit 82ba56c2 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: use full RCU API

RT guys alerted me to the fact that in their tree spinlocks
are preemptible and it is better to use full RCU API
(rcu_read_lock()/rcu_read_unlock()) to be safe.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 70093178
...@@ -63,10 +63,7 @@ static void evdev_pass_event(struct evdev_client *client, ...@@ -63,10 +63,7 @@ static void evdev_pass_event(struct evdev_client *client,
} }
/* /*
* Pass incoming event to all connected clients. Note that we are * Pass incoming event to all connected clients.
* caleld under a spinlock with interrupts off so we don't need
* to use rcu_read_lock() here. Writers will be using syncronize_sched()
* instead of synchrnoize_rcu().
*/ */
static void evdev_event(struct input_handle *handle, static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
...@@ -80,6 +77,8 @@ static void evdev_event(struct input_handle *handle, ...@@ -80,6 +77,8 @@ static void evdev_event(struct input_handle *handle,
event.code = code; event.code = code;
event.value = value; event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab); client = rcu_dereference(evdev->grab);
if (client) if (client)
evdev_pass_event(client, &event); evdev_pass_event(client, &event);
...@@ -87,6 +86,8 @@ static void evdev_event(struct input_handle *handle, ...@@ -87,6 +86,8 @@ static void evdev_event(struct input_handle *handle,
list_for_each_entry_rcu(client, &evdev->client_list, node) list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event); evdev_pass_event(client, &event);
rcu_read_unlock();
wake_up_interruptible(&evdev->wait); wake_up_interruptible(&evdev->wait);
} }
...@@ -142,12 +143,7 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client) ...@@ -142,12 +143,7 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
return error; return error;
rcu_assign_pointer(evdev->grab, client); rcu_assign_pointer(evdev->grab, client);
/* synchronize_rcu();
* We don't use synchronize_rcu() here because read-side
* critical section is protected by a spinlock instead
* of rcu_read_lock().
*/
synchronize_sched();
return 0; return 0;
} }
...@@ -158,7 +154,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) ...@@ -158,7 +154,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
return -EINVAL; return -EINVAL;
rcu_assign_pointer(evdev->grab, NULL); rcu_assign_pointer(evdev->grab, NULL);
synchronize_sched(); synchronize_rcu();
input_release_device(&evdev->handle); input_release_device(&evdev->handle);
return 0; return 0;
...@@ -170,7 +166,7 @@ static void evdev_attach_client(struct evdev *evdev, ...@@ -170,7 +166,7 @@ static void evdev_attach_client(struct evdev *evdev,
spin_lock(&evdev->client_lock); spin_lock(&evdev->client_lock);
list_add_tail_rcu(&client->node, &evdev->client_list); list_add_tail_rcu(&client->node, &evdev->client_list);
spin_unlock(&evdev->client_lock); spin_unlock(&evdev->client_lock);
synchronize_sched(); synchronize_rcu();
} }
static void evdev_detach_client(struct evdev *evdev, static void evdev_detach_client(struct evdev *evdev,
...@@ -179,7 +175,7 @@ static void evdev_detach_client(struct evdev *evdev, ...@@ -179,7 +175,7 @@ static void evdev_detach_client(struct evdev *evdev,
spin_lock(&evdev->client_lock); spin_lock(&evdev->client_lock);
list_del_rcu(&client->node); list_del_rcu(&client->node);
spin_unlock(&evdev->client_lock); spin_unlock(&evdev->client_lock);
synchronize_sched(); synchronize_rcu();
} }
static int evdev_open_device(struct evdev *evdev) static int evdev_open_device(struct evdev *evdev)
......
...@@ -65,16 +65,16 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) ...@@ -65,16 +65,16 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
/* /*
* Pass event through all open handles. This function is called with * Pass event through all open handles. This function is called with
* dev->event_lock held and interrupts disabled. Because of that we * dev->event_lock held and interrupts disabled.
* do not need to use rcu_read_lock() here although we are using RCU
* to access handle list. Note that because of that write-side uses
* synchronize_sched() instead of synchronize_ru().
*/ */
static void input_pass_event(struct input_dev *dev, static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
struct input_handle *handle = rcu_dereference(dev->grab); struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle) if (handle)
handle->handler->event(handle, type, code, value); handle->handler->event(handle, type, code, value);
else else
...@@ -82,6 +82,7 @@ static void input_pass_event(struct input_dev *dev, ...@@ -82,6 +82,7 @@ static void input_pass_event(struct input_dev *dev,
if (handle->open) if (handle->open)
handle->handler->event(handle, handle->handler->event(handle,
type, code, value); type, code, value);
rcu_read_unlock();
} }
/* /*
...@@ -293,9 +294,11 @@ void input_inject_event(struct input_handle *handle, ...@@ -293,9 +294,11 @@ void input_inject_event(struct input_handle *handle,
if (is_event_supported(type, dev->evbit, EV_MAX)) { if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
rcu_read_lock();
grab = rcu_dereference(dev->grab); grab = rcu_dereference(dev->grab);
if (!grab || grab == handle) if (!grab || grab == handle)
input_handle_event(dev, type, code, value); input_handle_event(dev, type, code, value);
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
} }
...@@ -325,11 +328,7 @@ int input_grab_device(struct input_handle *handle) ...@@ -325,11 +328,7 @@ int input_grab_device(struct input_handle *handle)
} }
rcu_assign_pointer(dev->grab, handle); rcu_assign_pointer(dev->grab, handle);
/* synchronize_rcu();
* Not using synchronize_rcu() because read-side is protected
* by a spinlock with interrupts off instead of rcu_read_lock().
*/
synchronize_sched();
out: out:
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
...@@ -344,7 +343,7 @@ static void __input_release_device(struct input_handle *handle) ...@@ -344,7 +343,7 @@ static void __input_release_device(struct input_handle *handle)
if (dev->grab == handle) { if (dev->grab == handle) {
rcu_assign_pointer(dev->grab, NULL); rcu_assign_pointer(dev->grab, NULL);
/* Make sure input_pass_event() notices that grab is gone */ /* Make sure input_pass_event() notices that grab is gone */
synchronize_sched(); synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node) list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open && handle->handler->start) if (handle->open && handle->handler->start)
...@@ -404,7 +403,7 @@ int input_open_device(struct input_handle *handle) ...@@ -404,7 +403,7 @@ int input_open_device(struct input_handle *handle)
* Make sure we are not delivering any more events * Make sure we are not delivering any more events
* through this handle * through this handle
*/ */
synchronize_sched(); synchronize_rcu();
} }
} }
...@@ -451,11 +450,11 @@ void input_close_device(struct input_handle *handle) ...@@ -451,11 +450,11 @@ void input_close_device(struct input_handle *handle)
if (!--handle->open) { if (!--handle->open) {
/* /*
* synchronize_sched() makes sure that input_pass_event() * synchronize_rcu() makes sure that input_pass_event()
* completed and that no more input events are delivered * completed and that no more input events are delivered
* through this handle * through this handle
*/ */
synchronize_sched(); synchronize_rcu();
} }
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
...@@ -1477,12 +1476,7 @@ int input_register_handle(struct input_handle *handle) ...@@ -1477,12 +1476,7 @@ int input_register_handle(struct input_handle *handle)
return error; return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list); list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
/* synchronize_rcu();
* We don't use synchronize_rcu() here because we rely
* on dev->event_lock to protect read-side critical
* section in input_pass_event().
*/
synchronize_sched();
/* /*
* Since we are supposed to be called from ->connect() * Since we are supposed to be called from ->connect()
...@@ -1521,7 +1515,7 @@ void input_unregister_handle(struct input_handle *handle) ...@@ -1521,7 +1515,7 @@ void input_unregister_handle(struct input_handle *handle)
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node); list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
synchronize_sched(); synchronize_rcu();
} }
EXPORT_SYMBOL(input_unregister_handle); EXPORT_SYMBOL(input_unregister_handle);
......
...@@ -149,8 +149,10 @@ static void joydev_event(struct input_handle *handle, ...@@ -149,8 +149,10 @@ static void joydev_event(struct input_handle *handle,
event.time = jiffies_to_msecs(jiffies); event.time = jiffies_to_msecs(jiffies);
rcu_read_lock();
list_for_each_entry_rcu(client, &joydev->client_list, node) list_for_each_entry_rcu(client, &joydev->client_list, node)
joydev_pass_event(client, &event); joydev_pass_event(client, &event);
rcu_read_unlock();
wake_up_interruptible(&joydev->wait); wake_up_interruptible(&joydev->wait);
} }
...@@ -178,12 +180,7 @@ static void joydev_attach_client(struct joydev *joydev, ...@@ -178,12 +180,7 @@ static void joydev_attach_client(struct joydev *joydev,
spin_lock(&joydev->client_lock); spin_lock(&joydev->client_lock);
list_add_tail_rcu(&client->node, &joydev->client_list); list_add_tail_rcu(&client->node, &joydev->client_list);
spin_unlock(&joydev->client_lock); spin_unlock(&joydev->client_lock);
/* synchronize_rcu();
* We don't use synchronize_rcu() here because read-side
* critical section is protected by a spinlock (dev->event_lock)
* instead of rcu_read_lock().
*/
synchronize_sched();
} }
static void joydev_detach_client(struct joydev *joydev, static void joydev_detach_client(struct joydev *joydev,
...@@ -192,7 +189,7 @@ static void joydev_detach_client(struct joydev *joydev, ...@@ -192,7 +189,7 @@ static void joydev_detach_client(struct joydev *joydev,
spin_lock(&joydev->client_lock); spin_lock(&joydev->client_lock);
list_del_rcu(&client->node); list_del_rcu(&client->node);
spin_unlock(&joydev->client_lock); spin_unlock(&joydev->client_lock);
synchronize_sched(); synchronize_rcu();
} }
static int joydev_open_device(struct joydev *joydev) static int joydev_open_device(struct joydev *joydev)
......
...@@ -265,6 +265,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, ...@@ -265,6 +265,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev,
unsigned int new_head; unsigned int new_head;
int wake_readers = 0; int wake_readers = 0;
rcu_read_lock();
list_for_each_entry_rcu(client, &mousedev->client_list, node) { list_for_each_entry_rcu(client, &mousedev->client_list, node) {
/* Just acquire the lock, interrupts already disabled */ /* Just acquire the lock, interrupts already disabled */
...@@ -309,6 +310,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, ...@@ -309,6 +310,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev,
wake_readers = 1; wake_readers = 1;
} }
} }
rcu_read_unlock();
if (wake_readers) if (wake_readers)
wake_up_interruptible(&mousedev->wait); wake_up_interruptible(&mousedev->wait);
...@@ -499,12 +501,7 @@ static void mousedev_attach_client(struct mousedev *mousedev, ...@@ -499,12 +501,7 @@ static void mousedev_attach_client(struct mousedev *mousedev,
spin_lock(&mousedev->client_lock); spin_lock(&mousedev->client_lock);
list_add_tail_rcu(&client->node, &mousedev->client_list); list_add_tail_rcu(&client->node, &mousedev->client_list);
spin_unlock(&mousedev->client_lock); spin_unlock(&mousedev->client_lock);
/* synchronize_rcu();
* We don't use synchronize_rcu() here because read-side
* critical section is protected by a spinlock (dev->event_lock)
* instead of rcu_read_lock().
*/
synchronize_sched();
} }
static void mousedev_detach_client(struct mousedev *mousedev, static void mousedev_detach_client(struct mousedev *mousedev,
...@@ -513,7 +510,7 @@ static void mousedev_detach_client(struct mousedev *mousedev, ...@@ -513,7 +510,7 @@ static void mousedev_detach_client(struct mousedev *mousedev,
spin_lock(&mousedev->client_lock); spin_lock(&mousedev->client_lock);
list_del_rcu(&client->node); list_del_rcu(&client->node);
spin_unlock(&mousedev->client_lock); spin_unlock(&mousedev->client_lock);
synchronize_sched(); synchronize_rcu();
} }
static int mousedev_release(struct inode *inode, struct file *file) static int mousedev_release(struct inode *inode, struct file *file)
......
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