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

Commit 03c0a920 authored by Radu Rendec's avatar Radu Rendec Committed by Greg Kroah-Hartman
Browse files

kernfs: Improve kernfs_notify() poll notification latency



kernfs_notify() does two notifications: poll and fsnotify. Originally,
both notifications were done from scheduled work context and all that
kernfs_notify() did was schedule the work.

This patch simply moves the poll notification from the scheduled work
handler to kernfs_notify(). The fsnotify notification still needs to be
done from scheduled work context because it can sleep (it needs to lock
a mutex).

If the poll notification is time critical (the notified thread needs to
wake as quickly as possible), it's better to do it from kernfs_notify()
directly. One example is calling sysfs_notify_dirent() from a hardware
interrupt handler to wake up a thread and handle the interrupt in user
space.

Signed-off-by: default avatarRadu Rendec <radu.rendec@gmail.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6be244dc
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -857,7 +857,6 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
static void kernfs_notify_workfn(struct work_struct *work)
{
	struct kernfs_node *kn;
	struct kernfs_open_node *on;
	struct kernfs_super_info *info;
repeat:
	/* pop one off the notify_list */
@@ -871,17 +870,6 @@ static void kernfs_notify_workfn(struct work_struct *work)
	kn->attr.notify_next = NULL;
	spin_unlock_irq(&kernfs_notify_lock);

	/* kick poll */
	spin_lock_irq(&kernfs_open_node_lock);

	on = kn->attr.open;
	if (on) {
		atomic_inc(&on->event);
		wake_up_interruptible(&on->poll);
	}

	spin_unlock_irq(&kernfs_open_node_lock);

	/* kick fsnotify */
	mutex_lock(&kernfs_mutex);

@@ -934,10 +922,21 @@ void kernfs_notify(struct kernfs_node *kn)
{
	static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn);
	unsigned long flags;
	struct kernfs_open_node *on;

	if (WARN_ON(kernfs_type(kn) != KERNFS_FILE))
		return;

	/* kick poll immediately */
	spin_lock_irqsave(&kernfs_open_node_lock, flags);
	on = kn->attr.open;
	if (on) {
		atomic_inc(&on->event);
		wake_up_interruptible(&on->poll);
	}
	spin_unlock_irqrestore(&kernfs_open_node_lock, flags);

	/* schedule work to kick fsnotify */
	spin_lock_irqsave(&kernfs_notify_lock, flags);
	if (!kn->attr.notify_next) {
		kernfs_get(kn);