procfs, fdinfo reworked, attempts N-th
Subsystems (5)
cover procfs, fdinfo reworked, attempts N-th
Hi guys,
here is a bit reworked series
- all exportfs junk is dropped out of code
- fdinfo for seq-files uses embedded seq_file entry
- dnotify is not yet addressed (but fdinfo for fsnotify can be easily extended in future)
Al, may I ask you to take a look on final fdinfo seq-file approach? Pavel, could you please check the fdnotify patch, will current amount of data be enough for us?
Any complains are welcome.
Cyrill
PATCH 1/7 procfs: Move /proc/pid/fd[info] handling code to fd.[ch]
This patch prepares the ground for further extension of /proc/pid/fd[info] handling code by moving fdinfo handling code into fs/proc/fd.c.
I think such move makes both fs/proc/base.c and fs/proc/fd.c easier to read.
--- fs/proc/Makefile | 2 fs/proc/base.c | 388 ----------------------------------------------------- fs/proc/fd.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/fd.h | 14 + fs/proc/internal.h | 48 ++++++ 5 files changed, 416 insertions(+), 387 deletions(-)
fs/proc/Makefile +1 -1
@@ -8,7 +8,7 @@ proc-y := nommu.o task_nommu.o proc-$(CONFIG_MMU) := mmu.o task_mmu.o proc-y += inode.o root.o base.o generic.o array.o \ - proc_tty.o + proc_tty.o fd.o proc-y += cmdline.o proc-y += consoles.o proc-y += cpuinfo.o
fs/proc/base.c +2 -386
430 lines not on this page · raw message
fs/proc/fd.c new file +351 -0
351 lines not on this page · raw message
fs/proc/fd.h new file +14 -0
@@ -0,0 +1,14 @@ +#ifndef __PROCFS_FD_H__ +#define __PROCFS_FD_H__ + +#include <linux/fs.h> + +extern const struct file_operations proc_fd_operations; +extern const struct inode_operations proc_fd_inode_operations; + +extern const struct file_operations proc_fdinfo_operations; +extern const struct inode_operations proc_fdinfo_inode_operations; + +extern int proc_fd_permission (struct inode *inode,int mask); + +#endif /* __PROCFS_FD_H__ */
fs/proc/internal.h +48 -0
66 lines not on this page · raw message
PATCH 2/7 procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file v2
In reply to Cyrill GorcunovThis patch converts /proc/pid/fdinfo/ handling routines to seq-file which is needed to extend seq operations and plug in auxiliary fdinfo provides from subsystems like eventfd/eventpoll/fsnotify.
Note the proc_fd_link no longer call for proc_fd_info, simply because proc_fd_info is converted to seq_fdinfo_open (which is seq-file open() prototype).
v2 (by Al Viro):
- Don't use helper function with optional arguments, thus proc_fd_info get deprecated
- Use proc_fdinfo structure with seq_file embedded, thus we can use container_of helper
- Use fput to free reference to the file we've grabbed
--- fs/proc/fd.c | 145 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 46 deletions(-)
fs/proc/fd.c +99 -46
@@ -6,61 +6,105 @@#include <linux/namei.h> #include <linux/pid.h> #include <linux/security.h> +#include <linux/file.h> +#include <linux/seq_file.h> #include <linux/proc_fs.h> #include "internal.h" #include "fd.h" -#define PROC_FDINFO_MAX 64 +struct proc_fdinfo { +struct seq_file m; +struct file *fd_file; +int f_flags; +}; + +static int seq_show (struct seq_file *m,void *v) +{ + struct proc_fdinfo *fdinfo = container_of(m, struct proc_fdinfo, m); +seq_printf (m,"pos:\t%lli\nflags:\t0%o\n" , + (long long )fdinfo->fd_file->f_pos, fdinfo->f_flags); +return 0 ; +} -static int proc_fd_info (struct inode *inode,struct path *path,char *info) +static int seq_fdinfo_open (struct inode *inode,struct file *file) { -struct task_struct *task =get_proc_task (inode); +struct proc_fdinfo *fdinfo =NULL ;struct files_struct *files =NULL ; -int fd =proc_fd (inode); -struct file *file; +struct task_struct *task; +struct file *fd_file; +int f_flags, ret; + ret = -ENOENT ; + + task =get_proc_task (inode);if (task) { files =get_files_struct (task);put_task_struct (task); } +if (files) { -/* -* We are not taking a ref to the file structure, so we must -* hold ->file_lock. -*/ +int fd =proc_fd (inode); +spin_lock (&files->file_lock); - file =fcheck_files (files, fd); -if (file) { -unsigned int f_flags; -struct fdtable *fdt; + fd_file =fcheck_files (files, fd); +if (fd_file) { +struct fdtable *fdt =files_fdtable (files); - fdt =files_fdtable (files); - f_flags = file->f_flags & ~O_CLOEXEC ; + f_flags = fd_file->f_flags & ~O_CLOEXEC ;if (close_on_exec (fd, fdt)) f_flags |=O_CLOEXEC ; -if (path) { - *path = file->f_path; -path_get (&file->f_path); - } -if (info) -snprintf (info,PROC_FDINFO_MAX , -"pos:\t%lli\n" -"flags:\t0%o\n" , - (long long ) file->f_pos, - f_flags); -spin_unlock (&files->file_lock); -put_files_struct (files); -return 0 ; +get_file (fd_file); + ret =0 ; }spin_unlock (&files->file_lock); +put_files_struct (files); } -return -ENOENT ; + +if (ret) +return ret; + + ret = -ENOMEM ; + fdinfo =kmalloc (sizeof (*fdinfo),GFP_KERNEL ); +if (!fdinfo) + goto err_put; + + fdinfo->fd_file = fd_file; + fdinfo->f_flags = f_flags; + file->private_data = &fdinfo->m; + + ret =single_open (file, seq_show,NULL ); +if (ret) + goto err_free; + +return 0 ; + +err_free: +kfree (fdinfo); +err_put: +fput (fd_file); +return ret; } +static int seq_fdinfo_release (struct inode *inode,struct file *file) +{ +struct proc_fdinfo *fdinfo = +container_of ((struct seq_file *)file->private_data, + struct proc_fdinfo, m); +fput (fdinfo->fd_file); +return single_release (inode, file); +} + +static const struct file_operations proc_fdinfo_file_operations = { + .open = seq_fdinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_fdinfo_release, +}; +static int tid_fd_revalidate (struct dentry *dentry,unsigned int flags) {struct files_struct *files;
@@ -130,7 +174,32 @@ static const struct dentry_operations tistatic int proc_fd_link (struct dentry *dentry,struct path *path) { -return proc_fd_info (dentry->d_inode, path,NULL ); +struct files_struct *files =NULL ; +struct task_struct *task; +int ret = -ENOENT ; + + task =get_proc_task (dentry->d_inode); +if (task) { + files =get_files_struct (task); +put_task_struct (task); + } + +if (files) { +int fd =proc_fd (dentry->d_inode); +struct file *fd_file; + +spin_lock (&files->file_lock); + fd_file =fcheck_files (files, fd); +if (fd_file) { + *path = fd_file->f_path; +path_get (&fd_file->f_path); + ret =0 ; + } +spin_unlock (&files->file_lock); +put_files_struct (files); + } + +return ret; } static struct dentry *
@@ -245,22 +314,6 @@ out_no_task:return retval; } -static ssize_t proc_fdinfo_read (struct file *file,char __user *buf, -size_t len,loff_t *ppos) -{ -char tmp[PROC_FDINFO_MAX ]; -int err =proc_fd_info (file->f_path.dentry->d_inode,NULL , tmp); -if (!err) - err =simple_read_from_buffer (buf, len, ppos, tmp,strlen (tmp)); -return err; -} - -static const struct file_operations proc_fdinfo_file_operations = { - .open = nonseekable_open, - .read = proc_fdinfo_read, - .llseek = no_llseek, -}; -static int proc_readfd (struct file *filp,void *dirent,filldir_t filldir) {return proc_readfd_common (filp, dirent, filldir, proc_fd_instantiate);
PATCH 3/7 procfs: Add ability to plug in auxiliary fdinfo providers
In reply to Cyrill GorcunovThis patch brings ability to print out auxiliary data associated with file in procfs interface /proc/pid/fdinfo/fd.
In particular further patches make eventfd, evenpoll, signalfd and fsnotify to print additional information complete enough to restore these objects after checkpoint.
To simplify the code we add show_fdinfo callback inside struct file_operations (as Al and Pavel are proposing).
--- fs/proc/fd.c | 5 +++++ include/linux/fs.h | 3 +++ 2 files changed, 8 insertions(+)
fs/proc/fd.c +5 -0
@@ -23,8 +23,13 @@ struct proc_fdinfo {static int seq_show (struct seq_file *m,void *v) { struct proc_fdinfo *fdinfo = container_of(m, struct proc_fdinfo, m); +seq_printf (m,"pos:\t%lli\nflags:\t0%o\n" , (long long )fdinfo->fd_file->f_pos, fdinfo->f_flags); + +if (fdinfo->fd_file->f_op->show_fdinfo) +return fdinfo->fd_file->f_op->show_fdinfo (m, fdinfo->fd_file); +return 0 ; }
include/linux/fs.h +3 -0
@@ -1775,6 +1775,8 @@ struct block_device_operations;#define HAVE_COMPAT_IOCTL 1#define HAVE_UNLOCKED_IOCTL 1 +struct seq_file ; +struct file_operations {struct module *owner;loff_t (*llseek) (struct file *,loff_t ,int );
@@ -1803,6 +1805,7 @@ struct file_operations {int (*setlease)(struct file *,long ,struct file_lock **);long (*fallocate)(struct file *file,int mode,loff_t offset,loff_t len); +int (*show_fdinfo)(struct seq_file *m,struct file *f); };struct inode_operations {
PATCH 4/7 fs, notify: Add procfs fdinfo helper v4
In reply to Cyrill GorcunovThis allow us to print out fsnotify details such as watchee inode, device, mask and file handle.
For example for inotify objects the output is
| pos: 0 | flags: 02000000 | inotify wd: 3 ino: 9e7e sdev: 800013 mask: 800afce ignored_mask: 0 | inotify wd: 2 ino: a111 sdev: 800013 mask: 800afce ignored_mask: 0 | inotify wd: 1 ino: 6b149 sdev: 800013 mask: 800afce ignored_mask: 0
For fanotify it is like
| pos: 0 | flags: 02 | fanotify ino: 68f71 sdev: 800013 mask: 1 ignored_mask: 40000000 | fanotify mnt_id: 13 mask: 1 ignored_mask: 40000000
To minimize impact on general fsnotify code the new functionality is gathered in fs/notify/fdinfo.c file.
--- fs/notify/Makefile | 2 fs/notify/fanotify/fanotify_user.c | 4 + fs/notify/fdinfo.c | 108 +++++++++++++++++++++++++++++++++++++ fs/notify/fdinfo.h | 22 +++++++ fs/notify/inotify/inotify_user.c | 4 + 5 files changed, 139 insertions(+), 1 deletion(-)
fs/notify/Makefile +1 -1
@@ -1,5 +1,5 @@ obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o \ - mark.o vfsmount_mark.o + mark.o vfsmount_mark.o fdinfo.o obj-y += dnotify/ obj-y += inotify/
fs/notify/fanotify/fanotify_user.c +4 -0
@@ -17,6 +17,7 @@#include <asm/ioctls.h> #include "../../mount.h" +#include "../fdinfo.h" #define FANOTIFY_DEFAULT_MAX_EVENTS 16384#define FANOTIFY_DEFAULT_MAX_MARKS 8192
@@ -446,6 +447,9 @@ static long fanotify_ioctl(struct file * }static const struct file_operations fanotify_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = fanotify_show_fdinfo, +#endif .poll = fanotify_poll, .read = fanotify_read, .write = fanotify_write,
fs/notify/fdinfo.c new file +108 -0
108 lines not on this page · raw message
fs/notify/fdinfo.h new file +22 -0
@@ -0,0 +1,22 @@ +#ifndef __FSNOTIFY_FDINFO_H__ +#define __FSNOTIFY_FDINFO_H__ + +#include <linux/errno.h> +#include <linux/proc_fs.h> + +struct seq_file ; +struct file ; + +#ifdef CONFIG_PROC_FS + +#ifdef CONFIG_INOTIFY_USER +extern int inotify_show_fdinfo (struct seq_file *m,struct file *f); +#endif + +#ifdef CONFIG_FANOTIFY +extern int fanotify_show_fdinfo (struct seq_file *m,struct file *f); +#endif + +#endif /* CONFIG_PROC_FS */ + +#endif /* __FSNOTIFY_FDINFO_H__ */
fs/notify/inotify/inotify_user.c +4 -0
@@ -40,6 +40,7 @@#include <linux/wait.h> #include "inotify.h" +#include "../fdinfo.h" #include <asm/ioctls.h>
@@ -335,6 +336,9 @@ static long inotify_ioctl(struct file *f }static const struct file_operations inotify_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = inotify_show_fdinfo, +#endif .poll = inotify_poll, .read = inotify_read, .fasync = inotify_fasync,
PATCH 5/7 fs, eventfd: Add procfs fdinfo helper
In reply to Cyrill GorcunovThis allow us to print out raw counter value. The /proc/pid/fdinfo/fd output is
| pos: 0 | flags: 04002 | eventfd-count: 5a
--- fs/eventfd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
fs/eventfd.c +20 -0
@@ -19,6 +19,8 @@#include <linux/export.h> #include <linux/kref.h> #include <linux/eventfd.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> struct eventfd_ctx {struct kref kref;
@@ -284,7 +286,25 @@ static ssize_t eventfd_write(struct filereturn res; } +#ifdef CONFIG_PROC_FS +static int eventfd_show_fdinfo (struct seq_file *m,struct file *f) +{ +struct eventfd_ctx *ctx = f->private_data; +int ret; + +spin_lock_irq (&ctx->wqh.lock); + ret =seq_printf (m,"eventfd-count: %16llx\n" , + (unsigned long long )ctx->count); +spin_unlock_irq (&ctx->wqh.lock); + +return ret; +} +#endif +static const struct file_operations eventfd_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = eventfd_show_fdinfo, +#endif .release = eventfd_release, .poll = eventfd_poll, .read = eventfd_read,
PATCH 6/7 fs, epoll: Add procfs fdinfo helper v2
In reply to Cyrill GorcunovThis allow us to print out eventpoll target file descriptor, events and data, the /proc/pid/fdinfo/fd consists of
| pos: 0 | flags: 02 | tfd: 5 events: 1d data: ffffffffffffffff
This feature is CONFIG_CHECKPOINT_RESTORE only.
--- fs/eventpoll.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
fs/eventpoll.c +28 -0
@@ -38,6 +38,8 @@#include <asm/io.h> #include <asm/mman.h> #include <linux/atomic.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> /* * LOCKING:
@@ -783,8 +785,34 @@ static unsigned int ep_eventpoll_poll(streturn pollflags !=-1 ? pollflags :0 ; } +#ifdef CONFIG_PROC_FS +static int ep_show_fdinfo (struct seq_file *m,struct file *f) +{ +struct eventpoll *ep = f->private_data; +struct rb_node *rbp; +int ret; + +mutex_lock (&ep->mtx); +for (rbp =rb_first (&ep->rbr); rbp; rbp =rb_next (rbp)) { + struct epitem *epi = rb_entry(rbp, struct epitem, rbn); + + ret =seq_printf (m,"tfd: %8d events: %8x data: %16llx\n" , + epi->ffd.fd, epi->event.events, + (long long )epi->event.data); +if (ret) +break ; + } +mutex_unlock (&ep->mtx); + +return ret; +} +#endif +/* File callbacks that implement the eventpoll file behaviour */ static const struct file_operations eventpoll_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = ep_show_fdinfo, +#endif .release = ep_eventpoll_release, .poll = ep_eventpoll_poll, .llseek = noop_llseek,
PATCH 7/7 fdinfo: Show sigmask for signalfd fd v2
In reply to Cyrill Gorcunov--- fs/proc/array.c | 2 +- fs/signalfd.c | 26 ++++++++++++++++++++++++++ include/linux/proc_fs.h | 3 +++ 3 files changed, 30 insertions(+), 1 deletion(-)
fs/proc/array.c +1 -1
@@ -220,7 +220,7 @@ static inline void task_state(struct seqseq_putc (m,'\n' ); } -static void render_sigset_t (struct seq_file *m,const char *header, +void render_sigset_t (struct seq_file *m,const char *header,sigset_t *set) {int i;
fs/signalfd.c +26 -0
@@ -29,6 +29,7 @@#include <linux/anon_inodes.h> #include <linux/signalfd.h> #include <linux/syscalls.h> +#include <linux/proc_fs.h> void signalfd_cleanup (struct sighand_struct *sighand) {
@@ -46,6 +47,7 @@ void signalfd_cleanup(struct sighand_str }struct signalfd_ctx { +seqcount_t cnt;sigset_t sigmask; };
@@ -227,7 +229,28 @@ static ssize_t signalfd_read(struct filereturn total ? total: ret; } +#ifdef CONFIG_PROC_FS +static int signalfd_show_fdinfo (struct seq_file *m,struct file *f) +{ +struct signalfd_ctx *ctx = f->private_data; +sigset_t sigmask; +unsigned seq; + +do { + seq =read_seqcount_begin (&ctx->cnt); + sigmask = ctx->sigmask; + }while (read_seqcount_retry (&ctx->cnt, seq)); + +signotset (&sigmask); +render_sigset_t (m,"sigmask:\t" , &sigmask); +return 0 ; +} +#endif +static const struct file_operations signalfd_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = signalfd_show_fdinfo, +#endif .release = signalfd_release, .poll = signalfd_poll, .read = signalfd_read,
@@ -259,6 +282,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigreturn -ENOMEM ; ctx->sigmask = sigmask; +seqcount_init (&ctx->cnt);/* * When we call this, the initialization must be complete, since
@@ -279,7 +303,9 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigreturn -EINVAL ; }spin_lock_irq (¤t->sighand->siglock); +write_seqcount_begin (&ctx->cnt); ctx->sigmask = sigmask; +write_seqcount_end (&ctx->cnt);spin_unlock_irq (¤t->sighand->siglock);wake_up (¤t->sighand->signalfd_wqh);
include/linux/proc_fs.h +3 -0
@@ -290,4 +290,7 @@ static inline struct net *PDE_NET(struct return pde->parent->data; } +#include <asm/signal.h> + +void render_sigset_t (struct seq_file *m,const char *header,sigset_t *set);#endif /* _LINUX_PROC_FS_H */