[PATCH RESEND v2 10/13] SUNRPC: let procfs own the wait queue of the procfs channel files
From: Christian Brauner
Date: Wed Nov 04 2026 - 18:32:18 EST
cache_poll() sleeps the poller on queue_wait, which went back to being
a static queue so that a poll() on a procfs channel file can't be left
on the queue of a cache_detail that its network namespace freed. procfs
owns the queue poll() uses now and it outlives the file, so the procfs
channel files leave the poll_wait() to procfs and an upcall wakes their
pollers through proc_poll_notify(). The channel entry is remembered in
the cache_detail for that and forgotten before the entries are removed.
The rpc_pipefs files keep sleeping on queue_wait, procfs has nothing to
do with them.
Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
include/linux/sunrpc/cache.h | 2 ++
net/sunrpc/cache.c | 20 +++++++++++---------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index bf4fc543e1e5..9d508205ebb2 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -129,6 +129,8 @@ struct cache_detail {
struct proc_dir_entry *procfs;
struct dentry *pipefs;
};
+ /* the channel file in @procfs, for proc_poll_notify() */
+ struct proc_dir_entry *procfs_channel;
struct net *net;
};
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index d242b6f33cbc..f220a3036b6e 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -970,20 +970,18 @@ out:
}
/*
- * Not in struct cache_detail: poll and epoll waiters stay queued until
- * their file is closed, but a channel file in procfs can stay open after
- * the cache_detail of its dying network namespace has been freed.
+ * For the rpc_pipefs channel files. Not in struct cache_detail: poll and
+ * epoll waiters stay queued until their file is closed, which can be after
+ * the cache_detail is gone. The procfs channel files are polled on the wait
+ * queue procfs owns for them instead, see proc_poll_notify().
*/
static DECLARE_WAIT_QUEUE_HEAD(queue_wait);
-static __poll_t cache_poll(struct file *filp, poll_table *wait,
- struct cache_detail *cd)
+static __poll_t cache_poll(struct file *filp, struct cache_detail *cd)
{
__poll_t mask;
struct cache_reader *rp = filp->private_data;
- poll_wait(filp, &queue_wait, wait);
-
/* alway allow write */
mask = EPOLLOUT | EPOLLWRNORM;
@@ -1248,6 +1246,7 @@ static int cache_do_upcall(struct cache_detail *detail, struct cache_head *h)
if (ret != -EAGAIN && detail->cache_notify)
detail->cache_notify(detail, h);
wake_up(&queue_wait);
+ proc_poll_notify(detail->procfs_channel);
if (ret == -EAGAIN) {
kfree(buf);
kfree(crq);
@@ -1593,7 +1592,7 @@ static __poll_t cache_poll_procfs(struct file *filp, poll_table *wait)
{
struct cache_detail *cd = pde_data(file_inode(filp));
- return cache_poll(filp, wait, cd);
+ return cache_poll(filp, cd);
}
static int cache_open_procfs(struct inode *inode, struct file *filp)
@@ -1690,6 +1689,7 @@ static const struct proc_ops cache_flush_proc_ops = {
static void remove_cache_proc_entries(struct cache_detail *cd)
{
if (cd->procfs) {
+ cd->procfs_channel = NULL;
proc_remove(cd->procfs);
cd->procfs = NULL;
}
@@ -1718,6 +1718,7 @@ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
&cache_channel_proc_ops, cd);
if (p == NULL)
goto out_nomem;
+ cd->procfs_channel = p;
}
if (cd->cache_show) {
p = proc_create_data("content", S_IFREG | 0400, cd->procfs,
@@ -1806,7 +1807,8 @@ static __poll_t cache_poll_pipefs(struct file *filp, poll_table *wait)
{
struct cache_detail *cd = RPC_I(file_inode(filp))->private;
- return cache_poll(filp, wait, cd);
+ poll_wait(filp, &queue_wait, wait);
+ return cache_poll(filp, cd);
}
static long cache_ioctl_pipefs(struct file *filp,
--
2.53.0