Implement ->proc_write_buf() for the procfs channel, flush and
use-gss-proxy files so procfs copies in what is written before it pins
the entry. The channel file parses the downcall from that copy and the
flush files share the parsing with rpc_pipefs in do_write_flush(). The
rpc_pipefs files keep copying in themselves.

CACHE_DOWNCALL_MAX and CACHE_FLUSH_MAX name the limits both sides
enforce, procfs through ->proc_write_size. The procfs files are removed
when the network namespace goes away and that no longer waits for a
writer that faults on its buffer.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
 net/sunrpc/auth_gss/svcauth_gss.c | 10 +++----
 net/sunrpc/cache.c                | 63 +++++++++++++++++++++++++++------------
 2 files changed, 48 insertions(+), 25 deletions(-)

diff --git a/net/sunrpc/auth_gss/svcauth_gss.c 
b/net/sunrpc/auth_gss/svcauth_gss.c
index 43839e805531..8d105cd900d4 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1408,8 +1408,8 @@ svcauth_gss_proc_init(struct svc_rqst *rqstp, struct 
rpc_gss_wire_cred *gc)
 
 #ifdef CONFIG_PROC_FS
 
-static ssize_t write_gssp(struct file *file, const char __user *buf,
-                        size_t count, loff_t *ppos)
+static ssize_t write_gssp(struct file *file, char *buf, size_t count,
+                         loff_t *ppos)
 {
        struct net *net = pde_data(file_inode(file));
        char tbuf[20];
@@ -1418,9 +1418,7 @@ static ssize_t write_gssp(struct file *file, const char 
__user *buf,
 
        if (*ppos || count > sizeof(tbuf)-1)
                return -EINVAL;
-       if (copy_from_user(tbuf, buf, count))
-               return -EFAULT;
-
+       memcpy(tbuf, buf, count);
        tbuf[count] = 0;
        res = kstrtoul(tbuf, 0, &i);
        if (res)
@@ -1468,7 +1466,7 @@ static ssize_t read_gssp(struct file *file, char __user 
*buf,
 
 static const struct proc_ops use_gss_proxy_proc_ops = {
        .proc_open      = nonseekable_open,
-       .proc_write     = write_gssp,
+       .proc_write_buf = write_gssp,
        .proc_read      = read_gssp,
 };
 
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 007521e8a57f..a257598768fa 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -924,6 +924,9 @@ static ssize_t cache_do_downcall(char *kaddr, const char 
__user *buf,
        return ret;
 }
 
+/* 32k is max userland buffer, lets check anyway */
+#define CACHE_DOWNCALL_MAX     (32768 - 1)
+
 static ssize_t cache_downcall(struct address_space *mapping,
                              const char __user *buf,
                              size_t count, struct cache_detail *cd)
@@ -931,7 +934,7 @@ static ssize_t cache_downcall(struct address_space *mapping,
        char *write_buf;
        ssize_t ret = -ENOMEM;
 
-       if (count >= 32768) { /* 32k is max userland buffer, lets check anyway 
*/
+       if (count > CACHE_DOWNCALL_MAX) {
                ret = -EINVAL;
                goto out;
        }
@@ -1508,19 +1511,15 @@ static ssize_t read_flush(struct file *file, char 
__user *buf,
        return simple_read_from_buffer(buf, count, ppos, tbuf, len);
 }
 
-static ssize_t write_flush(struct file *file, const char __user *buf,
-                          size_t count, loff_t *ppos,
-                          struct cache_detail *cd)
+/* longest number the flush files take */
+#define CACHE_FLUSH_MAX                19
+
+static ssize_t do_write_flush(char *tbuf, size_t count, loff_t *ppos,
+                             struct cache_detail *cd)
 {
-       char tbuf[20];
        char *ep;
        time64_t now;
 
-       if (*ppos || count > sizeof(tbuf)-1)
-               return -EINVAL;
-       if (copy_from_user(tbuf, buf, count))
-               return -EFAULT;
-       tbuf[count] = 0;
        simple_strtoul(tbuf, &ep, 0);
        if (*ep && *ep != '\n')
                return -EINVAL;
@@ -1551,6 +1550,20 @@ static ssize_t write_flush(struct file *file, const char 
__user *buf,
        return count;
 }
 
+static ssize_t write_flush(struct file *file, const char __user *buf,
+                          size_t count, loff_t *ppos,
+                          struct cache_detail *cd)
+{
+       char tbuf[CACHE_FLUSH_MAX + 1];
+
+       if (*ppos || count > CACHE_FLUSH_MAX)
+               return -EINVAL;
+       if (copy_from_user(tbuf, buf, count))
+               return -EFAULT;
+       tbuf[count] = 0;
+       return do_write_flush(tbuf, count, ppos, cd);
+}
+
 static ssize_t cache_read_procfs(struct file *filp, char __user *buf,
                                 size_t count, loff_t *ppos)
 {
@@ -1559,12 +1572,21 @@ static ssize_t cache_read_procfs(struct file *filp, 
char __user *buf,
        return cache_read(filp, buf, count, ppos, cd);
 }
 
-static ssize_t cache_write_procfs(struct file *filp, const char __user *buf,
-                                 size_t count, loff_t *ppos)
+/* procfs copied in what was written */
+static ssize_t cache_write_procfs(struct file *filp, char *buf, size_t count,
+                                 loff_t *ppos)
 {
        struct cache_detail *cd = pde_data(file_inode(filp));
+       struct inode *inode = file_inode(filp);
+       ssize_t ret;
 
-       return cache_write(filp, buf, count, ppos, cd);
+       if (!cd->cache_parse || !count)
+               return -EINVAL;
+
+       inode_lock(inode);
+       ret = cd->cache_parse(cd, buf, count);
+       inode_unlock(inode);
+       return ret ? ret : count;
 }
 
 static __poll_t cache_poll_procfs(struct file *filp, poll_table *wait)
@@ -1599,7 +1621,8 @@ static int cache_release_procfs(struct inode *inode, 
struct file *filp)
 
 static const struct proc_ops cache_channel_proc_ops = {
        .proc_read      = cache_read_procfs,
-       .proc_write     = cache_write_procfs,
+       .proc_write_buf = cache_write_procfs,
+       .proc_write_size = CACHE_DOWNCALL_MAX,
        .proc_poll      = cache_poll_procfs,
        .proc_ioctl     = cache_ioctl_procfs, /* for FIONREAD */
        .proc_open      = cache_open_procfs,
@@ -1653,19 +1676,21 @@ static ssize_t read_flush_procfs(struct file *filp, 
char __user *buf,
        return read_flush(filp, buf, count, ppos, cd);
 }
 
-static ssize_t write_flush_procfs(struct file *filp,
-                                 const char __user *buf,
-                                 size_t count, loff_t *ppos)
+static ssize_t write_flush_procfs(struct file *filp, char *buf, size_t count,
+                                 loff_t *ppos)
 {
        struct cache_detail *cd = pde_data(file_inode(filp));
 
-       return write_flush(filp, buf, count, ppos, cd);
+       if (*ppos)
+               return -EINVAL;
+       return do_write_flush(buf, count, ppos, cd);
 }
 
 static const struct proc_ops cache_flush_proc_ops = {
        .proc_open      = open_flush_procfs,
        .proc_read      = read_flush_procfs,
-       .proc_write     = write_flush_procfs,
+       .proc_write_buf = write_flush_procfs,
+       .proc_write_size = CACHE_FLUSH_MAX,
        .proc_release   = release_flush_procfs,
 };
 

-- 
2.53.0


Reply via email to