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
