diff options
Diffstat (limited to '')
-rw-r--r-- | debian/patches-rt/0310-eventfd-Make-signal-recursion-protection-a-task-bit.patch | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/debian/patches-rt/0310-eventfd-Make-signal-recursion-protection-a-task-bit.patch b/debian/patches-rt/0310-eventfd-Make-signal-recursion-protection-a-task-bit.patch new file mode 100644 index 000000000..719316f76 --- /dev/null +++ b/debian/patches-rt/0310-eventfd-Make-signal-recursion-protection-a-task-bit.patch @@ -0,0 +1,150 @@ +From 17c41196e72418f94cf308a8b23fe478612a1610 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Fri, 17 Dec 2021 11:32:09 +0100 +Subject: [PATCH 310/323] eventfd: Make signal recursion protection a task bit +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.204-rt100.tar.xz + +Upstream commit b542e383d8c005f06a131e2b40d5889b812f19c6 + +The recursion protection for eventfd_signal() is based on a per CPU +variable and relies on the !RT semantics of spin_lock_irqsave() for +protecting this per CPU variable. On RT kernels spin_lock_irqsave() neither +disables preemption nor interrupts which allows the spin lock held section +to be preempted. If the preempting task invokes eventfd_signal() as well, +then the recursion warning triggers. + +Paolo suggested to protect the per CPU variable with a local lock, but +that's heavyweight and actually not necessary. The goal of this protection +is to prevent the task stack from overflowing, which can be achieved with a +per task recursion protection as well. + +Replace the per CPU variable with a per task bit similar to other recursion +protection bits like task_struct::in_page_owner. This works on both !RT and +RT kernels and removes as a side effect the extra per CPU storage. + +No functional change for !RT kernels. + +Reported-by: Daniel Bristot de Oliveira <bristot@redhat.com> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Tested-by: Daniel Bristot de Oliveira <bristot@redhat.com> +Acked-by: Jason Wang <jasowang@redhat.com> +Cc: Al Viro <viro@zeniv.linux.org.uk> +Link: https://lore.kernel.org/r/87wnp9idso.ffs@tglx +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Signed-off-by: Luis Claudio R. Goncalves <lgoncalv@redhat.com> +--- + fs/aio.c | 2 +- + fs/eventfd.c | 12 +++++------- + include/linux/eventfd.h | 11 +++++------ + include/linux/sched.h | 4 ++++ + 4 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/fs/aio.c b/fs/aio.c +index c90e045a37bc..e1181dc37be1 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -1765,7 +1765,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, + list_del_init(&req->wait.entry); + list_del(&iocb->ki_list); + iocb->ki_res.res = mangle_poll(mask); +- if (iocb->ki_eventfd && eventfd_signal_count()) { ++ if (iocb->ki_eventfd && eventfd_signal_allowed()) { + iocb = NULL; + INIT_WORK(&req->work, aio_poll_put_work); + schedule_work(&req->work); +diff --git a/fs/eventfd.c b/fs/eventfd.c +index 3673eb8de035..ce9ca07d6c00 100644 +--- a/fs/eventfd.c ++++ b/fs/eventfd.c +@@ -25,8 +25,6 @@ + #include <linux/idr.h> + #include <linux/uio.h> + +-DEFINE_PER_CPU(int, eventfd_wake_count); +- + static DEFINE_IDA(eventfd_ida); + + struct eventfd_ctx { +@@ -53,21 +51,21 @@ __u64 eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n, unsigned mask) + * Deadlock or stack overflow issues can happen if we recurse here + * through waitqueue wakeup handlers. If the caller users potentially + * nested waitqueues with custom wakeup handlers, then it should +- * check eventfd_signal_count() before calling this function. If +- * it returns true, the eventfd_signal() call should be deferred to a ++ * check eventfd_signal_allowed() before calling this function. If ++ * it returns false, the eventfd_signal() call should be deferred to a + * safe context. + */ +- if (WARN_ON_ONCE(this_cpu_read(eventfd_wake_count))) ++ if (WARN_ON_ONCE(current->in_eventfd_signal)) + return 0; + + spin_lock_irqsave(&ctx->wqh.lock, flags); +- this_cpu_inc(eventfd_wake_count); ++ current->in_eventfd_signal = 1; + if (ULLONG_MAX - ctx->count < n) + n = ULLONG_MAX - ctx->count; + ctx->count += n; + if (waitqueue_active(&ctx->wqh)) + wake_up_locked_poll(&ctx->wqh, EPOLLIN | mask); +- this_cpu_dec(eventfd_wake_count); ++ current->in_eventfd_signal = 0; + spin_unlock_irqrestore(&ctx->wqh.lock, flags); + + return n; +diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h +index c1bd4883e2fa..842d223dfe17 100644 +--- a/include/linux/eventfd.h ++++ b/include/linux/eventfd.h +@@ -14,6 +14,7 @@ + #include <linux/err.h> + #include <linux/percpu-defs.h> + #include <linux/percpu.h> ++#include <linux/sched.h> + + /* + * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining +@@ -44,11 +45,9 @@ int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *w + __u64 *cnt); + void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt); + +-DECLARE_PER_CPU(int, eventfd_wake_count); +- +-static inline bool eventfd_signal_count(void) ++static inline bool eventfd_signal_allowed(void) + { +- return this_cpu_read(eventfd_wake_count); ++ return !current->in_eventfd_signal; + } + + #else /* CONFIG_EVENTFD */ +@@ -85,9 +84,9 @@ static inline int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, + return -ENOSYS; + } + +-static inline bool eventfd_signal_count(void) ++static inline bool eventfd_signal_allowed(void) + { +- return false; ++ return true; + } + + static inline void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt) +diff --git a/include/linux/sched.h b/include/linux/sched.h +index a73528e8235d..13d4957189bb 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -848,6 +848,10 @@ struct task_struct { + /* Stalled due to lack of memory */ + unsigned in_memstall:1; + #endif ++#ifdef CONFIG_EVENTFD ++ /* Recursion prevention for eventfd_signal() */ ++ unsigned in_eventfd_signal:1; ++#endif + + unsigned long atomic_flags; /* Flags requiring atomic access. */ + +-- +2.43.0 + |