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: Radu Rendec <radu.rendec@gmail.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6be244dcd5
commit
03c0a9208b
@@ -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)
|
static void kernfs_notify_workfn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct kernfs_node *kn;
|
struct kernfs_node *kn;
|
||||||
struct kernfs_open_node *on;
|
|
||||||
struct kernfs_super_info *info;
|
struct kernfs_super_info *info;
|
||||||
repeat:
|
repeat:
|
||||||
/* pop one off the notify_list */
|
/* pop one off the notify_list */
|
||||||
@@ -871,17 +870,6 @@ repeat:
|
|||||||
kn->attr.notify_next = NULL;
|
kn->attr.notify_next = NULL;
|
||||||
spin_unlock_irq(&kernfs_notify_lock);
|
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 */
|
/* kick fsnotify */
|
||||||
mutex_lock(&kernfs_mutex);
|
mutex_lock(&kernfs_mutex);
|
||||||
|
|
||||||
@@ -934,10 +922,21 @@ void kernfs_notify(struct kernfs_node *kn)
|
|||||||
{
|
{
|
||||||
static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn);
|
static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct kernfs_open_node *on;
|
||||||
|
|
||||||
if (WARN_ON(kernfs_type(kn) != KERNFS_FILE))
|
if (WARN_ON(kernfs_type(kn) != KERNFS_FILE))
|
||||||
return;
|
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);
|
spin_lock_irqsave(&kernfs_notify_lock, flags);
|
||||||
if (!kn->attr.notify_next) {
|
if (!kn->attr.notify_next) {
|
||||||
kernfs_get(kn);
|
kernfs_get(kn);
|
||||||
|
|||||||
Reference in New Issue
Block a user