[PATCH RESEND v2 04/23] proc: wait for the last user of an entry with wait_var_event()
From: Christian Brauner
Date: Wed Nov 04 2026 - 15:24:07 EST
proc_entry_rundown() waits for the last user of an entry with a
completion on its stack that it points the entry at while it waits.
That's a pointer in every struct proc_dir_entry for something that
happens once in the life of an entry, if at all.
Wait on the count itself with wait_var_event() instead and let
unuse_pde() wake the waiter with wake_up_var() when the count hits the
bias. The waiters sleep on the hashed wait queues behind that, so
procfs doesn't need a wait queue of its own for this, neither in the
entry nor a global one. kernfs keeps one per root for the same thing,
deactivate_waitq. Note that atomic_dec_return() is fully ordered, so
the count is visible before wake_up_var() looks for waiters.
No functional changes.
Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
fs/proc/inode.c | 7 +++----
fs/proc/internal.h | 1 -
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 66a3688757dd..8795add1898d 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/mount.h>
#include <linux/bug.h>
+#include <linux/wait_bit.h>
#include "internal.h"
@@ -203,7 +204,7 @@ static inline int use_pde(struct proc_dir_entry *pde)
static void unuse_pde(struct proc_dir_entry *pde)
{
if (unlikely(atomic_dec_return(&pde->in_use) == BIAS))
- complete(pde->pde_unload_completion);
+ wake_up_var(&pde->in_use);
}
/* Pin an entry that can go away around a call into it, see use_pde(). */
@@ -266,11 +267,9 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
void proc_entry_rundown(struct proc_dir_entry *de)
{
- DECLARE_COMPLETION_ONSTACK(c);
/* Wait until all existing callers into module are done. */
- de->pde_unload_completion = &c;
if (atomic_add_return(BIAS, &de->in_use) != BIAS)
- wait_for_completion(&c);
+ wait_var_event(&de->in_use, atomic_read(&de->in_use) == BIAS);
/* ->pde_openers list can't grow from now on. */
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 6b61d09ac5e5..ab4d7bd1fb75 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -38,7 +38,6 @@ struct proc_dir_entry {
struct list_head pde_openers; /* who did ->open, but not ->release */
/* protects ->pde_openers and all struct pde_opener instances */
spinlock_t pde_unload_lock;
- struct completion *pde_unload_completion;
const struct inode_operations *proc_iops;
union {
const struct proc_ops *proc_ops;
--
2.53.0