Skip to content

Commit

Permalink
Input: use full RCU API
Browse files Browse the repository at this point in the history
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: Dmitry Torokhov <[email protected]>
  • Loading branch information
dtor committed Oct 13, 2007
1 parent 7009317 commit 82ba56c
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 48 deletions.
22 changes: 9 additions & 13 deletions drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ static void evdev_pass_event(struct evdev_client *client,
}

/*
* Pass incoming event to all connected clients. Note that we are
* 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().
* Pass incoming event to all connected clients.
*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
Expand All @@ -80,13 +77,17 @@ static void evdev_event(struct input_handle *handle,
event.code = code;
event.value = value;

rcu_read_lock();

client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);

rcu_read_unlock();

wake_up_interruptible(&evdev->wait);
}

Expand Down Expand Up @@ -142,12 +143,7 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
return error;

rcu_assign_pointer(evdev->grab, client);
/*
* We don't use synchronize_rcu() here because read-side
* critical section is protected by a spinlock instead
* of rcu_read_lock().
*/
synchronize_sched();
synchronize_rcu();

return 0;
}
Expand All @@ -158,7 +154,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
return -EINVAL;

rcu_assign_pointer(evdev->grab, NULL);
synchronize_sched();
synchronize_rcu();
input_release_device(&evdev->handle);

return 0;
Expand All @@ -170,7 +166,7 @@ static void evdev_attach_client(struct evdev *evdev,
spin_lock(&evdev->client_lock);
list_add_tail_rcu(&client->node, &evdev->client_list);
spin_unlock(&evdev->client_lock);
synchronize_sched();
synchronize_rcu();
}

static void evdev_detach_client(struct evdev *evdev,
Expand All @@ -179,7 +175,7 @@ static void evdev_detach_client(struct evdev *evdev,
spin_lock(&evdev->client_lock);
list_del_rcu(&client->node);
spin_unlock(&evdev->client_lock);
synchronize_sched();
synchronize_rcu();
}

static int evdev_open_device(struct evdev *evdev)
Expand Down
36 changes: 15 additions & 21 deletions drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,24 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)

/*
* Pass event through all open handles. This function is called with
* dev->event_lock held and interrupts disabled. Because of that we
* 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().
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
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)
handle->handler->event(handle, type, code, value);
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}

/*
Expand Down Expand Up @@ -293,9 +294,11 @@ void input_inject_event(struct input_handle *handle,
if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags);

rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);
rcu_read_unlock();

spin_unlock_irqrestore(&dev->event_lock, flags);
}
Expand Down Expand Up @@ -325,11 +328,7 @@ int input_grab_device(struct input_handle *handle)
}

rcu_assign_pointer(dev->grab, handle);
/*
* Not using synchronize_rcu() because read-side is protected
* by a spinlock with interrupts off instead of rcu_read_lock().
*/
synchronize_sched();
synchronize_rcu();

out:
mutex_unlock(&dev->mutex);
Expand All @@ -344,7 +343,7 @@ static void __input_release_device(struct input_handle *handle)
if (dev->grab == handle) {
rcu_assign_pointer(dev->grab, NULL);
/* Make sure input_pass_event() notices that grab is gone */
synchronize_sched();
synchronize_rcu();

list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open && handle->handler->start)
Expand Down Expand Up @@ -404,7 +403,7 @@ int input_open_device(struct input_handle *handle)
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_sched();
synchronize_rcu();
}
}

Expand Down Expand Up @@ -451,11 +450,11 @@ void input_close_device(struct input_handle *handle)

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
* through this handle
*/
synchronize_sched();
synchronize_rcu();
}

mutex_unlock(&dev->mutex);
Expand Down Expand Up @@ -1477,12 +1476,7 @@ int input_register_handle(struct input_handle *handle)
return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex);
/*
* 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();
synchronize_rcu();

/*
* Since we are supposed to be called from ->connect()
Expand Down Expand Up @@ -1521,7 +1515,7 @@ void input_unregister_handle(struct input_handle *handle)
mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex);
synchronize_sched();
synchronize_rcu();
}
EXPORT_SYMBOL(input_unregister_handle);

Expand Down
11 changes: 4 additions & 7 deletions drivers/input/joydev.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ static void joydev_event(struct input_handle *handle,

event.time = jiffies_to_msecs(jiffies);

rcu_read_lock();
list_for_each_entry_rcu(client, &joydev->client_list, node)
joydev_pass_event(client, &event);
rcu_read_unlock();

wake_up_interruptible(&joydev->wait);
}
Expand Down Expand Up @@ -178,12 +180,7 @@ static void joydev_attach_client(struct joydev *joydev,
spin_lock(&joydev->client_lock);
list_add_tail_rcu(&client->node, &joydev->client_list);
spin_unlock(&joydev->client_lock);
/*
* 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();
synchronize_rcu();
}

static void joydev_detach_client(struct joydev *joydev,
Expand All @@ -192,7 +189,7 @@ static void joydev_detach_client(struct joydev *joydev,
spin_lock(&joydev->client_lock);
list_del_rcu(&client->node);
spin_unlock(&joydev->client_lock);
synchronize_sched();
synchronize_rcu();
}

static int joydev_open_device(struct joydev *joydev)
Expand Down
11 changes: 4 additions & 7 deletions drivers/input/mousedev.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev,
unsigned int new_head;
int wake_readers = 0;

rcu_read_lock();
list_for_each_entry_rcu(client, &mousedev->client_list, node) {

/* Just acquire the lock, interrupts already disabled */
Expand Down Expand Up @@ -309,6 +310,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev,
wake_readers = 1;
}
}
rcu_read_unlock();

if (wake_readers)
wake_up_interruptible(&mousedev->wait);
Expand Down Expand Up @@ -499,12 +501,7 @@ static void mousedev_attach_client(struct mousedev *mousedev,
spin_lock(&mousedev->client_lock);
list_add_tail_rcu(&client->node, &mousedev->client_list);
spin_unlock(&mousedev->client_lock);
/*
* 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();
synchronize_rcu();
}

static void mousedev_detach_client(struct mousedev *mousedev,
Expand All @@ -513,7 +510,7 @@ static void mousedev_detach_client(struct mousedev *mousedev,
spin_lock(&mousedev->client_lock);
list_del_rcu(&client->node);
spin_unlock(&mousedev->client_lock);
synchronize_sched();
synchronize_rcu();
}

static int mousedev_release(struct inode *inode, struct file *file)
Expand Down

0 comments on commit 82ba56c

Please sign in to comment.