Nothing implements them anymore. Every entry that can be removed fills
procfs' buffer through ->proc_read_buf() or is a seq_file entry, and
the permanent ones that still read straight into userspace have
file_operations of their own now.

With them go the flag, the registration checks that kept them apart
from ->proc_read_buf() and the seq_file entries, proc_reg_read(), and
two of the three sets of file_operations for regular files:
proc_reg_llseek() and proc_reg_read_iter() hand a seq_file entry to
seq_lseek() and seq_read_iter() themselves now, like
kernfs_fop_read_iter() does, so one set serves every entry that has
proc_ops. That set has ->splice_read(), so a splice() from an entry
that can't be read at all, a write-only one, fails with -EIO now
instead of -EINVAL.

Nothing in struct proc_ops takes a __user pointer anymore.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
 fs/proc/generic.c       | 14 ++++------
 fs/proc/inode.c         | 69 +++++--------------------------------------------
 fs/proc/internal.h      |  5 ----
 include/linux/proc_fs.h |  4 +--
 4 files changed, 12 insertions(+), 80 deletions(-)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 4e0142fec582..2515df3a0110 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -454,8 +454,7 @@ static int pde_set_flags(struct proc_dir_entry *pde)
        }
        if (pde_is_seq_file(pde)) {
                /* procfs reads and seeks through the seq_file itself */
-               if (WARN_ON_ONCE(proc_ops->proc_read || 
proc_ops->proc_read_iter ||
-                                proc_ops->proc_lseek))
+               if (WARN_ON_ONCE(proc_ops->proc_lseek))
                        return -EINVAL;
                /* and frees it, see pde_seq_release() */
                if (WARN_ON_ONCE(proc_ops->proc_release == seq_release ||
@@ -463,11 +462,8 @@ static int pde_set_flags(struct proc_dir_entry *pde)
                                 proc_ops->proc_release == single_release))
                        return -EINVAL;
                pde->flags |= PROC_ENTRY_proc_lseek;
-       } else {
-               if (proc_ops->proc_read_iter)
-                       pde->flags |= PROC_ENTRY_proc_read_iter;
-               if (proc_ops->proc_lseek)
-                       pde->flags |= PROC_ENTRY_proc_lseek;
+       } else if (proc_ops->proc_lseek) {
+               pde->flags |= PROC_ENTRY_proc_lseek;
        }
        if (proc_ops->proc_poll)
                pde->flags |= PROC_ENTRY_proc_poll;
@@ -482,8 +478,8 @@ static int pde_set_flags(struct proc_dir_entry *pde)
                        pde->flags |= PROC_ENTRY_SHORT_WRITES;
        }
        if (proc_ops->proc_read_buf) {
-               if (WARN_ON_ONCE(pde_is_seq_file(pde) || proc_ops->proc_read ||
-                                proc_ops->proc_read_iter))
+               /* procfs reads through the seq_file itself */
+               if (WARN_ON_ONCE(pde_is_seq_file(pde)))
                        return -EINVAL;
                pde->flags |= PROC_ENTRY_proc_read_buf;
                pde->read_size = proc_ops->proc_read_size ?: PAGE_SIZE;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 49ae30b6e515..9719c1b89de3 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -413,6 +413,9 @@ static loff_t proc_reg_llseek(struct file *file, loff_t 
offset, int whence)
        struct proc_dir_entry *pde = PDE(file_inode(file));
        loff_t rv;
 
+       /* procfs seeks through the seq_file itself, see pde_seq_start() */
+       if (pde_is_seq_file(pde))
+               return seq_lseek(file, offset, whence);
        if (!pde_pin(pde))
                return -EINVAL;
        rv = pde->proc_ops->proc_lseek(file, offset, whence);
@@ -477,37 +480,15 @@ static ssize_t pde_read_buf(struct proc_dir_entry *pde, 
struct kiocb *iocb,
 static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct proc_dir_entry *pde = PDE(file_inode(iocb->ki_filp));
-       ssize_t ret;
 
+       /* procfs reads through the seq_file itself, see pde_seq_start() */
+       if (pde_is_seq_file(pde))
+               return seq_read_iter(iocb, iter);
        if (pde_has_proc_read_buf(pde))
                return pde_read_buf(pde, iocb, iter);
-       if (!pde_pin(pde))
-               return -EIO;
-       ret = pde->proc_ops->proc_read_iter(iocb, iter);
-       pde_unpin(pde);
-       return ret;
-}
-
-static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char 
__user *buf, size_t count, loff_t *ppos)
-{
-       const auto read = pde->proc_ops->proc_read;
-       if (read)
-               return read(file, buf, count, ppos);
        return -EIO;
 }
 
