Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −13
Original line number Original line Diff line number Diff line
@@ -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,
	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,
		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)
		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)
		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,
	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,
	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)
+15 −21
Original line number Original line Diff line number Diff line
@@ -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,
			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,
	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)
	}
	}


	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)
	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)
			 * 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)


	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)
		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)
	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);


+4 −7
Original line number Original line Diff line number Diff line
@@ -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,
	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,
	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)
+4 −7
Original line number Original line Diff line number Diff line
@@ -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,
			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,
	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,
	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)