diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 7240d00ace86f331b33a13d6761f860fc5261800..e2aa4910365d6996b1e02d041a28ce8d65c4a05b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -510,6 +510,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { return -ENOSYS; } +static inline __poll_t kernfs_generic_poll(struct kernfs_open_file *of, + struct poll_table_struct *pt) +{ return -ENOSYS; } + static inline void kernfs_notify(struct kernfs_node *kn) { } static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name, diff --git a/include/linux/psi.h b/include/linux/psi.h index d290f0493c3335cddcc9153d4cdf36499866c0b4..41079ebe17a6a878cda9aa525a0b9701140c6ab3 100644 --- a/include/linux/psi.h +++ b/include/linux/psi.h @@ -32,8 +32,9 @@ int psi_cgroup_alloc(struct cgroup *cgrp); void psi_cgroup_free(struct cgroup *cgrp); void cgroup_move_task(struct task_struct *p, struct css_set *to); -struct psi_trigger *psi_trigger_create(struct psi_group *group, - char *buf, size_t nbytes, enum psi_res res); +struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf, + size_t nbytes, enum psi_res res, + struct kernfs_open_file *of); void psi_trigger_destroy(struct psi_trigger *t); __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file, diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h index c17aeb774e23a2d77b5a4008c433e47f46e0d951..0b6e17e7f84f050a6f3bdb5a51ad35bd9a1c3a02 100644 --- a/include/linux/psi_types.h +++ b/include/linux/psi_types.h @@ -173,6 +173,9 @@ struct psi_trigger { /* Wait queue for polling */ wait_queue_head_t event_wait; + /* Kernfs file for cgroup triggers */ + struct kernfs_open_file *of; + /* Pending event flag */ int event; diff --git a/init/Kconfig b/init/Kconfig index b137a6c043ac6d0d9ac36e4cfef3a2aa54dca752..2eb3f376ff4fc0a09490cde8fcc1eb803be0f6a0 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -603,6 +603,7 @@ config TASK_IO_ACCOUNTING config PSI bool "Pressure stall information tracking" + select KERNFS help Collect metrics that indicate how overcommitted the CPU, memory, and IO capacity are in the system. diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index d0a4a1c4c38d2f9fe7879be2b32bba6e6f32b4d1..262688aa2b7f11b20a252b950720d7653b57ec7c 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3718,7 +3718,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, } psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; - new = psi_trigger_create(psi, buf, nbytes, res); + new = psi_trigger_create(psi, buf, nbytes, res, of); if (IS_ERR(new)) { cgroup_put(cgrp); return PTR_ERR(new); diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 25f7d46ad7bd37214496f1a02abeb35f5e3f443e..962fe88bb5f9f9f9ef7ebeeed7c412d2f38fdaab 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -553,8 +553,12 @@ static u64 update_triggers(struct psi_group *group, u64 now) continue; /* Generate an event */ - if (cmpxchg(&t->event, 0, 1) == 0) - wake_up_interruptible(&t->event_wait); + if (cmpxchg(&t->event, 0, 1) == 0) { + if (t->of) + kernfs_notify(t->of->kn); + else + wake_up_interruptible(&t->event_wait); + } t->last_event_time = now; } @@ -1132,8 +1136,9 @@ static int psi_cpu_open(struct inode *inode, struct file *file) return single_open(file, psi_cpu_show, NULL); } -struct psi_trigger *psi_trigger_create(struct psi_group *group, - char *buf, size_t nbytes, enum psi_res res) +struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf, + size_t nbytes, enum psi_res res, + struct kernfs_open_file *of) { struct psi_trigger *t; enum psi_states state; @@ -1173,7 +1178,9 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, t->event = 0; t->last_event_time = 0; - init_waitqueue_head(&t->event_wait); + t->of = of; + if (!of) + init_waitqueue_head(&t->event_wait); mutex_lock(&group->trigger_lock); @@ -1219,7 +1226,10 @@ void psi_trigger_destroy(struct psi_trigger *t) * Wakeup waiters to stop polling. Can happen if cgroup is deleted * from under a polling process. */ - wake_up_interruptible(&t->event_wait); + if (t->of) + kernfs_notify(t->of->kn); + else + wake_up_interruptible(&t->event_wait); mutex_lock(&group->trigger_lock); @@ -1282,7 +1292,10 @@ __poll_t psi_trigger_poll(void **trigger_ptr, if (!t) return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI; - poll_wait(file, &t->event_wait, wait); + if (t->of) + kernfs_generic_poll(t->of, wait); + else + poll_wait(file, &t->event_wait, wait); if (cmpxchg(&t->event, 1, 0) == 1) ret |= EPOLLPRI; @@ -1321,7 +1334,7 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf, return -EBUSY; } - new = psi_trigger_create(&psi_system, buf, nbytes, res); + new = psi_trigger_create(&psi_system, buf, nbytes, res, NULL); if (IS_ERR(new)) { mutex_unlock(&seq->lock); return PTR_ERR(new);