-static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t 
count, loff_t *ppos)
-{
-       struct proc_dir_entry *pde = PDE(file_inode(file));
-       ssize_t rv;
-
-       if (!pde_pin(pde))
-               return -EIO;
-       rv = pde_read(pde, file, buf, count, ppos);
-       pde_unpin(pde);
-       return rv;
-}
-
 /*
  * procfs copies in what is written before it pins the entry. A writer that
  * faults on its buffer then doesn't hold up remove_proc_entry().
@@ -923,41 +904,7 @@ static int proc_reg_release(struct inode *inode, struct 
file *file)
        return 0;
 }
 
-/* For seq_file entries, see pde_seq_ops. */
-static const struct file_operations proc_seq_file_ops = {
-       .llseek         = seq_lseek,
-       .read_iter      = seq_read_iter,
-       .splice_read    = copy_splice_read,
-       .write          = proc_reg_write,
-       .poll           = proc_reg_poll,
-       .unlocked_ioctl = proc_reg_unlocked_ioctl,
-       .compat_ioctl   = proc_reg_compat_ioctl,
-       .mmap           = proc_reg_mmap,
-       .get_unmapped_area = proc_reg_get_unmapped_area,
-#ifndef CONFIG_MMU
-       .mmap_capabilities = proc_reg_mmap_capabilities,
-#endif
-       .open           = proc_reg_open,
-       .release        = proc_reg_release,
-};
-
 static const struct file_operations proc_reg_file_ops = {
-       .llseek         = proc_reg_llseek,
-       .read           = proc_reg_read,
-       .write          = proc_reg_write,
-       .poll           = proc_reg_poll,
-       .unlocked_ioctl = proc_reg_unlocked_ioctl,
-       .compat_ioctl   = proc_reg_compat_ioctl,
-       .mmap           = proc_reg_mmap,
-       .get_unmapped_area = proc_reg_get_unmapped_area,
-#ifndef CONFIG_MMU
-       .mmap_capabilities = proc_reg_mmap_capabilities,
-#endif
-       .open           = proc_reg_open,
-       .release        = proc_reg_release,
-};
-
-static const struct file_operations proc_iter_file_ops = {
        .llseek         = proc_reg_llseek,
        .read_iter      = proc_reg_read_iter,
        .write          = proc_reg_write,
@@ -1026,10 +973,6 @@ struct inode *proc_get_inode(struct super_block *sb, 
struct proc_dir_entry *de)
                inode->i_op = de->proc_iops;
                if (pde_has_proc_fops(de))
                        inode->i_fop = de->proc_fops;
-               else if (pde_is_seq_file(de))
-                       inode->i_fop = &proc_seq_file_ops;
-               else if (pde_has_proc_read_iter(de) || 
pde_has_proc_read_buf(de))
-                       inode->i_fop = &proc_iter_file_ops;
                else
                        inode->i_fop = &proc_reg_file_ops;
        } else if (S_ISDIR(inode->i_mode)) {
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 84c5c13651aa..0a22237e6778 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -103,11 +103,6 @@ static inline bool pde_has_proc_fops(const struct 
proc_dir_entry *pde)
        return pde->flags & PROC_ENTRY_proc_fops;
 }
 
-static inline bool pde_has_proc_read_iter(const struct proc_dir_entry *pde)
-{
-       return pde->flags & PROC_ENTRY_proc_read_iter;
-}
-
 static inline bool pde_has_proc_lseek(const struct proc_dir_entry *pde)
 {
        return pde->flags & PROC_ENTRY_proc_lseek;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 05e0d6e4f918..9c09766b8f72 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -17,6 +17,7 @@ struct seq_operations;
 enum {
        /*
         * All /proc entries using this ->proc_ops instance are never removed.
+        * procfs calls into them without pinning them.
         *
         * If in doubt, ignore this flag.
         */
@@ -26,7 +27,6 @@ enum {
        PROC_ENTRY_PERMANENT            = 1U << 0,
 #endif
 
-       PROC_ENTRY_proc_read_iter       = 1U << 1,
        PROC_ENTRY_proc_fops            = 1U << 2,
        PROC_ENTRY_proc_lseek           = 1U << 3,
        PROC_ENTRY_proc_seq_ops         = 1U << 4,
@@ -76,8 +76,6 @@ struct proc_ioctl_arg {
 struct proc_ops {
        unsigned int proc_flags;
        int     (*proc_open)(struct inode *, struct file *);
-       ssize_t (*proc_read)(struct file *, char __user *, size_t, loff_t *);
-       ssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *);
        /*
         * mandatory unless nonseekable_open() or equivalent is used, procfs
         * seeks seq_file entries itself

-- 
2.53.0

Reply via email to