From: Cyrill Gorcunov <gorcunov@openvz.org>
To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Cc: Al Viro <viro@zeniv.linux.org.uk>,
Alexey Dobriyan <adobriyan@gmail.com>,
Andrew Morton <akpm@linux-foundation.org>,
Pavel Emelyanov <xemul@parallels.com>,
James Bottomley <jbottomley@parallels.com>,
Matthew Helsley <matt.helsley@gmail.com>,
Cyrill Gorcunov <gorcunov@openvz.org>,
Al Viro <viro@ZenIV.linux.org.uk>
Subject: [patch 3/7] procfs: Add ability to plug in auxiliary fdinfo providers
Date: Wed, 25 Jul 2012 13:47:21 +0400 [thread overview]
Message-ID: <20120725095024.842540518@openvz.org> (raw)
In-Reply-To: 20120725094718.089879534@openvz.org
[-- Attachment #1: seq-fdinfo-seq-ops-helpers-6 --]
[-- Type: text/plain, Size: 7841 bytes --]
This patch brings ability to plug in auxiliary fdinfo providers.
For example in further patches eventfd, evenpoll and fsnotify
will print out information associated with files.
This feature is CONFIG_CHECKPOINT_RESTORE guarded to eliminate
overhead for those who don't need it at all (this
unfortunately makes patch bigger than I wanted).
The basic usage rule is the following
- fdinfo provider should register own "show" method
via proc_register_fdinfo_driver call, where "show"
methods are rather well known seq-file operations
- once the kernel opens /proc/$pid/fdinfo/$fd file
it calls for ->probe() method in registered fdinfo
drivers, and if probe success, then seq-file "show"
operations will be called to provide out additional
infomation
Initially we considered to inject some "show" metod to
file_operations but since there really a number of
file_operations declared inside kernel (and in real the
further patches cover onle eventfd/epoll/inotify) the
waste of memory space will be inacceptable I think.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Pavel Emelyanov <xemul@parallels.com>
CC: James Bottomley <jbottomley@parallels.com>
---
fs/proc/fd.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/proc_fs.h | 26 ++++++
2 files changed, 226 insertions(+)
Index: linux-2.6.git/fs/proc/fd.c
===================================================================
--- linux-2.6.git.orig/fs/proc/fd.c
+++ linux-2.6.git/fs/proc/fd.c
@@ -8,12 +8,210 @@
#include <linux/security.h>
#include <linux/file.h>
#include <linux/seq_file.h>
+#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include "internal.h"
#include "fd.h"
+#ifdef CONFIG_CHECKPOINT_RESTORE
+
+static LIST_HEAD(fdinfo_drivers);
+static DECLARE_RWSEM(fdinfo_drivers_sem);
+
+int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s)
+{
+ struct proc_fdinfo_driver *i;
+ int ret = 0;
+
+ if (!s->ops || !s->probe)
+ return -EINVAL;
+
+ down_write(&fdinfo_drivers_sem);
+ list_for_each_entry(i, &fdinfo_drivers, list) {
+ if (i == s) {
+ WARN_ONCE("Trying reassign fdinfo driver `%s'\n",
+ i->name);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (!ret)
+ list_add(&s->list, &fdinfo_drivers);
+ up_write(&fdinfo_drivers_sem);
+
+ return ret;
+}
+
+void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s)
+{
+ struct proc_fdinfo_driver *i, *tmp;
+
+ down_write(&fdinfo_drivers_sem);
+ list_for_each_entry_safe(i, tmp, &fdinfo_drivers, list) {
+ if (i == s) {
+ list_del(&i->list);
+ break;
+ }
+ }
+ up_write(&fdinfo_drivers_sem);
+}
+
+static int prep_fdinfo_driver(struct proc_fdinfo_extra *extra)
+{
+ struct proc_fdinfo_driver *s;
+
+ down_read(&fdinfo_drivers_sem);
+ list_for_each_entry(s, &fdinfo_drivers, list) {
+ if (s->probe(extra->f_file)) {
+ extra->driver = s;
+ break;
+ }
+ }
+ up_read(&fdinfo_drivers_sem);
+
+ return 0;
+}
+
+static void *seq_start(struct seq_file *m, loff_t *pos)
+{
+ struct proc_fdinfo_extra *extra = m->private;
+
+ down_read(&fdinfo_drivers_sem);
+ extra->pos = *pos;
+
+ return *pos == 0 ? extra :
+ (extra->driver ? extra->driver->ops->start(m, pos) : NULL);
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+{
+ struct proc_fdinfo_extra *extra = m->private;
+
+ if (extra->driver && extra->pos > 0)
+ extra->driver->ops->stop(m, v);
+ up_read(&fdinfo_drivers_sem);
+}
+
+static void *seq_next(struct seq_file *m, void *p, loff_t *pos)
+{
+ struct proc_fdinfo_extra *extra = m->private;
+ void *v = NULL;
+
+ if (extra->driver) {
+ int ret = 0;
+
+ if (*pos == 0) {
+ v = extra->driver->ops->start(m, pos);
+ if (v) {
+ ret = extra->driver->ops->show(m, v);
+ p = v;
+ } else
+ ret = -1;
+ }
+
+ if (!ret)
+ v = extra->driver->ops->next(m, p, pos);
+ } else
+ ++*pos;
+
+ extra->pos = *pos;
+ return v;
+}
+
+static int seq_show(struct seq_file *m, void *v)
+{
+ struct proc_fdinfo_extra *extra = m->private;
+
+ if (extra->driver && extra->pos > 0)
+ return extra->driver->ops->show(m, v);
+
+ seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
+ (long long)extra->f_file->f_pos,
+ extra->f_flags);
+ return 0;
+}
+
+static const struct seq_operations fdinfo_seq_ops = {
+ .start = seq_start,
+ .next = seq_next,
+ .stop = seq_stop,
+ .show = seq_show,
+};
+
+static int seq_fdinfo_open(struct inode *inode, struct file *file)
+{
+ struct files_struct *files = NULL;
+ struct proc_fdinfo_extra *extra;
+ struct task_struct *task;
+ struct seq_file *m;
+ int ret;
+
+ extra = kzalloc(sizeof(*extra), GFP_KERNEL);
+ if (!extra)
+ return -ENOMEM;
+
+ ret = seq_open(file, &fdinfo_seq_ops);
+ if (!ret) {
+ ret = -ENOENT;
+ m = file->private_data;
+ m->private = extra;
+
+ task = get_proc_task(inode);
+ if (task) {
+ files = get_files_struct(task);
+ put_task_struct(task);
+ }
+
+ if (files) {
+ int fd = proc_fd(inode);
+
+ spin_lock(&files->file_lock);
+ extra->f_file = fcheck_files(files, fd);
+ if (extra->f_file) {
+ struct fdtable *fdt = files_fdtable(files);
+
+ extra->f_flags = extra->f_file->f_flags & ~O_CLOEXEC;
+ if (close_on_exec(fd, fdt))
+ extra->f_flags |= O_CLOEXEC;
+ get_file(extra->f_file);
+ }
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
+
+ ret = prep_fdinfo_driver(extra);
+ }
+ }
+
+ if (ret) {
+ if (extra->f_file)
+ put_filp(extra->f_file);
+ kfree(extra);
+ }
+ return ret;
+}
+
+static int seq_fdinfo_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+ struct proc_fdinfo_extra *extra = m->private;
+
+ put_filp(extra->f_file);
+ kfree(m->private);
+
+ return seq_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,
+};
+
+#else /* CONFIG_CHECKPOINT_RESTORE */
+
struct proc_fdinfo {
loff_t f_pos;
int f_flags;
@@ -90,6 +288,8 @@ static const struct file_operations proc
.release = seq_fdinfo_release,
};
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct files_struct *files;
Index: linux-2.6.git/include/linux/proc_fs.h
===================================================================
--- linux-2.6.git.orig/include/linux/proc_fs.h
+++ linux-2.6.git/include/linux/proc_fs.h
@@ -100,6 +100,24 @@ struct vmcore {
loff_t offset;
};
+struct seq_operations;
+
+/* fdinfo auxiliary information drivers */
+struct proc_fdinfo_driver {
+ struct list_head list;
+ const char *name;
+ const struct seq_operations *ops;
+ int (*probe)(struct file *file);
+};
+
+/* auxiliary data allocated per fdinfo reader */
+struct proc_fdinfo_extra {
+ struct proc_fdinfo_driver *driver;
+ loff_t pos;
+ struct file *f_file;
+ unsigned int f_flags;
+};
+
#ifdef CONFIG_PROC_FS
extern void proc_root_init(void);
@@ -175,6 +193,11 @@ extern struct proc_dir_entry *proc_net_m
extern struct file *proc_ns_fget(int fd);
+#ifdef CONFIG_CHECKPOINT_RESTORE
+extern int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s);
+extern void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s);
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
#else
#define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; })
@@ -229,6 +252,9 @@ static inline struct file *proc_ns_fget(
return ERR_PTR(-EINVAL);
}
+static inline int proc_register_fdinfo_driver(struct proc_fdinfo_driver *s) { return -EINVAL; }
+static inline void proc_unregister_fdinfo_driver(struct proc_fdinfo_driver *s) { }
+
#endif /* CONFIG_PROC_FS */
#if !defined(CONFIG_PROC_KCORE)
next prev parent reply other threads:[~2012-07-25 9:47 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-25 9:47 [patch 0/7] procfs fdinfo extension, new round Cyrill Gorcunov
2012-07-25 9:47 ` [patch 1/7] procfs: Move /proc/pid/fd[info] handling code to fd.[ch] Cyrill Gorcunov
2012-07-25 9:47 ` [patch 2/7] procfs: Convert /proc/pid/fdinfo/ handling routines to seq-file Cyrill Gorcunov
2012-07-26 10:43 ` Pavel Emelyanov
2012-07-26 10:49 ` Cyrill Gorcunov
2012-07-25 9:47 ` Cyrill Gorcunov [this message]
2012-07-27 3:48 ` [patch 3/7] procfs: Add ability to plug in auxiliary fdinfo providers Pavel Emelyanov
2012-07-27 6:00 ` Cyrill Gorcunov
2012-07-27 6:08 ` Pavel Emelyanov
2012-07-27 6:23 ` Cyrill Gorcunov
2012-07-25 9:47 ` [patch 4/7] fs, eventfd: Add procfs fdinfo helper Cyrill Gorcunov
2012-07-25 9:47 ` [patch 5/7] fs, epoll: Add procfs fdinfo helper v2 Cyrill Gorcunov
2012-07-25 9:47 ` [patch 6/7] fs, exportfs: Add export_encode_inode_fh helper Cyrill Gorcunov
2012-07-25 9:47 ` [patch 7/7] fs, notify: Add procfs fdinfo helper v3 Cyrill Gorcunov
-- strict thread matches above, loose matches on Subject: below --
2012-08-16 16:34 [patch 0/7] procfs, fdinfo reworked, attempts N-th Cyrill Gorcunov
2012-08-16 16:34 ` [patch 3/7] procfs: Add ability to plug in auxiliary fdinfo providers Cyrill Gorcunov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120725095024.842540518@openvz.org \
--to=gorcunov@openvz.org \
--cc=adobriyan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=jbottomley@parallels.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=matt.helsley@gmail.com \
--cc=viro@zeniv.linux.org.uk \
--cc=xemul@parallels.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.