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) <[email protected]>
---
 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


Reply via email to